Skip to content

Commit b1ea06a

Browse files
oleg-nesterovIngo Molnar
authored andcommitted
sched/wait: Avoid abort_exclusive_wait() in ___wait_event()
___wait_event() doesn't really need abort_exclusive_wait(), we can simply change prepare_to_wait_event() to remove the waiter from q->task_list if it was interrupted. This simplifies the code/logic, and this way prepare_to_wait_event() can have more users, see the next change. Signed-off-by: Oleg Nesterov <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Cc: Al Viro <[email protected]> Cc: Bart Van Assche <[email protected]> Cc: Johannes Weiner <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: Mike Galbraith <[email protected]> Cc: Neil Brown <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Thomas Gleixner <[email protected]> Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Ingo Molnar <[email protected]> -- include/linux/wait.h | 7 +------ kernel/sched/wait.c | 35 +++++++++++++++++++++++++---------- 2 files changed, 26 insertions(+), 16 deletions(-)
1 parent 38a3e1f commit b1ea06a

File tree

2 files changed

+26
-16
lines changed

2 files changed

+26
-16
lines changed

include/linux/wait.h

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -280,12 +280,7 @@ wait_queue_head_t *bit_waitqueue(void *, int);
280280
\
281281
if (___wait_is_interruptible(state) && __int) { \
282282
__ret = __int; \
283-
if (exclusive) { \
284-
abort_exclusive_wait(&wq, &__wait, \
285-
NULL); \
286-
goto __out; \
287-
} \
288-
break; \
283+
goto __out; \
289284
} \
290285
\
291286
cmd; \

kernel/sched/wait.c

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -199,24 +199,39 @@ EXPORT_SYMBOL(prepare_to_wait_exclusive);
199199
long prepare_to_wait_event(wait_queue_head_t *q, wait_queue_t *wait, int state)
200200
{
201201
unsigned long flags;
202-
203-
if (signal_pending_state(state, current))
204-
return -ERESTARTSYS;
202+
long ret = 0;
205203

206204
wait->private = current;
207205
wait->func = autoremove_wake_function;
208206

209207
spin_lock_irqsave(&q->lock, flags);
210-
if (list_empty(&wait->task_list)) {
211-
if (wait->flags & WQ_FLAG_EXCLUSIVE)
212-
__add_wait_queue_tail(q, wait);
213-
else
214-
__add_wait_queue(q, wait);
208+
if (unlikely(signal_pending_state(state, current))) {
209+
/*
210+
* Exclusive waiter must not fail if it was selected by wakeup,
211+
* it should "consume" the condition we were waiting for.
212+
*
213+
* The caller will recheck the condition and return success if
214+
* we were already woken up, we can not miss the event because
215+
* wakeup locks/unlocks the same q->lock.
216+
*
217+
* But we need to ensure that set-condition + wakeup after that
218+
* can't see us, it should wake up another exclusive waiter if
219+
* we fail.
220+
*/
221+
list_del_init(&wait->task_list);
222+
ret = -ERESTARTSYS;
223+
} else {
224+
if (list_empty(&wait->task_list)) {
225+
if (wait->flags & WQ_FLAG_EXCLUSIVE)
226+
__add_wait_queue_tail(q, wait);
227+
else
228+
__add_wait_queue(q, wait);
229+
}
230+
set_current_state(state);
215231
}
216-
set_current_state(state);
217232
spin_unlock_irqrestore(&q->lock, flags);
218233

219-
return 0;
234+
return ret;
220235
}
221236
EXPORT_SYMBOL(prepare_to_wait_event);
222237

0 commit comments

Comments
 (0)