--- /usr/src/sys/kern/kern_condvar.c	Mon Dec 11 01:29:19 2006
+++ kern_condvar.c	Mon Dec 11 01:32:37 2006
@@ -149,7 +149,8 @@
 	DROP_GIANT();
 	mtx_unlock(mp);
 
-	sleepq_add(cvp, &mp->mtx_object, cvp->cv_description, SLEEPQ_CONDVAR);
+	sleepq_add(cvp, &mp->mtx_object, cvp->cv_description, SLEEPQ_CONDVAR,
+	    SQ_EXCLUSIVE_QUEUE);
 	sleepq_wait(cvp);
 
 	PICKUP_GIANT();
@@ -197,7 +198,7 @@
 	mtx_unlock(mp);
 
 	sleepq_add(cvp, &mp->mtx_object, cvp->cv_description, SLEEPQ_CONDVAR |
-	    SLEEPQ_INTERRUPTIBLE);
+	    SLEEPQ_INTERRUPTIBLE, SQ_EXCLUSIVE_QUEUE);
 	rval = sleepq_wait_sig(cvp);
 
 #ifdef KTRACE
@@ -250,7 +251,8 @@
 	DROP_GIANT();
 	mtx_unlock(mp);
 
-	sleepq_add(cvp, &mp->mtx_object, cvp->cv_description, SLEEPQ_CONDVAR);
+	sleepq_add(cvp, &mp->mtx_object, cvp->cv_description, SLEEPQ_CONDVAR,
+	    SQ_EXCLUSIVE_QUEUE);
 	sleepq_set_timeout(cvp, timo);
 	rval = sleepq_timedwait(cvp);
 
@@ -308,7 +310,7 @@
 	mtx_unlock(mp);
 
 	sleepq_add(cvp, &mp->mtx_object, cvp->cv_description, SLEEPQ_CONDVAR |
-	    SLEEPQ_INTERRUPTIBLE);
+	    SLEEPQ_INTERRUPTIBLE, SQ_EXCLUSIVE_QUEUE);
 	sleepq_set_timeout(cvp, timo);
 	rval = sleepq_timedwait_sig(cvp);
 
@@ -337,7 +339,7 @@
 	sleepq_lock(cvp);
 	if (cvp->cv_waiters > 0) {
 		cvp->cv_waiters--;
-		sleepq_signal(cvp, SLEEPQ_CONDVAR, -1);
+		sleepq_signal(cvp, SLEEPQ_CONDVAR, -1, SQ_EXCLUSIVE_QUEUE);
 	} else
 		sleepq_release(cvp);
 }
@@ -353,7 +355,7 @@
 	sleepq_lock(cvp);
 	if (cvp->cv_waiters > 0) {
 		cvp->cv_waiters = 0;
-		sleepq_broadcast(cvp, SLEEPQ_CONDVAR, pri);
+		sleepq_broadcast(cvp, SLEEPQ_CONDVAR, pri, SQ_EXCLUSIVE_QUEUE);
 	} else
 		sleepq_release(cvp);
 }
--- /usr/src/sys/kern/kern_synch.c	Mon Dec 11 01:29:19 2006
+++ kern_synch.c	Mon Dec 11 01:34:12 2006
@@ -189,7 +189,7 @@
 	 * return from cursig().
 	 */
 	sleepq_add(ident, ident == &lbolt ? NULL : &mtx->mtx_object, wmesg,
-	    flags);
+	    flags, SQ_EXCLUSIVE_QUEUE);
 	if (timo)
 		sleepq_set_timeout(ident, timo);
 
@@ -267,7 +267,8 @@
 	/*
 	 * We put ourselves on the sleep queue and start our timeout.
 	 */
-	sleepq_add(ident, &mtx->mtx_object, wmesg, SLEEPQ_MSLEEP);
+	sleepq_add(ident, &mtx->mtx_object, wmesg, SLEEPQ_MSLEEP,
+	    SQ_EXCLUSIVE_QUEUE);
 	if (timo)
 		sleepq_set_timeout(ident, timo);
 
