mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-12-29 17:25:38 +00:00
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>
This commit is contained in:
parent
24337c133f
commit
22c43c81a5
@ -362,6 +362,155 @@ do { \
|
||||
__ret; \
|
||||
})
|
||||
|
||||
|
||||
#define __wait_event_interruptible_locked(wq, condition, exclusive, irq) \
|
||||
({ \
|
||||
int __ret = 0; \
|
||||
DEFINE_WAIT(__wait); \
|
||||
if (exclusive) \
|
||||
__wait.flags |= WQ_FLAG_EXCLUSIVE; \
|
||||
do { \
|
||||
if (likely(list_empty(&__wait.task_list))) \
|
||||
__add_wait_queue_tail(&(wq), &__wait); \
|
||||
set_current_state(TASK_INTERRUPTIBLE); \
|
||||
if (signal_pending(current)) { \
|
||||
__ret = -ERESTARTSYS; \
|
||||
break; \
|
||||
} \
|
||||
if (irq) \
|
||||
spin_unlock_irq(&(wq).lock); \
|
||||
else \
|
||||
spin_unlock(&(wq).lock); \
|
||||
schedule(); \
|
||||
if (irq) \
|
||||
spin_lock_irq(&(wq).lock); \
|
||||
else \
|
||||
spin_lock(&(wq).lock); \
|
||||
} while (!(condition)); \
|
||||
__remove_wait_queue(&(wq), &__wait); \
|
||||
__set_current_state(TASK_RUNNING); \
|
||||
__ret; \
|
||||
})
|
||||
|
||||
|
||||
/**
|
||||
* wait_event_interruptible_locked - sleep until a condition gets true
|
||||
* @wq: the waitqueue to wait on
|
||||
* @condition: a C expression for the event to wait for
|
||||
*
|
||||
* The process is put to sleep (TASK_INTERRUPTIBLE) until the
|
||||
* @condition evaluates to true or a signal is received.
|
||||
* The @condition is checked each time the waitqueue @wq is woken up.
|
||||
*
|
||||
* It must be called with wq.lock being held. This spinlock is
|
||||
* unlocked while sleeping but @condition testing is done while lock
|
||||
* is held and when this macro exits the lock is held.
|
||||
*
|
||||
* The lock is locked/unlocked using spin_lock()/spin_unlock()
|
||||
* functions which must match the way they are locked/unlocked outside
|
||||
* of this macro.
|
||||
*
|
||||
* wake_up_locked() has to be called after changing any variable that could
|
||||
* change the result of the wait condition.
|
||||
*
|
||||
* The function will return -ERESTARTSYS if it was interrupted by a
|
||||
* signal and 0 if @condition evaluated to true.
|
||||
*/
|
||||
#define wait_event_interruptible_locked(wq, condition) \
|
||||
((condition) \
|
||||
? 0 : __wait_event_interruptible_locked(wq, condition, 0, 0))
|
||||
|
||||
/**
|
||||
* wait_event_interruptible_locked_irq - sleep until a condition gets true
|
||||
* @wq: the waitqueue to wait on
|
||||
* @condition: a C expression for the event to wait for
|
||||
*
|
||||
* The process is put to sleep (TASK_INTERRUPTIBLE) until the
|
||||
* @condition evaluates to true or a signal is received.
|
||||
* The @condition is checked each time the waitqueue @wq is woken up.
|
||||
*
|
||||
* It must be called with wq.lock being held. This spinlock is
|
||||
* unlocked while sleeping but @condition testing is done while lock
|
||||
* is held and when this macro exits the lock is held.
|
||||
*
|
||||
* The lock is locked/unlocked using spin_lock_irq()/spin_unlock_irq()
|
||||
* functions which must match the way they are locked/unlocked outside
|
||||
* of this macro.
|
||||
*
|
||||
* wake_up_locked() has to be called after changing any variable that could
|
||||
* change the result of the wait condition.
|
||||
*
|
||||
* The function will return -ERESTARTSYS if it was interrupted by a
|
||||
* signal and 0 if @condition evaluated to true.
|
||||
*/
|
||||
#define wait_event_interruptible_locked_irq(wq, condition) \
|
||||
((condition) \
|
||||
? 0 : __wait_event_interruptible_locked(wq, condition, 0, 1))
|
||||
|
||||
/**
|
||||
* wait_event_interruptible_exclusive_locked - sleep exclusively until a condition gets true
|
||||
* @wq: the waitqueue to wait on
|
||||
* @condition: a C expression for the event to wait for
|
||||
*
|
||||
* The process is put to sleep (TASK_INTERRUPTIBLE) until the
|
||||
* @condition evaluates to true or a signal is received.
|
||||
* The @condition is checked each time the waitqueue @wq is woken up.
|
||||
*
|
||||
* It must be called with wq.lock being held. This spinlock is
|
||||
* unlocked while sleeping but @condition testing is done while lock
|
||||
* is held and when this macro exits the lock is held.
|
||||
*
|
||||
* The lock is locked/unlocked using spin_lock()/spin_unlock()
|
||||
* functions which must match the way they are locked/unlocked outside
|
||||
* of this macro.
|
||||
*
|
||||
* The process is put on the wait queue with an WQ_FLAG_EXCLUSIVE flag
|
||||
* set thus when other process waits process on the list if this
|
||||
* process is awaken further processes are not considered.
|
||||
*
|
||||
* wake_up_locked() has to be called after changing any variable that could
|
||||
* change the result of the wait condition.
|
||||
*
|
||||
* The function will return -ERESTARTSYS if it was interrupted by a
|
||||
* signal and 0 if @condition evaluated to true.
|
||||
*/
|
||||
#define wait_event_interruptible_exclusive_locked(wq, condition) \
|
||||
((condition) \
|
||||
? 0 : __wait_event_interruptible_locked(wq, condition, 1, 0))
|
||||
|
||||
/**
|
||||
* wait_event_interruptible_exclusive_locked_irq - sleep until a condition gets true
|
||||
* @wq: the waitqueue to wait on
|
||||
* @condition: a C expression for the event to wait for
|
||||
*
|
||||
* The process is put to sleep (TASK_INTERRUPTIBLE) until the
|
||||
* @condition evaluates to true or a signal is received.
|
||||
* The @condition is checked each time the waitqueue @wq is woken up.
|
||||
*
|
||||
* It must be called with wq.lock being held. This spinlock is
|
||||
* unlocked while sleeping but @condition testing is done while lock
|
||||
* is held and when this macro exits the lock is held.
|
||||
*
|
||||
* The lock is locked/unlocked using spin_lock_irq()/spin_unlock_irq()
|
||||
* functions which must match the way they are locked/unlocked outside
|
||||
* of this macro.
|
||||
*
|
||||
* The process is put on the wait queue with an WQ_FLAG_EXCLUSIVE flag
|
||||
* set thus when other process waits process on the list if this
|
||||
* process is awaken further processes are not considered.
|
||||
*
|
||||
* wake_up_locked() has to be called after changing any variable that could
|
||||
* change the result of the wait condition.
|
||||
*
|
||||
* The function will return -ERESTARTSYS if it was interrupted by a
|
||||
* signal and 0 if @condition evaluated to true.
|
||||
*/
|
||||
#define wait_event_interruptible_exclusive_locked_irq(wq, condition) \
|
||||
((condition) \
|
||||
? 0 : __wait_event_interruptible_locked(wq, condition, 1, 1))
|
||||
|
||||
|
||||
|
||||
#define __wait_event_killable(wq, condition, ret) \
|
||||
do { \
|
||||
DEFINE_WAIT(__wait); \
|
||||
|
@ -3950,6 +3950,7 @@ void __wake_up_locked(wait_queue_head_t *q, unsigned int mode)
|
||||
{
|
||||
__wake_up_common(q, mode, 1, 0, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__wake_up_locked);
|
||||
|
||||
void __wake_up_locked_key(wait_queue_head_t *q, unsigned int mode, void *key)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user