Skip to content

Commit 6c43c09

Browse files
committed
documentation: Update circular buffer for load-acquire/store-release
This commit replaces full barriers by targeted use of load-acquire and store-release. Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com> [ paulmck: Restore comments as suggested by David Howells. ]
1 parent 9873552 commit 6c43c09

File tree

1 file changed

+19
-18
lines changed

1 file changed

+19
-18
lines changed

Documentation/circular-buffers.txt

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ The producer will look something like this:
160160
spin_lock(&producer_lock);
161161

162162
unsigned long head = buffer->head;
163+
/* The spin_unlock() and next spin_lock() provide needed ordering. */
163164
unsigned long tail = ACCESS_ONCE(buffer->tail);
164165

165166
if (CIRC_SPACE(head, tail, buffer->size) >= 1) {
@@ -168,9 +169,8 @@ The producer will look something like this:
168169

169170
produce_item(item);
170171

171-
smp_wmb(); /* commit the item before incrementing the head */
172-
173-
ACCESS_ONCE(buffer->head) = (head + 1) & (buffer->size - 1);
172+
smp_store_release(buffer->head,
173+
(head + 1) & (buffer->size - 1));
174174

175175
/* wake_up() will make sure that the head is committed before
176176
* waking anyone up */
@@ -200,21 +200,20 @@ The consumer will look something like this:
200200

201201
spin_lock(&consumer_lock);
202202

203-
unsigned long head = ACCESS_ONCE(buffer->head);
203+
/* Read index before reading contents at that index. */
204+
unsigned long head = smp_load_acquire(buffer->head);
204205
unsigned long tail = buffer->tail;
205206

206207
if (CIRC_CNT(head, tail, buffer->size) >= 1) {
207-
/* read index before reading contents at that index */
208-
smp_rmb();
209208

210209
/* extract one item from the buffer */
211210
struct item *item = buffer[tail];
212211

213212
consume_item(item);
214213

215-
smp_mb(); /* finish reading descriptor before incrementing tail */
216-
217-
ACCESS_ONCE(buffer->tail) = (tail + 1) & (buffer->size - 1);
214+
/* Finish reading descriptor before incrementing tail. */
215+
smp_store_release(buffer->tail,
216+
(tail + 1) & (buffer->size - 1));
218217
}
219218

220219
spin_unlock(&consumer_lock);
@@ -223,15 +222,17 @@ This will instruct the CPU to make sure the index is up to date before reading
223222
the new item, and then it shall make sure the CPU has finished reading the item
224223
before it writes the new tail pointer, which will erase the item.
225224

226-
227-
Note the use of ACCESS_ONCE() in both algorithms to read the opposition index.
228-
This prevents the compiler from discarding and reloading its cached value -
229-
which some compilers will do across smp_read_barrier_depends(). This isn't
230-
strictly needed if you can be sure that the opposition index will _only_ be
231-
used the once. Similarly, ACCESS_ONCE() is used in both algorithms to
232-
write the thread's index. This documents the fact that we are writing
233-
to something that can be read concurrently and also prevents the compiler
234-
from tearing the store.
225+
Note the use of ACCESS_ONCE() and smp_load_acquire() to read the
226+
opposition index. This prevents the compiler from discarding and
227+
reloading its cached value - which some compilers will do across
228+
smp_read_barrier_depends(). This isn't strictly needed if you can
229+
be sure that the opposition index will _only_ be used the once.
230+
The smp_load_acquire() additionally forces the CPU to order against
231+
subsequent memory references. Similarly, smp_store_release() is used
232+
in both algorithms to write the thread's index. This documents the
233+
fact that we are writing to something that can be read concurrently,
234+
prevents the compiler from tearing the store, and enforces ordering
235+
against previous accesses.
235236

236237

237238
===============

0 commit comments

Comments
 (0)