The term linear buffer is a generic reference to many buffers that are
created with a single piece of linear contiguous memory that is controlled by
pointers whose address increments linearly. The examples so far discussed are
all of linear buffers.
The main point about them is that they will lose data when full and fail
to provide data when empty. This is obvious but as will be shown, the way in
which this happens with linear buffers compared to circular ones is different.
With a linear buffer, it loses incoming data when full so that the data it does
contain becomes older and older. This is the overrun condition. When it is
empty, it will provide old data, usually the last entry, and so the processor
will continue to process potentially incorrect data. This is the underrun
Within a real-time system, these conditions are often but not always
considered error conditions. In some cases, the loss of data is not critical
but with any data processing that is based on regular sampling, it will
introduce errors. There are further com-plications concerning how these
conditions are prevented from occurring. The solution is to use a technique
where the pointers are checked against certain values and the results used to
trigger an action such as fetching more data and so on. These values are
commonly referred to as high and low water marks, so named because they are
similar to the high and low water marks seen at the coast that indicate the
minimum and maximum levels that tidal water will fall and rise.
The number of entries below the low water mark determine how many
entries the buffer still has and thus the amount of time that is available to
start filling the buffer before the buffer empties and the underrun condition
exists. The number of empty entries in the buffer above the high water mark
determines the length of time that is available to stop the further filling of
the buffer and thus prevent data loss through overrun. By comparing the various
input and output pointers with these values, events can be gener-ated to start
or stop filling the buffer. This could simply take the form of jumping to a
subroutine, generating a software interrupt or within the context of an
operating system posting a message to another task to fill the buffer.