Documentation: update ring-buffer-design.txt
Fix typos, grammos, spellos, hyphenation. Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com> Acked-by: Steven Rostedt <rostedt@goodmis.org> Cc: Mel Gorman <mel@csn.ul.ie> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
74dbdd239b
commit
006b4298f2
@ -33,9 +33,9 @@ head_page - a pointer to the page that the reader will use next
|
|||||||
|
|
||||||
tail_page - a pointer to the page that will be written to next
|
tail_page - a pointer to the page that will be written to next
|
||||||
|
|
||||||
commit_page - a pointer to the page with the last finished non nested write.
|
commit_page - a pointer to the page with the last finished non-nested write.
|
||||||
|
|
||||||
cmpxchg - hardware assisted atomic transaction that performs the following:
|
cmpxchg - hardware-assisted atomic transaction that performs the following:
|
||||||
|
|
||||||
A = B iff previous A == C
|
A = B iff previous A == C
|
||||||
|
|
||||||
@ -52,15 +52,15 @@ The Generic Ring Buffer
|
|||||||
The ring buffer can be used in either an overwrite mode or in
|
The ring buffer can be used in either an overwrite mode or in
|
||||||
producer/consumer mode.
|
producer/consumer mode.
|
||||||
|
|
||||||
Producer/consumer mode is where the producer were to fill up the
|
Producer/consumer mode is where if the producer were to fill up the
|
||||||
buffer before the consumer could free up anything, the producer
|
buffer before the consumer could free up anything, the producer
|
||||||
will stop writing to the buffer. This will lose most recent events.
|
will stop writing to the buffer. This will lose most recent events.
|
||||||
|
|
||||||
Overwrite mode is where the produce were to fill up the buffer
|
Overwrite mode is where if the producer were to fill up the buffer
|
||||||
before the consumer could free up anything, the producer will
|
before the consumer could free up anything, the producer will
|
||||||
overwrite the older data. This will lose the oldest events.
|
overwrite the older data. This will lose the oldest events.
|
||||||
|
|
||||||
No two writers can write at the same time (on the same per cpu buffer),
|
No two writers can write at the same time (on the same per-cpu buffer),
|
||||||
but a writer may interrupt another writer, but it must finish writing
|
but a writer may interrupt another writer, but it must finish writing
|
||||||
before the previous writer may continue. This is very important to the
|
before the previous writer may continue. This is very important to the
|
||||||
algorithm. The writers act like a "stack". The way interrupts works
|
algorithm. The writers act like a "stack". The way interrupts works
|
||||||
@ -88,7 +88,7 @@ A writer can preempt a reader, but a reader can not preempt a writer.
|
|||||||
But a reader can read the buffer at the same time (on another processor)
|
But a reader can read the buffer at the same time (on another processor)
|
||||||
as a writer.
|
as a writer.
|
||||||
|
|
||||||
The ring buffer is made up of a list of pages held together by a link list.
|
The ring buffer is made up of a list of pages held together by a linked list.
|
||||||
|
|
||||||
At initialization a reader page is allocated for the reader that is not
|
At initialization a reader page is allocated for the reader that is not
|
||||||
part of the ring buffer.
|
part of the ring buffer.
|
||||||
@ -102,7 +102,7 @@ the head page.
|
|||||||
|
|
||||||
The reader has its own page to use. At start up time, this page is
|
The reader has its own page to use. At start up time, this page is
|
||||||
allocated but is not attached to the list. When the reader wants
|
allocated but is not attached to the list. When the reader wants
|
||||||
to read from the buffer, if its page is empty (like it is on start up)
|
to read from the buffer, if its page is empty (like it is on start-up),
|
||||||
it will swap its page with the head_page. The old reader page will
|
it will swap its page with the head_page. The old reader page will
|
||||||
become part of the ring buffer and the head_page will be removed.
|
become part of the ring buffer and the head_page will be removed.
|
||||||
The page after the inserted page (old reader_page) will become the
|
The page after the inserted page (old reader_page) will become the
|
||||||
@ -281,7 +281,7 @@ with the previous write.
|
|||||||
The commit pointer points to the last write location that was
|
The commit pointer points to the last write location that was
|
||||||
committed without preempting another write. When a write that
|
committed without preempting another write. When a write that
|
||||||
preempted another write is committed, it only becomes a pending commit
|
preempted another write is committed, it only becomes a pending commit
|
||||||
and will not be a full commit till all writes have been committed.
|
and will not be a full commit until all writes have been committed.
|
||||||
|
|
||||||
The commit page points to the page that has the last full commit.
|
The commit page points to the page that has the last full commit.
|
||||||
The tail page points to the page with the last write (before
|
The tail page points to the page with the last write (before
|
||||||
@ -292,7 +292,7 @@ be several pages ahead. If the tail page catches up to the commit
|
|||||||
page then no more writes may take place (regardless of the mode
|
page then no more writes may take place (regardless of the mode
|
||||||
of the ring buffer: overwrite and produce/consumer).
|
of the ring buffer: overwrite and produce/consumer).
|
||||||
|
|
||||||
The order of pages are:
|
The order of pages is:
|
||||||
|
|
||||||
head page
|
head page
|
||||||
commit page
|
commit page
|
||||||
@ -395,7 +395,7 @@ The main idea behind the lockless algorithm is to combine the moving
|
|||||||
of the head_page pointer with the swapping of pages with the reader.
|
of the head_page pointer with the swapping of pages with the reader.
|
||||||
State flags are placed inside the pointer to the page. To do this,
|
State flags are placed inside the pointer to the page. To do this,
|
||||||
each page must be aligned in memory by 4 bytes. This will allow the 2
|
each page must be aligned in memory by 4 bytes. This will allow the 2
|
||||||
least significant bits of the address to be used as flags. Since
|
least significant bits of the address to be used as flags, since
|
||||||
they will always be zero for the address. To get the address,
|
they will always be zero for the address. To get the address,
|
||||||
simply mask out the flags.
|
simply mask out the flags.
|
||||||
|
|
||||||
@ -460,7 +460,7 @@ When the reader tries to swap the page with the ring buffer, it
|
|||||||
will also use cmpxchg. If the flag bit in the pointer to the
|
will also use cmpxchg. If the flag bit in the pointer to the
|
||||||
head page does not have the HEADER flag set, the compare will fail
|
head page does not have the HEADER flag set, the compare will fail
|
||||||
and the reader will need to look for the new head page and try again.
|
and the reader will need to look for the new head page and try again.
|
||||||
Note, the flag UPDATE and HEADER are never set at the same time.
|
Note, the flags UPDATE and HEADER are never set at the same time.
|
||||||
|
|
||||||
The reader swaps the reader page as follows:
|
The reader swaps the reader page as follows:
|
||||||
|
|
||||||
@ -539,7 +539,7 @@ updated to the reader page.
|
|||||||
| +-----------------------------+ |
|
| +-----------------------------+ |
|
||||||
+------------------------------------+
|
+------------------------------------+
|
||||||
|
|
||||||
Another important point. The page that the reader page points back to
|
Another important point: The page that the reader page points back to
|
||||||
by its previous pointer (the one that now points to the new head page)
|
by its previous pointer (the one that now points to the new head page)
|
||||||
never points back to the reader page. That is because the reader page is
|
never points back to the reader page. That is because the reader page is
|
||||||
not part of the ring buffer. Traversing the ring buffer via the next pointers
|
not part of the ring buffer. Traversing the ring buffer via the next pointers
|
||||||
@ -659,7 +659,7 @@ before pushing the head page. If it is, then it can be assumed that the
|
|||||||
tail page wrapped the buffer, and we must drop new writes.
|
tail page wrapped the buffer, and we must drop new writes.
|
||||||
|
|
||||||
This is not a race condition, because the commit page can only be moved
|
This is not a race condition, because the commit page can only be moved
|
||||||
by the outter most writer (the writer that was preempted).
|
by the outermost writer (the writer that was preempted).
|
||||||
This means that the commit will not move while a writer is moving the
|
This means that the commit will not move while a writer is moving the
|
||||||
tail page. The reader cannot swap the reader page if it is also being
|
tail page. The reader cannot swap the reader page if it is also being
|
||||||
used as the commit page. The reader can simply check that the commit
|
used as the commit page. The reader can simply check that the commit
|
||||||
@ -733,7 +733,7 @@ The write converts the head page pointer to UPDATE.
|
|||||||
--->| |<---| |<---| |<---| |<---
|
--->| |<---| |<---| |<---| |<---
|
||||||
+---+ +---+ +---+ +---+
|
+---+ +---+ +---+ +---+
|
||||||
|
|
||||||
But if a nested writer preempts here. It will see that the next
|
But if a nested writer preempts here, it will see that the next
|
||||||
page is a head page, but it is also nested. It will detect that
|
page is a head page, but it is also nested. It will detect that
|
||||||
it is nested and will save that information. The detection is the
|
it is nested and will save that information. The detection is the
|
||||||
fact that it sees the UPDATE flag instead of a HEADER or NORMAL
|
fact that it sees the UPDATE flag instead of a HEADER or NORMAL
|
||||||
@ -892,7 +892,7 @@ It will return to the first writer.
|
|||||||
--->| |<---| |<---| |<---| |<---
|
--->| |<---| |<---| |<---| |<---
|
||||||
+---+ +---+ +---+ +---+
|
+---+ +---+ +---+ +---+
|
||||||
|
|
||||||
The first writer can not know atomically test if the tail page moved
|
The first writer cannot know atomically if the tail page moved
|
||||||
while it updates the HEAD page. It will then update the head page to
|
while it updates the HEAD page. It will then update the head page to
|
||||||
what it thinks is the new head page.
|
what it thinks is the new head page.
|
||||||
|
|
||||||
@ -923,9 +923,9 @@ if the tail page is either where it use to be or on the next page:
|
|||||||
--->| |<---| |<---| |<---| |<---
|
--->| |<---| |<---| |<---| |<---
|
||||||
+---+ +---+ +---+ +---+
|
+---+ +---+ +---+ +---+
|
||||||
|
|
||||||
If tail page != A and tail page does not equal B, then it must reset the
|
If tail page != A and tail page != B, then it must reset the pointer
|
||||||
pointer back to NORMAL. The fact that it only needs to worry about
|
back to NORMAL. The fact that it only needs to worry about nested
|
||||||
nested writers, it only needs to check this after setting the HEAD page.
|
writers means that it only needs to check this after setting the HEAD page.
|
||||||
|
|
||||||
|
|
||||||
(first writer)
|
(first writer)
|
||||||
|
Loading…
Reference in New Issue
Block a user