aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/sched/wait.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/sched/wait.c')
-rw-r--r--kernel/sched/wait.c123
1 files changed, 55 insertions, 68 deletions
diff --git a/kernel/sched/wait.c b/kernel/sched/wait.c
index f15d6b6a538a..9453efe9b25a 100644
--- a/kernel/sched/wait.c
+++ b/kernel/sched/wait.c
@@ -196,27 +196,48 @@ prepare_to_wait_exclusive(wait_queue_head_t *q, wait_queue_t *wait, int state)
196} 196}
197EXPORT_SYMBOL(prepare_to_wait_exclusive); 197EXPORT_SYMBOL(prepare_to_wait_exclusive);
198 198
199long prepare_to_wait_event(wait_queue_head_t *q, wait_queue_t *wait, int state) 199void init_wait_entry(wait_queue_t *wait, int flags)
200{ 200{
201 unsigned long flags; 201 wait->flags = flags;
202
203 if (signal_pending_state(state, current))
204 return -ERESTARTSYS;
205
206 wait->private = current; 202 wait->private = current;
207 wait->func = autoremove_wake_function; 203 wait->func = autoremove_wake_function;
204 INIT_LIST_HEAD(&wait->task_list);
205}
206EXPORT_SYMBOL(init_wait_entry);
207
208long prepare_to_wait_event(wait_queue_head_t *q, wait_queue_t *wait, int state)
209{
210 unsigned long flags;
211 long ret = 0;
208 212
209 spin_lock_irqsave(&q->lock, flags); 213 spin_lock_irqsave(&q->lock, flags);
210 if (list_empty(&wait->task_list)) { 214 if (unlikely(signal_pending_state(state, current))) {
211 if (wait->flags & WQ_FLAG_EXCLUSIVE) 215 /*
212 __add_wait_queue_tail(q, wait); 216 * Exclusive waiter must not fail if it was selected by wakeup,
213 else 217 * it should "consume" the condition we were waiting for.
214 __add_wait_queue(q, wait); 218 *
219 * The caller will recheck the condition and return success if
220 * we were already woken up, we can not miss the event because
221 * wakeup locks/unlocks the same q->lock.
222 *
223 * But we need to ensure that set-condition + wakeup after that
224 * can't see us, it should wake up another exclusive waiter if
225 * we fail.
226 */
227 list_del_init(&wait->task_list);
228 ret = -ERESTARTSYS;
229 } else {
230 if (list_empty(&wait->task_list)) {
231 if (wait->flags & WQ_FLAG_EXCLUSIVE)
232 __add_wait_queue_tail(q, wait);
233 else
234 __add_wait_queue(q, wait);
235 }
236 set_current_state(state);
215 } 237 }
216 set_current_state(state);
217 spin_unlock_irqrestore(&q->lock, flags); 238 spin_unlock_irqrestore(&q->lock, flags);
218 239
219 return 0; 240 return ret;
220} 241}
221EXPORT_SYMBOL(prepare_to_wait_event); 242EXPORT_SYMBOL(prepare_to_wait_event);
222 243
@@ -255,39 +276,6 @@ void finish_wait(wait_queue_head_t *q, wait_queue_t *wait)
255} 276}
256EXPORT_SYMBOL(finish_wait); 277EXPORT_SYMBOL(finish_wait);
257 278
258/**
259 * abort_exclusive_wait - abort exclusive waiting in a queue
260 * @q: waitqueue waited on
261 * @wait: wait descriptor
262 * @mode: runstate of the waiter to be woken
263 * @key: key to identify a wait bit queue or %NULL
264 *
265 * Sets current thread back to running state and removes
266 * the wait descriptor from the given waitqueue if still
267 * queued.
268 *
269 * Wakes up the next waiter if the caller is concurrently
270 * woken up through the queue.
271 *
272 * This prevents waiter starvation where an exclusive waiter
273 * aborts and is woken up concurrently and no one wakes up
274 * the next waiter.
275 */
276void abort_exclusive_wait(wait_queue_head_t *q, wait_queue_t *wait,
277 unsigned int mode, void *key)
278{
279 unsigned long flags;
280
281 __set_current_state(TASK_RUNNING);
282 spin_lock_irqsave(&q->lock, flags);
283 if (!list_empty(&wait->task_list))
284 list_del_init(&wait->task_list);
285 else if (waitqueue_active(q))
286 __wake_up_locked_key(q, mode, key);
287 spin_unlock_irqrestore(&q->lock, flags);
288}
289EXPORT_SYMBOL(abort_exclusive_wait);
290
291int autoremove_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key) 279int autoremove_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key)
292{ 280{
293 int ret = default_wake_function(wait, mode, sync, key); 281 int ret = default_wake_function(wait, mode, sync, key);
@@ -425,20 +413,29 @@ int __sched
425__wait_on_bit_lock(wait_queue_head_t *wq, struct wait_bit_queue *q, 413__wait_on_bit_lock(wait_queue_head_t *wq, struct wait_bit_queue *q,
426 wait_bit_action_f *action, unsigned mode) 414 wait_bit_action_f *action, unsigned mode)
427{ 415{
428 do { 416 int ret = 0;
429 int ret;
430 417
418 for (;;) {
431 prepare_to_wait_exclusive(wq, &q->wait, mode); 419 prepare_to_wait_exclusive(wq, &q->wait, mode);
432 if (!test_bit(q->key.bit_nr, q->key.flags)) 420 if (test_bit(q->key.bit_nr, q->key.flags)) {
433 continue; 421 ret = action(&q->key, mode);
434 ret = action(&q->key, mode); 422 /*
435 if (!ret) 423 * See the comment in prepare_to_wait_event().
436 continue; 424 * finish_wait() does not necessarily takes wq->lock,
437 abort_exclusive_wait(wq, &q->wait, mode, &q->key); 425 * but test_and_set_bit() implies mb() which pairs with
438 return ret; 426 * smp_mb__after_atomic() before wake_up_page().
439 } while (test_and_set_bit(q->key.bit_nr, q->key.flags)); 427 */
440 finish_wait(wq, &q->wait); 428 if (ret)
441 return 0; 429 finish_wait(wq, &q->wait);
430 }
431 if (!test_and_set_bit(q->key.bit_nr, q->key.flags)) {
432 if (!ret)
433 finish_wait(wq, &q->wait);
434 return 0;
435 } else if (ret) {
436 return ret;
437 }
438 }
442} 439}
443EXPORT_SYMBOL(__wait_on_bit_lock); 440EXPORT_SYMBOL(__wait_on_bit_lock);
444 441
@@ -483,16 +480,6 @@ void wake_up_bit(void *word, int bit)
483} 480}
484EXPORT_SYMBOL(wake_up_bit); 481EXPORT_SYMBOL(wake_up_bit);
485 482
486wait_queue_head_t *bit_waitqueue(void *word, int bit)
487{
488 const int shift = BITS_PER_LONG == 32 ? 5 : 6;
489 const struct zone *zone = page_zone(virt_to_page(word));
490 unsigned long val = (unsigned long)word << shift | bit;
491
492 return &zone->wait_table[hash_long(val, zone->wait_table_bits)];
493}
494EXPORT_SYMBOL(bit_waitqueue);
495
496/* 483/*
497 * Manipulate the atomic_t address to produce a better bit waitqueue table hash 484 * Manipulate the atomic_t address to produce a better bit waitqueue table hash
498 * index (we're keying off bit -1, but that would produce a horrible hash 485 * index (we're keying off bit -1, but that would produce a horrible hash