diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2014-01-12 18:31:24 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2014-01-13 05:45:19 -0500 |
commit | 99b60ce69734dfeda58c6184a326b9475ce1dba3 (patch) | |
tree | f9e4c7f179859f3e20bdd5e7c501196f0a07eddf | |
parent | a52b89ebb6d4499be38780db8d176c5d3a6fbc17 (diff) |
futexes: Document multiprocessor ordering guarantees
That's essential, if you want to hack on futexes.
Reviewed-by: Darren Hart <dvhart@linux.intel.com>
Reviewed-by: Peter Zijlstra <peterz@infradead.org>
Reviewed-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Davidlohr Bueso <davidlohr@hp.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Jeff Mahoney <jeffm@suse.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Randy Dunlap <rdunlap@infradead.org>
Cc: Scott Norton <scott.norton@hp.com>
Cc: Tom Vaden <tom.vaden@hp.com>
Cc: Aswin Chandramouleeswaran <aswin@hp.com>
Cc: Waiman Long <Waiman.Long@hp.com>
Cc: Jason Low <jason.low2@hp.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Link: http://lkml.kernel.org/r/1389569486-25487-4-git-send-email-davidlohr@hp.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | kernel/futex.c | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/kernel/futex.c b/kernel/futex.c index 577481d5c59d..fcc6850483fb 100644 --- a/kernel/futex.c +++ b/kernel/futex.c | |||
@@ -69,6 +69,63 @@ | |||
69 | 69 | ||
70 | #include "locking/rtmutex_common.h" | 70 | #include "locking/rtmutex_common.h" |
71 | 71 | ||
72 | /* | ||
73 | * Basic futex operation and ordering guarantees: | ||
74 | * | ||
75 | * The waiter reads the futex value in user space and calls | ||
76 | * futex_wait(). This function computes the hash bucket and acquires | ||
77 | * the hash bucket lock. After that it reads the futex user space value | ||
78 | * again and verifies that the data has not changed. If it has not | ||
79 | * changed it enqueues itself into the hash bucket, releases the hash | ||
80 | * bucket lock and schedules. | ||
81 | * | ||
82 | * The waker side modifies the user space value of the futex and calls | ||
83 | * futex_wake(). This functions computes the hash bucket and acquires | ||
84 | * the hash bucket lock. Then it looks for waiters on that futex in the | ||
85 | * hash bucket and wakes them. | ||
86 | * | ||
87 | * Note that the spin_lock serializes waiters and wakers, so that the | ||
88 | * following scenario is avoided: | ||
89 | * | ||
90 | * CPU 0 CPU 1 | ||
91 | * val = *futex; | ||
92 | * sys_futex(WAIT, futex, val); | ||
93 | * futex_wait(futex, val); | ||
94 | * uval = *futex; | ||
95 | * *futex = newval; | ||
96 | * sys_futex(WAKE, futex); | ||
97 | * futex_wake(futex); | ||
98 | * if (queue_empty()) | ||
99 | * return; | ||
100 | * if (uval == val) | ||
101 | * lock(hash_bucket(futex)); | ||
102 | * queue(); | ||
103 | * unlock(hash_bucket(futex)); | ||
104 | * schedule(); | ||
105 | * | ||
106 | * This would cause the waiter on CPU 0 to wait forever because it | ||
107 | * missed the transition of the user space value from val to newval | ||
108 | * and the waker did not find the waiter in the hash bucket queue. | ||
109 | * The spinlock serializes that: | ||
110 | * | ||
111 | * CPU 0 CPU 1 | ||
112 | * val = *futex; | ||
113 | * sys_futex(WAIT, futex, val); | ||
114 | * futex_wait(futex, val); | ||
115 | * lock(hash_bucket(futex)); | ||
116 | * uval = *futex; | ||
117 | * *futex = newval; | ||
118 | * sys_futex(WAKE, futex); | ||
119 | * futex_wake(futex); | ||
120 | * lock(hash_bucket(futex)); | ||
121 | * if (uval == val) | ||
122 | * queue(); | ||
123 | * unlock(hash_bucket(futex)); | ||
124 | * schedule(); if (!queue_empty()) | ||
125 | * wake_waiters(futex); | ||
126 | * unlock(hash_bucket(futex)); | ||
127 | */ | ||
128 | |||
72 | int __read_mostly futex_cmpxchg_enabled; | 129 | int __read_mostly futex_cmpxchg_enabled; |
73 | 130 | ||
74 | /* | 131 | /* |