aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul E. McKenney <paulmck@linux.vnet.ibm.com>2013-11-04 14:20:56 -0500
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>2013-12-03 13:08:57 -0500
commit6c43c091bdc56b8cab888cfa6b0ee9effb5fc255 (patch)
tree9cf326daf1bae24cdde58c12d3304edadea06036
parent9873552fc1b01ef9bddc9fec4c492d9fa8b27f51 (diff)
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. ]
-rw-r--r--Documentation/circular-buffers.txt37
1 files changed, 19 insertions, 18 deletions
diff --git a/Documentation/circular-buffers.txt b/Documentation/circular-buffers.txt
index a36bed3db4ee..88951b179262 100644
--- a/Documentation/circular-buffers.txt
+++ b/Documentation/circular-buffers.txt
@@ -160,6 +160,7 @@ The producer will look something like this:
160 spin_lock(&producer_lock); 160 spin_lock(&producer_lock);
161 161
162 unsigned long head = buffer->head; 162 unsigned long head = buffer->head;
163 /* The spin_unlock() and next spin_lock() provide needed ordering. */
163 unsigned long tail = ACCESS_ONCE(buffer->tail); 164 unsigned long tail = ACCESS_ONCE(buffer->tail);
164 165
165 if (CIRC_SPACE(head, tail, buffer->size) >= 1) { 166 if (CIRC_SPACE(head, tail, buffer->size) >= 1) {
@@ -168,9 +169,8 @@ The producer will look something like this:
168 169
169 produce_item(item); 170 produce_item(item);
170 171
171 smp_wmb(); /* commit the item before incrementing the head */ 172 smp_store_release(buffer->head,
172 173 (head + 1) & (buffer->size - 1));
173 ACCESS_ONCE(buffer->head) = (head + 1) & (buffer->size - 1);
174 174
175 /* wake_up() will make sure that the head is committed before 175 /* wake_up() will make sure that the head is committed before
176 * waking anyone up */ 176 * waking anyone up */
@@ -200,21 +200,20 @@ The consumer will look something like this:
200 200
201 spin_lock(&consumer_lock); 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 unsigned long tail = buffer->tail; 205 unsigned long tail = buffer->tail;
205 206
206 if (CIRC_CNT(head, tail, buffer->size) >= 1) { 207 if (CIRC_CNT(head, tail, buffer->size) >= 1) {
207 /* read index before reading contents at that index */
208 smp_rmb();
209 208
210 /* extract one item from the buffer */ 209 /* extract one item from the buffer */
211 struct item *item = buffer[tail]; 210 struct item *item = buffer[tail];
212 211
213 consume_item(item); 212 consume_item(item);
214 213
215 smp_mb(); /* finish reading descriptor before incrementing tail */ 214 /* Finish reading descriptor before incrementing tail. */
216 215 smp_store_release(buffer->tail,
217 ACCESS_ONCE(buffer->tail) = (tail + 1) & (buffer->size - 1); 216 (tail + 1) & (buffer->size - 1));
218 } 217 }
219 218
220 spin_unlock(&consumer_lock); 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
223the new item, and then it shall make sure the CPU has finished reading the item 222the new item, and then it shall make sure the CPU has finished reading the item
224before it writes the new tail pointer, which will erase the item. 223before it writes the new tail pointer, which will erase the item.
225 224
226 225Note the use of ACCESS_ONCE() and smp_load_acquire() to read the
227Note the use of ACCESS_ONCE() in both algorithms to read the opposition index. 226opposition index. This prevents the compiler from discarding and
228This prevents the compiler from discarding and reloading its cached value - 227reloading its cached value - which some compilers will do across
229which some compilers will do across smp_read_barrier_depends(). This isn't 228smp_read_barrier_depends(). This isn't strictly needed if you can
230strictly needed if you can be sure that the opposition index will _only_ be 229be sure that the opposition index will _only_ be used the once.
231used the once. Similarly, ACCESS_ONCE() is used in both algorithms to 230The smp_load_acquire() additionally forces the CPU to order against
232write the thread's index. This documents the fact that we are writing 231subsequent memory references. Similarly, smp_store_release() is used
233to something that can be read concurrently and also prevents the compiler 232in both algorithms to write the thread's index. This documents the
234from tearing the store. 233fact that we are writing to something that can be read concurrently,
234prevents the compiler from tearing the store, and enforces ordering
235against previous accesses.
235 236
236 237
237=============== 238===============