
From: Ingo Molnar <mingo@elte.hu>

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 <mingo@elte.hu>
Tested-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 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;				\
_
