<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">diff -urN linux.orig/include/linux/wait.h linux.diff/include/linux/wait.h
--- linux.orig/include/linux/wait.h	Tue Jan 22 15:14:48 2002
+++ linux.diff/include/linux/wait.h	Tue Jan 22 15:19:39 2002
@@ -28,17 +28,20 @@
 #define WAITQUEUE_DEBUG 0
 #endif
 
+typedef struct __wait_queue wait_queue_t;
+typedef void (*wait_queue_func_t)(wait_queue_t *wait);
+
 struct __wait_queue {
 	unsigned int flags;
 #define WQ_FLAG_EXCLUSIVE	0x01
 	struct task_struct * task;
 	struct list_head task_list;
+	wait_queue_func_t func;
 #if WAITQUEUE_DEBUG
 	long __magic;
 	long __waker;
 #endif
 };
-typedef struct __wait_queue wait_queue_t;
 
 /*
  * 'dual' spinlock architecture. Can be switched between spinlock_t and
@@ -137,6 +140,7 @@
 #endif
 
 #define __WAITQUEUE_INITIALIZER(name, tsk) {				\
+	func:		NULL,						\
 	task:		tsk,						\
 	task_list:	{ NULL, NULL },					\
 			 __WAITQUEUE_DEBUG_INIT(name)}
@@ -174,6 +178,22 @@
 #endif
 	q-&gt;flags = 0;
 	q-&gt;task = p;
+	q-&gt;func = NULL;
+#if WAITQUEUE_DEBUG
+	q-&gt;__magic = (long)&amp;q-&gt;__magic;
+#endif
+}
+
+static inline void init_waitqueue_func_entry(wait_queue_t *q,
+					wait_queue_func_t func)
+{
+#if WAITQUEUE_DEBUG
+	if (!q || !p)
+		WQ_BUG();
+#endif
+	q-&gt;flags = 0;
+	q-&gt;task = NULL;
+	q-&gt;func = func;
 #if WAITQUEUE_DEBUG
 	q-&gt;__magic = (long)&amp;q-&gt;__magic;
 #endif
@@ -231,6 +251,22 @@
 	list_del(&amp;old-&gt;task_list);
 }
 
+#define add_wait_queue_cond(q, wait, cond) \
+	({							\
+		unsigned long flags;				\
+		int _raced = 0;					\
+		wq_write_lock_irqsave(&amp;(q)-&gt;lock, flags);	\
+		(wait)-&gt;flags = 0;				\
+		__add_wait_queue((q), (wait));			\
+		rmb();						\
+		if (!(cond)) {					\
+			_raced = 1;				\
+			__remove_wait_queue((q), (wait));	\
+		}						\
+		wq_write_unlock_irqrestore(&amp;(q)-&gt;lock, flags);	\
+		_raced;						\
+	})
+
 #endif /* __KERNEL__ */
 
 #endif
diff -urN linux.orig/kernel/sched.c linux.diff/kernel/sched.c
--- linux.orig/kernel/sched.c	Fri Jan 11 15:29:58 2002
+++ linux.diff/kernel/sched.c	Fri Jan 11 18:42:53 2002
@@ -730,33 +730,44 @@
 }
 
 /*
- * The core wakeup function.  Non-exclusive wakeups (nr_exclusive == 0) just wake everything
- * up.  If it's an exclusive wakeup (nr_exclusive == small +ve number) then we wake all the
- * non-exclusive tasks and one exclusive task.
+ * The core wakeup function.  Non-exclusive wakeups (nr_exclusive == 0) just
+ * wake everything up.  If it's an exclusive wakeup (nr_exclusive == small
+ * +ve number) then we wake all the non-exclusive tasks and one exclusive task.
  *
  * There are circumstances in which we can try to wake a task which has already
- * started to run but is not in state TASK_RUNNING.  try_to_wake_up() returns zero
- * in this (rare) case, and we handle it by contonuing to scan the queue.
+ * started to run but is not in state TASK_RUNNING.  try_to_wake_up() returns
+ * zero in this (rare) case, and we handle it by contonuing to scan the queue.
  */
 static inline void __wake_up_common (wait_queue_head_t *q, unsigned int mode,
 			 	     int nr_exclusive, const int sync)
 {
-	struct list_head *tmp;
+	struct list_head *tmp, *next;
 	struct task_struct *p;
 
 	CHECK_MAGIC_WQHEAD(q);
 	WQ_CHECK_LIST_HEAD(&amp;q-&gt;task_list);
 	
-	list_for_each(tmp,&amp;q-&gt;task_list) {
+	list_for_each_safe(tmp, next, &amp;q-&gt;task_list) {
 		unsigned int state;
-                wait_queue_t *curr = list_entry(tmp, wait_queue_t, task_list);
+		wait_queue_t *curr = list_entry(tmp, wait_queue_t, task_list);
+		wait_queue_func_t func;
 
 		CHECK_MAGIC(curr-&gt;__magic);
+		func = curr-&gt;func;
+		if (func) {
+			unsigned flags = curr-&gt;flags;
+			func(curr);
+			if ((flags &amp; WQ_FLAG_EXCLUSIVE) &amp;&amp; !--nr_exclusive)
+				break;
+			continue;
+		}
 		p = curr-&gt;task;
 		state = p-&gt;state;
 		if (state &amp; mode) {
 			WQ_NOTE_WAKER(curr);
-			if (try_to_wake_up(p, sync) &amp;&amp; (curr-&gt;flags&amp;WQ_FLAG_EXCLUSIVE) &amp;&amp; !--nr_exclusive)
+			if (try_to_wake_up(p, sync) &amp;&amp;
+			    (curr-&gt;flags &amp; WQ_FLAG_EXCLUSIVE) &amp;&amp;
+			    !--nr_exclusive)
 				break;
 		}
 	}
</pre></body></html>