Index: sys/kern/kern_clock.c =================================================================== --- sys/kern/kern_clock.c (revision 255087) +++ sys/kern/kern_clock.c (working copy) @@ -177,6 +177,7 @@ static const char *blessed[] = { "so_rcv_sx", NULL }; +static int spintime_threshold = 600; static int slptime_threshold = 1800; static int blktime_threshold = 900; static int sleepfreq = 3; @@ -187,12 +188,13 @@ deadlkres(void) struct proc *p; struct thread *td; void *wchan; - int blkticks, i, slpticks, slptype, tryl, tticks; + int blkticks, i, spinticks, slpticks, slptype, tryl, tticks; tryl = 0; for (;;) { blkticks = blktime_threshold * hz; slpticks = slptime_threshold * hz; + spinticks = spintime_threshold * hz; /* * Avoid to sleep on the sx_lock in order to avoid a possible @@ -217,9 +219,24 @@ deadlkres(void) FOREACH_THREAD_IN_PROC(p, td) { thread_lock(td); - if (TD_ON_LOCK(td)) { + if (TD_IS_SPINNING(td)) { /* + * The thread is adaptively spinning + * trying to acquire a lock. + */ + tticks = ticks - td->td_spintick; + thread_unlock(td); + if (tticks > spinticks) { + PROC_UNLOCK(p); + sx_sunlock(&allproc_lock); + panic("%s: possible deadlock detected for %p, blocked for %d ticks", + __func__, td, tticks); + } + } + else if (TD_ON_LOCK(td)) { + + /* * The thread should be blocked on a * turnstile, simply check if the * turnstile channel is in good state. @@ -315,6 +332,9 @@ SYSCTL_INT(_debug_deadlkres, OID_AUTO, slptime_thr SYSCTL_INT(_debug_deadlkres, OID_AUTO, blktime_threshold, CTLFLAG_RW, &blktime_threshold, 0, "Number of seconds within is valid to block on a turnstile"); +SYSCTL_INT(_debug_deadlkres, OID_AUTO, spintime_threshold, CTLFLAG_RW, + &spintime_threshold, 0, + "Number of seconds within is valid to spin on a lock"); SYSCTL_INT(_debug_deadlkres, OID_AUTO, sleepfreq, CTLFLAG_RW, &sleepfreq, 0, "Number of seconds between any deadlock resolver thread run"); #endif /* DEADLKRES */ Index: sys/kern/kern_mutex.c =================================================================== --- sys/kern/kern_mutex.c (revision 255087) +++ sys/kern/kern_mutex.c (working copy) @@ -376,6 +376,7 @@ __mtx_lock_sleep(volatile uintptr_t *c, uintptr_t uintptr_t v; #ifdef ADAPTIVE_MUTEXES volatile struct thread *owner; + int saveflags; #endif #ifdef KTR int cont_logged = 0; @@ -430,6 +431,8 @@ __mtx_lock_sleep(volatile uintptr_t *c, uintptr_t */ v = m->mtx_lock; if (v != MTX_UNOWNED) { + saveflags = curthread_pflags_set(TDP_SPINNING); + curthread->td_spintick = ticks; owner = (struct thread *)(v & ~MTX_FLAGMASK); if (TD_IS_RUNNING(owner)) { if (LOCK_LOG_TEST(&m->lock_object, 0)) @@ -443,8 +446,10 @@ __mtx_lock_sleep(volatile uintptr_t *c, uintptr_t spin_cnt++; #endif } + curthread_pflags_restore(saveflags); continue; } + curthread_pflags_restore(saveflags); } #endif @@ -486,6 +491,12 @@ __mtx_lock_sleep(volatile uintptr_t *c, uintptr_t continue; } + /* + * Reset the spintick counter, as long as we're not spinning for + * this lock anymore. + */ + curthread->td_spintick = 0; + /* * We definitely must sleep for this lock. */ Index: sys/sys/proc.h =================================================================== --- sys/sys/proc.h (revision 255087) +++ sys/sys/proc.h (working copy) @@ -247,6 +247,7 @@ struct thread { u_int td_estcpu; /* (t) estimated cpu utilization */ int td_slptick; /* (t) Time at sleep. */ int td_blktick; /* (t) Time spent blocked. */ + int td_spintick; /* (t) Time spent spinning on locks. */ int td_swvoltick; /* (t) Time at last SW_VOL switch. */ u_int td_cow; /* (*) Number of copy-on-write faults */ struct rusage td_ru; /* (t) rusage information. */ @@ -424,6 +425,7 @@ do { \ #define TDP_RESETSPUR 0x04000000 /* Reset spurious page fault history. */ #define TDP_NERRNO 0x08000000 /* Last errno is already in td_errno */ #define TDP_UIOHELD 0x10000000 /* Current uio has pages held in td_ma */ +#define TDP_SPINNING 0x20000000 /* Thread is curretly spinning for a lock */ /* * Reasons that the current thread can not be run yet. @@ -448,6 +450,7 @@ do { \ #define TD_ON_UPILOCK(td) ((td)->td_flags & TDF_UPIBLOCKED) #define TD_IS_IDLETHREAD(td) ((td)->td_flags & TDF_IDLETD) +#define TD_IS_SPINNING(td) ((td)->td_pflags & TDP_SPINNING) #define TD_SET_INHIB(td, inhib) do { \ (td)->td_state = TDS_INHIBITED; \