@@ -316,7 +317,7 @@
 {
 
 	sleepq_lock(ident);
-	sleepq_broadcast(ident, SLEEPQ_MSLEEP, -1);
+	sleepq_broadcast(ident, SLEEPQ_MSLEEP, -1, SQ_EXCLUSIVE_QUEUE);
 }
 
 /*
@@ -330,7 +331,7 @@
 {
 
 	sleepq_lock(ident);
-	sleepq_signal(ident, SLEEPQ_MSLEEP, -1);
+	sleepq_signal(ident, SLEEPQ_MSLEEP, -1, SQ_EXCLUSIVE_QUEUE);
 }
 
 /*
--- /usr/src/sys/kern/subr_sleepqueue.c	Mon Dec 11 01:29:19 2006
+++ subr_sleepqueue.c	Mon Dec 11 01:53:49 2006
@@ -114,7 +114,7 @@
  *  c - sleep queue chain lock
  */
 struct sleepqueue {
-	TAILQ_HEAD(, thread) sq_blocked;	/* (c) Blocked threads. */
+	TAILQ_HEAD(, thread) sq_blocked[2];	/* (c) Blocked threads. */
 	LIST_ENTRY(sleepqueue) sq_hash;		/* (c) Chain and free list. */
 	LIST_HEAD(, sleepqueue) sq_free;	/* (c) Free queues. */
 	void	*sq_wchan;			/* (c) Wait channel. */
@@ -148,10 +148,13 @@
 /*
  * Prototypes for non-exported routines.
  */
+static int	sleepq_catch_signals(void *wchan);
+static int	sleepq_check_signals(void);
 static int	sleepq_check_timeout(void);
+static void	sleepq_resume_thread(struct sleepqueue *sq, struct thread *td,
+		    int pri);
 static void	sleepq_switch(void *wchan);
 static void	sleepq_timeout(void *arg);
-static void	sleepq_resume_thread(struct sleepqueue *sq, struct thread *td, int pri);
 
 /*
  * Early initialization of sleep queues that is called from the sleepinit()
@@ -194,7 +197,8 @@
 	struct sleepqueue *sq;
 
 	sq = malloc(sizeof(struct sleepqueue), M_SLEEPQUEUE, M_WAITOK | M_ZERO);
-	TAILQ_INIT(&sq->sq_blocked);
+	TAILQ_INIT(&sq->sq_blocked[SQ_EXCLUSIVE_QUEUE]);
+	TAILQ_INIT(&sq->sq_blocked[SQ_SHARED_QUEUE]);
 	LIST_INIT(&sq->sq_free);
 	return (sq);
 }
@@ -207,7 +211,8 @@
 {
 
 	MPASS(sq != NULL);
-	MPASS(TAILQ_EMPTY(&sq->sq_blocked));
+	MPASS(TAILQ_EMPTY(&sq->sq_blocked[SQ_EXCLUSIVE_QUEUE]));
+	MPASS(TAILQ_EMPTY(&sq->sq_blocked[SQ_SHARED_QUEUE]));
 	free(sq, M_SLEEPQUEUE);
 }
 
@@ -262,7 +267,8 @@
  * woken up.
  */
 void
-sleepq_add(void *wchan, struct lock_object *lock, const char *wmesg, int flags)
+sleepq_add(void *wchan, struct lock_object *lock, const char *wmesg, int flags,
+    int queue)
 {
 	struct sleepqueue_chain *sc;
 	struct sleepqueue *sq;
@@ -273,6 +279,7 @@
 	mtx_assert(&sc->sc_lock, MA_OWNED);
 	MPASS(td->td_sleepqueue != NULL);
 	MPASS(wchan != NULL);
+	MPASS(queue == SQ_EXCLUSIVE_QUEUE || queue == SQ_SHARED_QUEUE);
 
 	/* If this thread is not allowed to sleep, die a horrible death. */
 	KASSERT(!(td->td_pflags & TDP_NOSLEEPING),
@@ -297,8 +304,10 @@
 #endif
 		sq = td->td_sleepqueue;
 		LIST_INSERT_HEAD(&sc->sc_queues, sq, sq_hash);
-		KASSERT(TAILQ_EMPTY(&sq->sq_blocked),
-		    ("thread's sleep queue has a non-empty queue"));
+		KASSERT(TAILQ_EMPTY(&sq->sq_blocked[SQ_EXCLUSIVE_QUEUE]),
+		    ("thread's sleep queue has an exclusive non-empty queue"));
+		KASSERT(TAILQ_EMPTY(&sq->sq_blocked[SQ_SHARED_QUEUE]),
+		    ("thread's sleep queue has a shared non-empty queue"));
 		KASSERT(LIST_EMPTY(&sq->sq_free),
 		    ("thread's sleep queue has a non-empty free list"));
 		KASSERT(sq->sq_wchan == NULL, ("stale sq_wchan pointer"));
@@ -313,9 +322,10 @@
 		MPASS((flags & SLEEPQ_TYPE) == sq->sq_type);
 		LIST_INSERT_HEAD(&sq->sq_free, td->td_sleepqueue, sq_hash);
 	}
-	TAILQ_INSERT_TAIL(&sq->sq_blocked, td, td_slpq);
+	TAILQ_INSERT_TAIL(&sq->sq_blocked[queue], td, td_slpq);
 	td->td_sleepqueue = NULL;
 	mtx_lock_spin(&sched_lock);
+	td->td_sqqueue = queue;
 	td->td_wchan = wchan;
 	td->td_wmesg = wmesg;
 	if (flags & SLEEPQ_INTERRUPTIBLE) {
@@ -606,12 +616,14 @@
 	MPASS(td != NULL);
 	MPASS(sq->sq_wchan != NULL);
 	MPASS(td->td_wchan == sq->sq_wchan);
+	MPASS(td->td_sqqueue == SQ_EXCLUSIVE_QUEUE || td->td_sqqueue ==
+	    SQ_SHARED_QUEUE);
 	sc = SC_LOOKUP(sq->sq_wchan);
 	mtx_assert(&sc->sc_lock, MA_OWNED);
 	mtx_assert(&sched_lock, MA_OWNED);
 
 	/* Remove the thread from the queue. */
-	TAILQ_REMOVE(&sq->sq_blocked, td, td_slpq);
+	TAILQ_REMOVE(&sq->sq_blocked[td->sqqueue], td, td_slpq);
 
 	/*
 	 * Get a sleep queue for this thread.  If this is the last waiter,
@@ -656,13 +668,14 @@
  * Find the highest priority thread sleeping on a wait channel and resume it.
  */
 void
-sleepq_signal(void *wchan, int flags, int pri)
+sleepq_signal(void *wchan, int flags, int pri, int queue)
 {
 	struct sleepqueue *sq;
 	struct thread *td, *besttd;
 
 	CTR2(KTR_PROC, "sleepq_signal(%p, %d)", wchan, flags);
 	KASSERT(wchan != NULL, ("%s: invalid NULL wait channel", __func__));
+	MPASS(queue == SQ_EXCLUSIVE_QUEUE || queue == SQ_SHARED_QUEUE);
 	sq = sleepq_lookup(wchan);
 	if (sq == NULL) {
 		sleepq_release(wchan);
@@ -678,7 +691,7 @@
 	 * the tail of sleep queues.
 	 */
 	besttd = NULL;
-	TAILQ_FOREACH(td, &sq->sq_blocked, td_slpq) {
+	TAILQ_FOREACH(td, &sq->sq_blocked[queue], td_slpq) {
 		if (besttd == NULL || td->td_priority < besttd->td_priority)
 			besttd = td;
 	}
@@ -693,12 +706,13 @@
  * Resume all threads sleeping on a specified wait channel.
  */
 void
-sleepq_broadcast(void *wchan, int flags, int pri)
+sleepq_broadcast(void *wchan, int flags, int pri, int queue)
 {
 	struct sleepqueue *sq;
 
 	CTR2(KTR_PROC, "sleepq_broadcast(%p, %d)", wchan, flags);
 	KASSERT(wchan != NULL, ("%s: invalid NULL wait channel", __func__));
+	MPASS(queue == SQ_EXCLUSIVE_QUEUE || queue == SQ_SHARED_QUEUE);
 	sq = sleepq_lookup(wchan);
 	if (sq == NULL) {
 		sleepq_release(wchan);
@@ -709,8 +723,9 @@
 
 	/* Resume all blocked threads on the sleep queue. */
 	mtx_lock_spin(&sched_lock);
-	while (!TAILQ_EMPTY(&sq->sq_blocked))
-		sleepq_resume_thread(sq, TAILQ_FIRST(&sq->sq_blocked), pri);
+	while (!TAILQ_EMPTY(&sq->sq_blocked[queue]))
+		sleepq_resume_thread(sq, TAILQ_FIRST(&sq->sq_blocked[queue]),
+		    pri);
 	mtx_unlock_spin(&sched_lock);
 	sleepq_release(wchan);
 }
@@ -901,15 +916,27 @@
 	}
 #endif
 	db_printf("Blocked threads:\n");
-	if (TAILQ_EMPTY(&sq->sq_blocked))
+	db_printf("\nExclusive queue:\n");
+	if (TAILQ_EMPTY(&sq->sq_blocked[SQ_EXCLUSIVE_QUEUE]))
 		db_printf("\tempty\n");
 	else
-		TAILQ_FOREACH(td, &sq->sq_blocked, td_slpq) {
+		TAILQ_FOREACH(td, &sq->sq_blocked[SQ_EXCLUSIVE_QUEUE],
+		    td_slpq) {
 			db_printf("\t%p (tid %d, pid %d, \"%s\")\n", td,
 			    td->td_tid, td->td_proc->p_pid,
 			    td->td_name[0] != '\0' ? td->td_name :
 			    td->td_proc->p_comm);
-		}	
+		}
+	db_printf("\nShared queue:\n");
+	if (TAILQ_EMPTY(&sq->sq_blocked[SQ_SHARED_QUEUE]))
+		db_printf("\tempty\n");
+	else
+		TAILQ_FOREACH(td, &sq->sq_blocked[SQ_SHARED_QUEUE], td_slpq) {
+			db_printf("\t%p (tid %d, pid %d, \"%s\")\n", td,
+			    td->td_tid, td->td_proc->p_pid,
+			    td->td_name[0] != '\0' ? td->td_name :
+			    td->td_proc->p_comm);
+		}
 }
 
 /* Alias 'show sleepqueue' to 'show sleepq'. */
--- /usr/src/sys/sys/proc.h	Mon Dec 11 01:29:19 2006
+++ proc.h	Mon Dec 11 01:55:30 2006
@@ -235,6 +235,7 @@
 	int		td_inhibitors;	/* (j) Why can not run. */
 	int		td_pflags;	/* (k) Private thread (TDP_*) flags. */
 	int		td_dupfd;	/* (k) Ret value from fdopen. XXX */
+	int		td_sqqueue;	/* (j) Sleepqueue queue blocked on. */
 	void		*td_wchan;	/* (j) Sleep address. */
 	const char	*td_wmesg;	/* (j) Reason for sleep. */
 	u_char		td_lastcpu;	/* (j) Last cpu we were on. */
--- /usr/src/sys/sys/sleepqueue.h	Mon Dec 11 01:29:19 2006
+++ sleepqueue.h	Mon Dec 11 02:01:06 2006
@@ -86,21 +86,26 @@
 #define	SLEEPQ_CONDVAR		0x01		/* Used for a cv. */
 #define	SLEEPQ_INTERRUPTIBLE	0x100		/* Sleep is interruptible. */
 
+/* Handy sleep queues delivery constants. */
+#define	SQ_EXCLUSIVE_QUEUE	0
+#define	SQ_SHARED_QUEUE		1
+
 void	init_sleepqueues(void);
 void	sleepq_abort(struct thread *td, int intrval);
-void	sleepq_add(void *, struct lock_object *, const char *, int);
+void	sleepq_add(void *wchan, struct lock_object *lock, const char *wmesg,
+	    int flags, int queue);
 struct sleepqueue *sleepq_alloc(void);
-void	sleepq_broadcast(void *, int, int);
-void	sleepq_free(struct sleepqueue *);
-void	sleepq_lock(void *);
-struct sleepqueue *sleepq_lookup(void *);
-void	sleepq_release(void *);
-void	sleepq_remove(struct thread *, void *);
-void	sleepq_signal(void *, int, int);
+void	sleepq_broadcast(void *wchan, int flags, int pri, int queue);
+void	sleepq_free(struct sleepqueue *sq);
+void	sleepq_lock(void *wchan);
+struct sleepqueue *sleepq_lookup(void *wchan);
+void	sleepq_release(void *wchan);
+void	sleepq_remove(struct thread *td, void *wchan);
+void	sleepq_signal(void *wchan, int flags, int pri, int queue);
 void	sleepq_set_timeout(void *wchan, int timo);
 int	sleepq_timedwait(void *wchan);
 int	sleepq_timedwait_sig(void *wchan);
-void	sleepq_wait(void *);
+void	sleepq_wait(void *wchan);
 int	sleepq_wait_sig(void *wchan);
 
 #endif	/* _KERNEL */
