Skip to contentSkip to conversation

add wait_event() to <linux/completion.h>

PATCH New David Brownell 1 participant 1 message Dec 12, 2002

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 add wait_event() to <linux/completion.h>

Folk periodically talk about evolving the "struct completion" support ... here's one:

int wait_event (struct completion *x, signed long timeout_jiffies);

Returns zero if the event happened, nonzero if it timed out. An example timeout action might be to cancel a request then use wait_for_completion(x) to synchronize with that.

It's been behaving for me so far. Questions from me:

- Is this appropriate to merge as-is? The tradeoff I'm thinking of is code duplication; this patch avoids it ("smaller==better" rule-of-thumb) but maybe someone has real tuning knowledge, or a "standard" lk policy applies. Or there might be bugs or api transgressions.

- One routine was unavailable to modules; now exported. That seemed to just be an oversight.

This doesn't add an "interruptible wait" api mode, which I'd expect some others might find a use for. This patch will let us clean up some dubious code in usbcore which is more or less trying to do a wait_event().

Thanks in advance for any comments.

- Dave

include/linux/completion.h renamed from include/linux-dist/completion.h +1 -0
@@ -28,6 +28,7 @@
 }
 
 extern void FASTCALL(wait_for_completion(struct completion *));
+extern int FASTCALL(wait_timeout(struct completion *, signed long jiffies));
 extern void FASTCALL(complete(struct completion *));
 extern void FASTCALL(complete_all(struct completion *));
 
kernel/ksyms.c renamed from kernel-dist/ksyms.c +2 -0
@@ -404,7 +404,9 @@ EXPORT_SYMBOL(autoremove_wake_function);
 
 /* completion handling */
 EXPORT_SYMBOL(wait_for_completion);
+EXPORT_SYMBOL(wait_timeout);
 EXPORT_SYMBOL(complete);
+EXPORT_SYMBOL(complete_all);
 
 /* The notion of irq probe/assignment is foreign to S/390 */
 
kernel/sched.c renamed from kernel-dist/sched.c +12 -1
@@ -1204,6 +1204,11 @@ void complete_all(struct completion *x)
 
 void wait_for_completion(struct completion *x)
 {
+	wait_timeout (x, MAX_SCHEDULE_TIMEOUT);
+}
+
+int wait_timeout(struct completion *x, signed long timeout_jiffies)
+{
 	might_sleep();
 	spin_lock_irq(&x->wait.lock);
 	if (!x->done) {
@@ -1214,13 +1219,19 @@ void wait_for_completion(struct completi
 		do {
 			__set_current_state(TASK_UNINTERRUPTIBLE);
 			spin_unlock_irq(&x->wait.lock);
-			schedule();
+			timeout_jiffies = schedule_timeout(timeout_jiffies);
+			if (timeout_jiffies == 0) {
+				__remove_wait_queue(&x->wait, &wait);
+				/* caller should wait again */
+				return 1;
+			}
 			spin_lock_irq(&x->wait.lock);
 		} while (!x->done);
 		__remove_wait_queue(&x->wait, &wait);
 	}
 	x->done--;
 	spin_unlock_irq(&x->wait.lock);
+	return 0;
 }
 
 #define	SLEEP_ON_VAR				\