diff options
author | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2013-11-04 14:20:56 -0500 |
---|---|---|
committer | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2013-12-03 13:08:57 -0500 |
commit | 6c43c091bdc56b8cab888cfa6b0ee9effb5fc255 (patch) | |
tree | 9cf326daf1bae24cdde58c12d3304edadea06036 | |
parent | 9873552fc1b01ef9bddc9fec4c492d9fa8b27f51 (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.txt | 37 |
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 | |||
223 | the new item, and then it shall make sure the CPU has finished reading the item | 222 | the new item, and then it shall make sure the CPU has finished reading the item |
224 | before it writes the new tail pointer, which will erase the item. | 223 | before it writes the new tail pointer, which will erase the item. |
225 | 224 | ||
226 | 225 | Note the use of ACCESS_ONCE() and smp_load_acquire() to read the | |
227 | Note the use of ACCESS_ONCE() in both algorithms to read the opposition index. | 226 | opposition index. This prevents the compiler from discarding and |
228 | This prevents the compiler from discarding and reloading its cached value - | 227 | reloading its cached value - which some compilers will do across |
229 | which some compilers will do across smp_read_barrier_depends(). This isn't | 228 | smp_read_barrier_depends(). This isn't strictly needed if you can |
230 | strictly needed if you can be sure that the opposition index will _only_ be | 229 | be sure that the opposition index will _only_ be used the once. |
231 | used the once. Similarly, ACCESS_ONCE() is used in both algorithms to | 230 | The smp_load_acquire() additionally forces the CPU to order against |
232 | write the thread's index. This documents the fact that we are writing | 231 | subsequent memory references. Similarly, smp_store_release() is used |
233 | to something that can be read concurrently and also prevents the compiler | 232 | in both algorithms to write the thread's index. This documents the |
234 | from tearing the store. | 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 | =============== |