diff options
Diffstat (limited to 'kernel/sched/wait.c')
-rw-r--r-- | kernel/sched/wait.c | 123 |
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 | } |
197 | EXPORT_SYMBOL(prepare_to_wait_exclusive); | 197 | EXPORT_SYMBOL(prepare_to_wait_exclusive); |
198 | 198 | ||
199 | long prepare_to_wait_event(wait_queue_head_t *q, wait_queue_t *wait, int state) | 199 | void 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 | } | ||
206 | EXPORT_SYMBOL(init_wait_entry); | ||
207 | |||
208 | long 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 | } |
221 | EXPORT_SYMBOL(prepare_to_wait_event); | 242 | EXPORT_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 | } |
256 | EXPORT_SYMBOL(finish_wait); | 277 | EXPORT_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 | */ | ||
276 | void 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 | } | ||
289 | EXPORT_SYMBOL(abort_exclusive_wait); | ||
290 | |||
291 | int autoremove_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key) | 279 | int 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 | } |
443 | EXPORT_SYMBOL(__wait_on_bit_lock); | 440 | EXPORT_SYMBOL(__wait_on_bit_lock); |
444 | 441 | ||
@@ -483,16 +480,6 @@ void wake_up_bit(void *word, int bit) | |||
483 | } | 480 | } |
484 | EXPORT_SYMBOL(wake_up_bit); | 481 | EXPORT_SYMBOL(wake_up_bit); |
485 | 482 | ||
486 | wait_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 | } | ||
494 | EXPORT_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 |