aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/futex.c
diff options
context:
space:
mode:
authorDavidlohr Bueso <davidlohr@hp.com>2014-04-09 14:55:07 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-04-12 20:57:51 -0400
commitd7e8af1afeffb03ab250b91cd70ba8c701f0f2b7 (patch)
tree6d86d4e19034d9c66392fc8904477dc5288ca850 /kernel/futex.c
parent454fd351f2e2b6baa926d61064aaf70d2a77976e (diff)
futex: update documentation for ordering guarantees
Commits 11d4616bd07f ("futex: revert back to the explicit waiter counting code") and 69cd9eba3886 ("futex: avoid race between requeue and wake") changed some of the finer details of how we think about futexes. One was a late fix and the other a consequence of overlooking the whole requeuing logic. The first change caused our documentation to be incorrect, and the second made us aware that we need to explicitly add more details to it. Signed-off-by: Davidlohr Bueso <davidlohr@hp.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel/futex.c')
-rw-r--r--kernel/futex.c32
1 files changed, 23 insertions, 9 deletions
diff --git a/kernel/futex.c b/kernel/futex.c
index 6801b3751a95..5f589279e462 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -70,7 +70,10 @@
70#include "locking/rtmutex_common.h" 70#include "locking/rtmutex_common.h"
71 71
72/* 72/*
73 * Basic futex operation and ordering guarantees: 73 * READ this before attempting to hack on futexes!
74 *
75 * Basic futex operation and ordering guarantees
76 * =============================================
74 * 77 *
75 * The waiter reads the futex value in user space and calls 78 * The waiter reads the futex value in user space and calls
76 * futex_wait(). This function computes the hash bucket and acquires 79 * futex_wait(). This function computes the hash bucket and acquires
@@ -119,7 +122,7 @@
119 * sys_futex(WAIT, futex, val); 122 * sys_futex(WAIT, futex, val);
120 * futex_wait(futex, val); 123 * futex_wait(futex, val);
121 * 124 *
122 * waiters++; 125 * waiters++; (a)
123 * mb(); (A) <-- paired with -. 126 * mb(); (A) <-- paired with -.
124 * | 127 * |
125 * lock(hash_bucket(futex)); | 128 * lock(hash_bucket(futex)); |
@@ -135,14 +138,14 @@
135 * unlock(hash_bucket(futex)); 138 * unlock(hash_bucket(futex));
136 * schedule(); if (waiters) 139 * schedule(); if (waiters)
137 * lock(hash_bucket(futex)); 140 * lock(hash_bucket(futex));
138 * wake_waiters(futex); 141 * else wake_waiters(futex);
139 * unlock(hash_bucket(futex)); 142 * waiters--; (b) unlock(hash_bucket(futex));
140 * 143 *
141 * Where (A) orders the waiters increment and the futex value read -- this 144 * Where (A) orders the waiters increment and the futex value read through
142 * is guaranteed by the head counter in the hb spinlock; and where (B) 145 * atomic operations (see hb_waiters_inc) and where (B) orders the write
143 * orders the write to futex and the waiters read -- this is done by the 146 * to futex and the waiters read -- this is done by the barriers in
144 * barriers in get_futex_key_refs(), through either ihold or atomic_inc, 147 * get_futex_key_refs(), through either ihold or atomic_inc, depending on the
145 * depending on the futex type. 148 * futex type.
146 * 149 *
147 * This yields the following case (where X:=waiters, Y:=futex): 150 * This yields the following case (where X:=waiters, Y:=futex):
148 * 151 *
@@ -155,6 +158,17 @@
155 * Which guarantees that x==0 && y==0 is impossible; which translates back into 158 * Which guarantees that x==0 && y==0 is impossible; which translates back into
156 * the guarantee that we cannot both miss the futex variable change and the 159 * the guarantee that we cannot both miss the futex variable change and the
157 * enqueue. 160 * enqueue.
161 *
162 * Note that a new waiter is accounted for in (a) even when it is possible that
163 * the wait call can return error, in which case we backtrack from it in (b).
164 * Refer to the comment in queue_lock().
165 *
166 * Similarly, in order to account for waiters being requeued on another
167 * address we always increment the waiters for the destination bucket before
168 * acquiring the lock. It then decrements them again after releasing it -
169 * the code that actually moves the futex(es) between hash buckets (requeue_futex)
170 * will do the additional required waiter count housekeeping. This is done for
171 * double_lock_hb() and double_unlock_hb(), respectively.
158 */ 172 */
159 173
160#ifndef CONFIG_HAVE_FUTEX_CMPXCHG 174#ifndef CONFIG_HAVE_FUTEX_CMPXCHG