@@ -160,6 +160,7 @@ The producer will look something like this:
160
160
spin_lock(&producer_lock);
161
161
162
162
unsigned long head = buffer->head;
163
+ /* The spin_unlock() and next spin_lock() provide needed ordering. */
163
164
unsigned long tail = ACCESS_ONCE(buffer->tail);
164
165
165
166
if (CIRC_SPACE(head, tail, buffer->size) >= 1) {
@@ -168,9 +169,8 @@ The producer will look something like this:
168
169
169
170
produce_item(item);
170
171
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));
174
174
175
175
/* wake_up() will make sure that the head is committed before
176
176
* waking anyone up */
@@ -200,21 +200,20 @@ The consumer will look something like this:
200
200
201
201
spin_lock(&consumer_lock);
202
202
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);
204
205
unsigned long tail = buffer->tail;
205
206
206
207
if (CIRC_CNT(head, tail, buffer->size) >= 1) {
207
- /* read index before reading contents at that index */
208
- smp_rmb();
209
208
210
209
/* extract one item from the buffer */
211
210
struct item *item = buffer[tail];
212
211
213
212
consume_item(item);
214
213
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) );
218
217
}
219
218
220
219
spin_unlock(&consumer_lock);
@@ -223,15 +222,17 @@ This will instruct the CPU to make sure the index is up to date before reading
223
222
the new item, and then it shall make sure the CPU has finished reading the item
224
223
before it writes the new tail pointer, which will erase the item.
225
224
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.
235
236
236
237
237
238
===============
0 commit comments