diff options
| -rw-r--r-- | include/linux/wait.h | 31 | ||||
| -rw-r--r-- | kernel/sched/wait.c | 39 | 
2 files changed, 49 insertions, 21 deletions
diff --git a/include/linux/wait.h b/include/linux/wait.h index aacb1282d19a..db076ca7f11d 100644 --- a/include/linux/wait.h +++ b/include/linux/wait.h @@ -620,30 +620,19 @@ do {									\  	__ret;								\  }) +extern int do_wait_intr(wait_queue_head_t *, wait_queue_t *); +extern int do_wait_intr_irq(wait_queue_head_t *, wait_queue_t *); -#define __wait_event_interruptible_locked(wq, condition, exclusive, irq) \ +#define __wait_event_interruptible_locked(wq, condition, exclusive, fn) \  ({									\ -	int __ret = 0;							\ +	int __ret;							\  	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;				\ +		__ret = fn(&(wq), &__wait);				\ +		if (__ret)						\  			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);				\ @@ -676,7 +665,7 @@ do {									\   */  #define wait_event_interruptible_locked(wq, condition)			\  	((condition)							\ -	 ? 0 : __wait_event_interruptible_locked(wq, condition, 0, 0)) +	 ? 0 : __wait_event_interruptible_locked(wq, condition, 0, do_wait_intr))  /**   * wait_event_interruptible_locked_irq - sleep until a condition gets true @@ -703,7 +692,7 @@ do {									\   */  #define wait_event_interruptible_locked_irq(wq, condition)		\  	((condition)							\ -	 ? 0 : __wait_event_interruptible_locked(wq, condition, 0, 1)) +	 ? 0 : __wait_event_interruptible_locked(wq, condition, 0, do_wait_intr_irq))  /**   * wait_event_interruptible_exclusive_locked - sleep exclusively until a condition gets true @@ -734,7 +723,7 @@ do {									\   */  #define wait_event_interruptible_exclusive_locked(wq, condition)	\  	((condition)							\ -	 ? 0 : __wait_event_interruptible_locked(wq, condition, 1, 0)) +	 ? 0 : __wait_event_interruptible_locked(wq, condition, 1, do_wait_intr))  /**   * wait_event_interruptible_exclusive_locked_irq - sleep until a condition gets true @@ -765,7 +754,7 @@ do {									\   */  #define wait_event_interruptible_exclusive_locked_irq(wq, condition)	\  	((condition)							\ -	 ? 0 : __wait_event_interruptible_locked(wq, condition, 1, 1)) +	 ? 0 : __wait_event_interruptible_locked(wq, condition, 1, do_wait_intr_irq))  #define __wait_event_killable(wq, condition)				\ diff --git a/kernel/sched/wait.c b/kernel/sched/wait.c index 4d2ea6f25568..b8c84c6dee64 100644 --- a/kernel/sched/wait.c +++ b/kernel/sched/wait.c @@ -242,6 +242,45 @@ long prepare_to_wait_event(wait_queue_head_t *q, wait_queue_t *wait, int state)  }  EXPORT_SYMBOL(prepare_to_wait_event); +/* + * Note! These two wait functions are entered with the + * wait-queue lock held (and interrupts off in the _irq + * case), so there is no race with testing the wakeup + * condition in the caller before they add the wait + * entry to the wake queue. + */ +int do_wait_intr(wait_queue_head_t *wq, wait_queue_t *wait) +{ +	if (likely(list_empty(&wait->task_list))) +		__add_wait_queue_tail(wq, wait); + +	set_current_state(TASK_INTERRUPTIBLE); +	if (signal_pending(current)) +		return -ERESTARTSYS; + +	spin_unlock(&wq->lock); +	schedule(); +	spin_lock(&wq->lock); +	return 0; +} +EXPORT_SYMBOL(do_wait_intr); + +int do_wait_intr_irq(wait_queue_head_t *wq, wait_queue_t *wait) +{ +	if (likely(list_empty(&wait->task_list))) +		__add_wait_queue_tail(wq, wait); + +	set_current_state(TASK_INTERRUPTIBLE); +	if (signal_pending(current)) +		return -ERESTARTSYS; + +	spin_unlock_irq(&wq->lock); +	schedule(); +	spin_lock_irq(&wq->lock); +	return 0; +} +EXPORT_SYMBOL(do_wait_intr_irq); +  /**   * finish_wait - clean up after waiting in a queue   * @q: waitqueue waited on  | 
