--- //depot/vendor/freebsd_7/src/sys/kern/kern_synch.c 2007/05/31 19:36:45 +++ //depot/yahoo/ybsd_7/src/sys/kern/kern_synch.c 2007/06/06 10:51:41 @@ -365,6 +366,18 @@ } /* + * Returns true if it was able to find an in-memory thread to wake up. + */ +int +wakeup_just_one(ident) + register void *ident; +{ + + sleepq_lock(ident); + return (sleepq_signal(ident, SLEEPQ_SLEEP | SLEEPQ_JUST_ONE, -1, 0)); +} + +/* * The machine independent parts of context switching. */ void --- //depot/vendor/freebsd_7/src/sys/kern/subr_sleepqueue.c 2007/05/18 00:35:26 +++ //depot/yahoo/ybsd_7/src/sys/kern/subr_sleepqueue.c 2007/06/06 09:38:19 @@ -704,7 +705,7 @@ /* * Find the highest priority thread sleeping on a wait channel and resume it. */ -void +int sleepq_signal(void *wchan, int flags, int pri, int queue) { struct sleepqueue *sq; @@ -716,11 +717,34 @@ sq = sleepq_lookup(wchan); if (sq == NULL) { sleepq_release(wchan); - return; + return (0); } KASSERT(sq->sq_type == (flags & SLEEPQ_TYPE), ("%s: mismatch between sleep/wakeup and cv_*", __func__)); + if (flags & SLEEPQ_JUST_ONE) { + /* + * Find the thread that has been sleeping the shortest + * amount of time and that is not swapped out. We hold + * sched_lock during this whole traversal to make sure the + * thread we pick doesn't get swapped out while we are + * picking it. + */ + mtx_lock_spin(&sched_lock); + besttd = TAILQ_LAST(&sq->sq_blocked[queue], threadqueue); + TAILQ_FOREACH_REVERSE(td, &sq->sq_blocked[queue], threadqueue, td_slpq) { + if (td->td_proc->p_sflag & PS_INMEM) { + besttd = td; + break; + } + } + if (besttd != NULL) + sleepq_resume_thread(sq, besttd, pri); + mtx_unlock_spin(&sched_lock); + sleepq_release(wchan); + return (besttd != NULL); + } + /* * Find the highest priority thread on the queue. If there is a * tie, use the thread that first appears in the queue as it has @@ -737,6 +761,7 @@ sleepq_resume_thread(sq, besttd, pri); mtx_unlock_spin(&sched_lock); sleepq_release(wchan); + return (1); } /* --- //depot/vendor/freebsd_7/src/sys/kern/uipc_socket.c 2007/05/31 19:36:45 +++ //depot/yahoo/ybsd_7/src/sys/kern/uipc_socket.c 2007/06/06 14:56:59 @@ -2843,8 +2844,9 @@ head->so_qlen++; so->so_qstate |= SQ_COMP; ACCEPT_UNLOCK(); - sorwakeup(head); - wakeup_one(&head->so_timeo); + if (!wakeup_just_one(&head->so_timeo)) { + sorwakeup(head); + } } else { ACCEPT_UNLOCK(); so->so_upcall = --- //depot/vendor/freebsd_7/src/sys/sys/sleepqueue.h 2007/03/31 17:35:54 +++ //depot/yahoo/ybsd_7/src/sys/sys/sleepqueue.h 2007/06/06 09:38:19 @@ -88,6 +89,7 @@ #define SLEEPQ_PAUSE 0x02 /* Used by pause. */ #define SLEEPQ_SX 0x03 /* Used by an sx lock. */ #define SLEEPQ_INTERRUPTIBLE 0x100 /* Sleep is interruptible. */ +#define SLEEPQ_JUST_ONE 0x200 /* Alternate signal semantics */ void init_sleepqueues(void); void sleepq_abort(struct thread *td, int intrval); @@ -100,7 +102,7 @@ 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); +int 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);