This is a general introduction to circular buffers.
We recount here some ideas relevant to fiber interface hardware.
We assume everywhere that “ring” is used some circular buffer in memory whose size is a power of two and whose address is a multiple of its size.
With most, perhaps all rings there are 2 cursors at fixed cached memory locations.
The ring’s writer reports in one of these and the reader in the other.
The cursors that the hardware writes may be assigned consecutively and similarly the cursors that the hardware reads.
This simplifies the hardware in that to update cursors, it may write integral numbers of cache lines or other unit size of its convenience.
The reader and writer both consult the other cursor.
For header and payload rings the hardware is either the reader or the writer and the software plays the other rôle.
There are probably rings where the software plays both rôles.
There might be rings where the hardware plays both rôles but not in the current plans.
Several sorts of rings cycle around a buffer in memory and are used for both input and output.
Some live in cached and others in uncached memory.
I propose here that the hardware intermittently report its cursor in an agreed cached memory location and consult the counter party cursor in another agreed location to see if it should continue thru the buffer.
These reports should be 32 bits even though the size of the ring is probably less and the real locations may be larger than 32 bits.
This allows the software to notice that the hardware has ‘lapped’ it.
The frequency of this update is a trade-off.
Too often and the cache load is excessive, too seldom and the CPU is held too far behind.
When a ring belongs to a data stream it is customary for the element supplying the data to not overtake the element that is using the data.
For a long fiber pouring into a ring the data will continue to arrive even if the buffer’s consumer fails to make progress.
The sender can be notified to cease sending data but several buffers full may arrive before that takes effect.
Perhaps it is good for the hardware to stop filling the buffer in order to avoid ruining the data that has already arrived.
Subsequent data are lost however, except at the other fiber end.
Storing the data elsewhere is tantamount to making the buffer bigger.
We may not want to commit to a buffer big enough for two fibers full of bits.
If the input from fiber stalls to avoid over-writing data in payload ring, then it should make a note in the header ring and perhaps cease reporting headers.
When the blockage is removed it should resume on the next payload.
If the input from fiber stalls to avoid overwriting headers, then upon resumption, it should report, in the header ring, how many headers were omitted.
Perhaps it should continue to deliver payloads.
Except for the data stream of payloads to the fiber, the hardware streams to memory are all sequential and can be moved to or from memory in units convenient to the hardware.
If the hardware takes this liberty the writer of the ring should guard against idle spells where some packet or other signal is stalled ‘waiting for the next bus’.
No-ops can be inserted in such cases.
For each ring there are in general the following cursors:
- ReaderB
- Where the reader is fetching and perhaps modifying data
- ReaderE
- Data that is ready for the reader.
- WriterB
- Where the writer is modifying data, perhaps not sequentially.
- WriterE
- Space cleared for writing.
- ReaderB
Integrity demands that these be in circular order; none may overtake the next.
In modular form exactly one of these must be false:
ReaderB < ReaderE; ReaderE < WriterB; WriterB < WriterE; WriterE < ReaderB.