diff options
author | Michal Nazarewicz <m.nazarewicz@samsung.com> | 2010-05-05 06:53:11 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-05-20 16:21:42 -0400 |
commit | 22c43c81a51e05f61e90445ceb59d486c12fd921 (patch) | |
tree | 88582f01bf413bdc4d9d95a512116c9fe44afa33 /include/linux/wait.h | |
parent | 24337c133ff92ba8d7c42819db17f7f2b0de3129 (diff) |
wait_event_interruptible_locked() interface
New wait_event_interruptible{,_exclusive}_locked{,_irq} macros added.
They work just like versions without _locked* suffix but require the
wait queue's lock to be held. Also __wake_up_locked() is now exported
as to pair it with the above macros.
The use case of this new facility is when one uses wait queue's lock
to protect a data structure. This may be advantageous if the
structure needs to be protected by a spinlock anyway. In particular,
with additional spinlock the following code has to be used to wait
for a condition:
spin_lock(&data.lock);
...
for (ret = 0; !ret && !(condition); ) {
spin_unlock(&data.lock);
ret = wait_event_interruptible(data.wqh, (condition));
spin_lock(&data.lock);
}
...
spin_unlock(&data.lock);
This looks bizarre plus wait_event_interruptible() locks the wait
queue's lock anyway so there is a unlock+lock sequence where it could
be avoided.
To avoid those problems and benefit from wait queue's lock, a code
similar to the following should be used:
/* Waiting */
spin_lock(&data.wqh.lock);
...
ret = wait_event_interruptible_locked(data.wqh, (condition));
...
spin_unlock(&data.wqh.lock);
/* Waiting exclusively */
spin_lock(&data.whq.lock);
...
ret = wait_event_interruptible_exclusive_locked(data.whq, (condition));
...
spin_unlock(&data.whq.lock);
/* Waking up */
spin_lock(&data.wqh.lock);
...
wake_up_locked(&data.wqh);
...
spin_unlock(&data.wqh.lock);
When spin_lock_irq() is used matching versions of macros need to be
used (*_locked_irq()).
Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com>
Cc: Kyungmin Park <kyungmin.park@samsung.com>
Cc: Marek Szyprowski <m.szyprowski@samsung.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Takashi Iwai <tiwai@suse.de>
Cc: David Howells <dhowells@redhat.com>
Cc: Andreas Herrmann <andreas.herrmann3@amd.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Mike Galbraith <efault@gmx.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'include/linux/wait.h')
-rw-r--r-- | include/linux/wait.h | 149 |
1 files changed, 149 insertions, 0 deletions
diff --git a/include/linux/wait.h b/include/linux/wait.h index a48e16b77d5e..fc3c040e5e3a 100644 --- a/include/linux/wait.h +++ b/include/linux/wait.h | |||
@@ -362,6 +362,155 @@ do { \ | |||
362 | __ret; \ | 362 | __ret; \ |
363 | }) | 363 | }) |
364 | 364 | ||
365 | |||
366 | #define __wait_event_interruptible_locked(wq, condition, exclusive, irq) \ | ||
367 | ({ \ | ||
368 | int __ret = 0; \ | ||
369 | DEFINE_WAIT(__wait); \ | ||
370 | if (exclusive) \ | ||
371 | __wait.flags |= WQ_FLAG_EXCLUSIVE; \ | ||
372 | do { \ | ||
373 | if (likely(list_empty(&__wait.task_list))) \ | ||
374 | __add_wait_queue_tail(&(wq), &__wait); \ | ||
375 | set_current_state(TASK_INTERRUPTIBLE); \ | ||
376 | if (signal_pending(current)) { \ | ||
377 | __ret = -ERESTARTSYS; \ | ||
378 | break; \ | ||
379 | } \ | ||
380 | if (irq) \ | ||
381 | spin_unlock_irq(&(wq).lock); \ | ||
382 | else \ | ||
383 | spin_unlock(&(wq).lock); \ | ||
384 | schedule(); \ | ||
385 | if (irq) \ | ||
386 | spin_lock_irq(&(wq).lock); \ | ||
387 | else \ | ||
388 | spin_lock(&(wq).lock); \ | ||
389 | } while (!(condition)); \ | ||
390 | __remove_wait_queue(&(wq), &__wait); \ | ||
391 | __set_current_state(TASK_RUNNING); \ | ||
392 | __ret; \ | ||
393 | }) | ||
394 | |||
395 | |||
396 | /** | ||
397 | * wait_event_interruptible_locked - sleep until a condition gets true | ||
398 | * @wq: the waitqueue to wait on | ||
399 | * @condition: a C expression for the event to wait for | ||
400 | * | ||
401 | * The process is put to sleep (TASK_INTERRUPTIBLE) until the | ||
402 | * @condition evaluates to true or a signal is received. | ||
403 | * The @condition is checked each time the waitqueue @wq is woken up. | ||
404 | * | ||
405 | * It must be called with wq.lock being held. This spinlock is | ||
406 | * unlocked while sleeping but @condition testing is done while lock | ||
407 | * is held and when this macro exits the lock is held. | ||
408 | * | ||
409 | * The lock is locked/unlocked using spin_lock()/spin_unlock() | ||
410 | * functions which must match the way they are locked/unlocked outside | ||
411 | * of this macro. | ||
412 | * | ||
413 | * wake_up_locked() has to be called after changing any variable that could | ||
414 | * change the result of the wait condition. | ||
415 | * | ||
416 | * The function will return -ERESTARTSYS if it was interrupted by a | ||
417 | * signal and 0 if @condition evaluated to true. | ||
418 | */ | ||
419 | #define wait_event_interruptible_locked(wq, condition) \ | ||
420 | ((condition) \ | ||
421 | ? 0 : __wait_event_interruptible_locked(wq, condition, 0, 0)) | ||
422 | |||
423 | /** | ||
424 | * wait_event_interruptible_locked_irq - sleep until a condition gets true | ||
425 | * @wq: the waitqueue to wait on | ||
426 | * @condition: a C expression for the event to wait for | ||
427 | * | ||
428 | * The process is put to sleep (TASK_INTERRUPTIBLE) until the | ||
429 | * @condition evaluates to true or a signal is received. | ||
430 | * The @condition is checked each time the waitqueue @wq is woken up. | ||
431 | * | ||
432 | * It must be called with wq.lock being held. This spinlock is | ||
433 | * unlocked while sleeping but @condition testing is done while lock | ||
434 | * is held and when this macro exits the lock is held. | ||
435 | * | ||
436 | * The lock is locked/unlocked using spin_lock_irq()/spin_unlock_irq() | ||
437 | * functions which must match the way they are locked/unlocked outside | ||
438 | * of this macro. | ||
439 | * | ||
440 | * wake_up_locked() has to be called after changing any variable that could | ||
441 | * change the result of the wait condition. | ||
442 | * | ||
443 | * The function will return -ERESTARTSYS if it was interrupted by a | ||
444 | * signal and 0 if @condition evaluated to true. | ||
445 | */ | ||
446 | #define wait_event_interruptible_locked_irq(wq, condition) \ | ||
447 | ((condition) \ | ||
448 | ? 0 : __wait_event_interruptible_locked(wq, condition, 0, 1)) | ||
449 | |||
450 | /** | ||
451 | * wait_event_interruptible_exclusive_locked - sleep exclusively until a condition gets true | ||
452 | * @wq: the waitqueue to wait on | ||
453 | * @condition: a C expression for the event to wait for | ||
454 | * | ||
455 | * The process is put to sleep (TASK_INTERRUPTIBLE) until the | ||
456 | * @condition evaluates to true or a signal is received. | ||
457 | * The @condition is checked each time the waitqueue @wq is woken up. | ||
458 | * | ||
459 | * It must be called with wq.lock being held. This spinlock is | ||
460 | * unlocked while sleeping but @condition testing is done while lock | ||
461 | * is held and when this macro exits the lock is held. | ||
462 | * | ||
463 | * The lock is locked/unlocked using spin_lock()/spin_unlock() | ||
464 | * functions which must match the way they are locked/unlocked outside | ||
465 | * of this macro. | ||
466 | * | ||
467 | * The process is put on the wait queue with an WQ_FLAG_EXCLUSIVE flag | ||
468 | * set thus when other process waits process on the list if this | ||
469 | * process is awaken further processes are not considered. | ||
470 | * | ||
471 | * wake_up_locked() has to be called after changing any variable that could | ||
472 | * change the result of the wait condition. | ||
473 | * | ||
474 | * The function will return -ERESTARTSYS if it was interrupted by a | ||
475 | * signal and 0 if @condition evaluated to true. | ||
476 | */ | ||
477 | #define wait_event_interruptible_exclusive_locked(wq, condition) \ | ||
478 | ((condition) \ | ||
479 | ? 0 : __wait_event_interruptible_locked(wq, condition, 1, 0)) | ||
480 | |||
481 | /** | ||
482 | * wait_event_interruptible_exclusive_locked_irq - sleep until a condition gets true | ||
483 | * @wq: the waitqueue to wait on | ||
484 | * @condition: a C expression for the event to wait for | ||
485 | * | ||
486 | * The process is put to sleep (TASK_INTERRUPTIBLE) until the | ||
487 | * @condition evaluates to true or a signal is received. | ||
488 | * The @condition is checked each time the waitqueue @wq is woken up. | ||
489 | * | ||
490 | * It must be called with wq.lock being held. This spinlock is | ||
491 | * unlocked while sleeping but @condition testing is done while lock | ||
492 | * is held and when this macro exits the lock is held. | ||
493 | * | ||
494 | * The lock is locked/unlocked using spin_lock_irq()/spin_unlock_irq() | ||
495 | * functions which must match the way they are locked/unlocked outside | ||
496 | * of this macro. | ||
497 | * | ||
498 | * The process is put on the wait queue with an WQ_FLAG_EXCLUSIVE flag | ||
499 | * set thus when other process waits process on the list if this | ||
500 | * process is awaken further processes are not considered. | ||
501 | * | ||
502 | * wake_up_locked() has to be called after changing any variable that could | ||
503 | * change the result of the wait condition. | ||
504 | * | ||
505 | * The function will return -ERESTARTSYS if it was interrupted by a | ||
506 | * signal and 0 if @condition evaluated to true. | ||
507 | */ | ||
508 | #define wait_event_interruptible_exclusive_locked_irq(wq, condition) \ | ||
509 | ((condition) \ | ||
510 | ? 0 : __wait_event_interruptible_locked(wq, condition, 1, 1)) | ||
511 | |||
512 | |||
513 | |||
365 | #define __wait_event_killable(wq, condition, ret) \ | 514 | #define __wait_event_killable(wq, condition, ret) \ |
366 | do { \ | 515 | do { \ |
367 | DEFINE_WAIT(__wait); \ | 516 | DEFINE_WAIT(__wait); \ |