Skip to content

Commit 8cd641e

Browse files
Davidlohr Buesobonzini
authored andcommitted
sched/wait: Add swq_has_sleeper()
Which is the equivalent of what we have in regular waitqueues. I'm not crazy about the name, but this also helps us get both apis closer -- which iirc comes originally from the -net folks. We also duplicate the comments for the lockless swait_active(), from wait.h. Future users will make use of this interface. Signed-off-by: Davidlohr Bueso <dbueso@suse.de> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
1 parent 3a8b067 commit 8cd641e

File tree

1 file changed

+56
-2
lines changed

1 file changed

+56
-2
lines changed

include/linux/swait.h

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,63 @@ extern void __init_swait_queue_head(struct swait_queue_head *q, const char *name
7979
DECLARE_SWAIT_QUEUE_HEAD(name)
8080
#endif
8181

82-
static inline int swait_active(struct swait_queue_head *q)
82+
/**
83+
* swait_active -- locklessly test for waiters on the queue
84+
* @wq: the waitqueue to test for waiters
85+
*
86+
* returns true if the wait list is not empty
87+
*
88+
* NOTE: this function is lockless and requires care, incorrect usage _will_
89+
* lead to sporadic and non-obvious failure.
90+
*
91+
* NOTE2: this function has the same above implications as regular waitqueues.
92+
*
93+
* Use either while holding swait_queue_head::lock or when used for wakeups
94+
* with an extra smp_mb() like:
95+
*
96+
* CPU0 - waker CPU1 - waiter
97+
*
98+
* for (;;) {
99+
* @cond = true; prepare_to_swait(&wq_head, &wait, state);
100+
* smp_mb(); // smp_mb() from set_current_state()
101+
* if (swait_active(wq_head)) if (@cond)
102+
* wake_up(wq_head); break;
103+
* schedule();
104+
* }
105+
* finish_swait(&wq_head, &wait);
106+
*
107+
* Because without the explicit smp_mb() it's possible for the
108+
* swait_active() load to get hoisted over the @cond store such that we'll
109+
* observe an empty wait list while the waiter might not observe @cond.
110+
* This, in turn, can trigger missing wakeups.
111+
*
112+
* Also note that this 'optimization' trades a spin_lock() for an smp_mb(),
113+
* which (when the lock is uncontended) are of roughly equal cost.
114+
*/
115+
static inline int swait_active(struct swait_queue_head *wq)
116+
{
117+
return !list_empty(&wq->task_list);
118+
}
119+
120+
/**
121+
* swq_has_sleeper - check if there are any waiting processes
122+
* @wq: the waitqueue to test for waiters
123+
*
124+
* Returns true if @wq has waiting processes
125+
*
126+
* Please refer to the comment for swait_active.
127+
*/
128+
static inline bool swq_has_sleeper(struct swait_queue_head *wq)
83129
{
84-
return !list_empty(&q->task_list);
130+
/*
131+
* We need to be sure we are in sync with the list_add()
132+
* modifications to the wait queue (task_list).
133+
*
134+
* This memory barrier should be paired with one on the
135+
* waiting side.
136+
*/
137+
smp_mb();
138+
return swait_active(wq);
85139
}
86140

87141
extern void swake_up(struct swait_queue_head *q);

0 commit comments

Comments
 (0)