Index: sys/kern/subr_sleepqueue.c =================================================================== --- sys/kern/subr_sleepqueue.c +++ sys/kern/subr_sleepqueue.c @@ -67,6 +67,7 @@ #include #include +#include #include #include #include @@ -145,13 +146,17 @@ #endif } __aligned(CACHE_LINE_SIZE); -#ifdef SLEEPQUEUE_PROFILING -u_int sleepq_max_depth; static SYSCTL_NODE(_debug, OID_AUTO, sleepq, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "sleepq profiling"); +static COUNTER_U64_DEFINE_EARLY(sleepq_spurious_timeouts); +SYSCTL_COUNTER_U64(_debug_sleepq, OID_AUTO, spurious_timeouts, CTLFLAG_RD, + &sleepq_spurious_timeouts, "XXXMJ"); + +#ifdef SLEEPQUEUE_PROFILING static SYSCTL_NODE(_debug_sleepq, OID_AUTO, chains, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "sleepq chain stats"); +static u_int sleepq_max_depth; SYSCTL_UINT(_debug_sleepq, OID_AUTO, max_depth, CTLFLAG_RD, &sleepq_max_depth, 0, "maxmimum depth achieved of a single chain"); @@ -560,6 +565,10 @@ * just return. */ if (td->td_sleepqueue != NULL) { + /* + * XXXMJ is it possible for TDF_TIMEOUT to be set? Does it + * matter? + */ mtx_unlock_spin(&sc->sc_lock); thread_unlock(td); return; @@ -833,7 +842,8 @@ td->td_sleepqueue = LIST_FIRST(&sq->sq_free); LIST_REMOVE(td->td_sleepqueue, sq_hash); - if ((td->td_flags & TDF_TIMEOUT) == 0 && td->td_sleeptimo != 0) + if ((td->td_flags & TDF_TIMEOUT) == 0 && td->td_sleeptimo != 0 && + td->td_lock == &sc->sc_lock) { /* * We ignore the situation where timeout subsystem was * unable to stop our callout. The struct thread is @@ -843,8 +853,16 @@ * sleepq_timeout() ensure that the thread does not * get spurious wakeups, even if the callout was reset * or thread reused. + * + * We also cannot safely stop the callout if a scheduler + * lock is held since softclock_thread() forces a lock + * order of callout lock -> scheduler lock. The thread + * lock will be a scheduler lock only if the thread is + * preparing to go to sleep, so this is hopefully a rare + * scenario. */ callout_stop(&td->td_slpcallout); + } td->td_wmesg = NULL; td->td_wchan = NULL; @@ -1045,6 +1063,7 @@ /* * The thread does not want a timeout (yet). */ + counter_u64_add(sleepq_spurious_timeouts, 1); } else if (TD_IS_SLEEPING(td) && TD_ON_SLEEPQ(td)) { /* * See if the thread is asleep and get the wait @@ -1068,6 +1087,8 @@ * routines or it can be in sleepq_catch_signals(). */ td->td_flags |= TDF_TIMEOUT; + } else { + counter_u64_add(sleepq_spurious_timeouts, 1); } thread_unlock(td); }