From: Ingo Molnar Adds 3 new completion API calls, which are a straightforward extension of the current APIs: int wait_for_completion_interruptible(struct completion *x); unsigned long wait_for_completion_timeout(struct completion *x, unsigned long timeout); unsigned long wait_for_completion_interruptible_timeout( struct completion *x, unsigned long timeout); This enables the conversion of more semaphore-using code to completions. There is code that cannot be converted right now (and is forced to use semaphores) because these primitives are missing. Thomas Gleixner has a bunch of patches to make use of them. Signed-off-by: Ingo Molnar Tested-by: Thomas Gleixner Signed-off-by: Andrew Morton --- 25-akpm/include/linux/completion.h | 6 ++ 25-akpm/kernel/sched.c | 95 +++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+) diff -puN include/linux/completion.h~completion-api-additions include/linux/completion.h --- 25/include/linux/completion.h~completion-api-additions Wed Jan 19 15:32:31 2005 +++ 25-akpm/include/linux/completion.h Wed Jan 19 15:32:31 2005 @@ -28,6 +28,12 @@ static inline void init_completion(struc } extern void FASTCALL(wait_for_completion(struct completion *)); +extern int FASTCALL(wait_for_completion_interruptible(struct completion *x)); +extern unsigned long FASTCALL(wait_for_completion_timeout(struct completion *x, + unsigned long timeout)); +extern unsigned long FASTCALL(wait_for_completion_interruptible_timeout( + struct completion *x, unsigned long timeout)); + extern void FASTCALL(complete(struct completion *)); extern void FASTCALL(complete_all(struct completion *)); diff -puN kernel/sched.c~completion-api-additions kernel/sched.c --- 25/kernel/sched.c~completion-api-additions Wed Jan 19 15:32:31 2005 +++ 25-akpm/kernel/sched.c Wed Jan 19 15:32:31 2005 @@ -3005,6 +3005,101 @@ void fastcall __sched wait_for_completio } EXPORT_SYMBOL(wait_for_completion); +unsigned long fastcall __sched +wait_for_completion_timeout(struct completion *x, unsigned long timeout) +{ + might_sleep(); + + spin_lock_irq(&x->wait.lock); + if (!x->done) { + DECLARE_WAITQUEUE(wait, current); + + wait.flags |= WQ_FLAG_EXCLUSIVE; + __add_wait_queue_tail(&x->wait, &wait); + do { + __set_current_state(TASK_UNINTERRUPTIBLE); + spin_unlock_irq(&x->wait.lock); + timeout = schedule_timeout(timeout); + if (!timeout) + goto out; + spin_lock_irq(&x->wait.lock); + } while (!x->done); + __remove_wait_queue(&x->wait, &wait); + } + x->done--; + spin_unlock_irq(&x->wait.lock); +out: + return timeout; +} +EXPORT_SYMBOL(wait_for_completion_timeout); + +int fastcall __sched wait_for_completion_interruptible(struct completion *x) +{ + int ret = 0; + + might_sleep(); + + spin_lock_irq(&x->wait.lock); + if (!x->done) { + DECLARE_WAITQUEUE(wait, current); + + wait.flags |= WQ_FLAG_EXCLUSIVE; + __add_wait_queue_tail(&x->wait, &wait); + do { + if (signal_pending(current)) { + ret = -ERESTARTSYS; + goto out; + } + __set_current_state(TASK_INTERRUPTIBLE); + spin_unlock_irq(&x->wait.lock); + schedule(); + spin_lock_irq(&x->wait.lock); + } while (!x->done); + __remove_wait_queue(&x->wait, &wait); + } + x->done--; +out: + spin_unlock_irq(&x->wait.lock); + + return ret; +} +EXPORT_SYMBOL(wait_for_completion_interruptible); + +unsigned long fastcall __sched +wait_for_completion_interruptible_timeout(struct completion *x, + unsigned long timeout) +{ + might_sleep(); + + spin_lock_irq(&x->wait.lock); + if (!x->done) { + DECLARE_WAITQUEUE(wait, current); + + wait.flags |= WQ_FLAG_EXCLUSIVE; + __add_wait_queue_tail(&x->wait, &wait); + do { + if (signal_pending(current)) { + timeout = -ERESTARTSYS; + goto out_unlock; + } + __set_current_state(TASK_INTERRUPTIBLE); + spin_unlock_irq(&x->wait.lock); + timeout = schedule_timeout(timeout); + if (!timeout) + goto out; + spin_lock_irq(&x->wait.lock); + } while (!x->done); + __remove_wait_queue(&x->wait, &wait); + } + x->done--; +out_unlock: + spin_unlock_irq(&x->wait.lock); +out: + return timeout; +} +EXPORT_SYMBOL(wait_for_completion_interruptible_timeout); + + #define SLEEP_ON_VAR \ unsigned long flags; \ wait_queue_t wait; \ _