summaryrefslogtreecommitdiffstats
path: root/include/linux/wait.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/linux/wait.h')
-rw-r--r--include/linux/wait.h30
1 files changed, 30 insertions, 0 deletions
diff --git a/include/linux/wait.h b/include/linux/wait.h
index 1e1bf9f963a9..f3bac30587f7 100644
--- a/include/linux/wait.h
+++ b/include/linux/wait.h
@@ -102,6 +102,36 @@ init_waitqueue_func_entry(wait_queue_t *q, wait_queue_func_t func)
102 q->func = func; 102 q->func = func;
103} 103}
104 104
105/**
106 * waitqueue_active -- locklessly test for waiters on the queue
107 * @q: the waitqueue to test for waiters
108 *
109 * returns true if the wait list is not empty
110 *
111 * NOTE: this function is lockless and requires care, incorrect usage _will_
112 * lead to sporadic and non-obvious failure.
113 *
114 * Use either while holding wait_queue_head_t::lock or when used for wakeups
115 * with an extra smp_mb() like:
116 *
117 * CPU0 - waker CPU1 - waiter
118 *
119 * for (;;) {
120 * @cond = true; prepare_to_wait(&wq, &wait, state);
121 * smp_mb(); // smp_mb() from set_current_state()
122 * if (waitqueue_active(wq)) if (@cond)
123 * wake_up(wq); break;
124 * schedule();
125 * }
126 * finish_wait(&wq, &wait);
127 *
128 * Because without the explicit smp_mb() it's possible for the
129 * waitqueue_active() load to get hoisted over the @cond store such that we'll
130 * observe an empty wait list while the waiter might not observe @cond.
131 *
132 * Also note that this 'optimization' trades a spin_lock() for an smp_mb(),
133 * which (when the lock is uncontended) are of roughly equal cost.
134 */
105static inline int waitqueue_active(wait_queue_head_t *q) 135static inline int waitqueue_active(wait_queue_head_t *q)
106{ 136{
107 return !list_empty(&q->task_list); 137 return !list_empty(&q->task_list);