Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/kern_clock.c
Show First 20 Lines • Show All 178 Lines • ▼ Show 20 Lines | static const char *blessed[] = { | ||||
"so_snd_sx", | "so_snd_sx", | ||||
"so_rcv_sx", | "so_rcv_sx", | ||||
NULL | NULL | ||||
}; | }; | ||||
static int slptime_threshold = 1800; | static int slptime_threshold = 1800; | ||||
static int blktime_threshold = 900; | static int blktime_threshold = 900; | ||||
static int sleepfreq = 3; | static int sleepfreq = 3; | ||||
static __inline void | |||||
_deadlres_td_on_lock(struct proc *p, struct thread *td, int blkticks) | |||||
{ | |||||
int tticks; | |||||
/* | |||||
* The thread should be blocked on a turnstile, simply check | |||||
* if the turnstile channel is in good state. | |||||
*/ | |||||
MPASS(td->td_blocked != NULL); | |||||
tticks = ticks - td->td_blktick; | |||||
thread_unlock(td); | |||||
if (tticks > blkticks) { | |||||
/* | |||||
* Accordingly with provided thresholds, this thread is stuck | |||||
* for too long on a turnstile. | |||||
*/ | |||||
PROC_UNLOCK(p); | |||||
sx_sunlock(&V_allproc_lock); | |||||
panic("%s: possible deadlock detected for %p, " | |||||
"blocked for %d ticks\n", __func__, td, tticks); | |||||
} | |||||
} | |||||
static __inline void | |||||
_deadlres_td_sleep_q(struct proc *p, struct thread *td, int slpticks) | |||||
{ | |||||
void *wchan; | |||||
int i, slptype, tryl, tticks; | |||||
/* | |||||
* Check if the thread is sleeping on a lock, otherwise skip the check. | |||||
* Drop the thread lock in order to avoid a LOR with the sleepqueue | |||||
* spinlock. | |||||
*/ | |||||
wchan = td->td_wchan; | |||||
tticks = ticks - td->td_slptick; | |||||
thread_unlock(td); | |||||
slptype = sleepq_type(wchan); | |||||
if ((slptype == SLEEPQ_SX || slptype == SLEEPQ_LK) && | |||||
tticks > slpticks) { | |||||
/* | |||||
* Accordingly with provided thresholds, this thread is stuck | |||||
* for too long on a sleepqueue. | |||||
* However, being on a sleepqueue, we might still check for the | |||||
* blessed list. | |||||
*/ | |||||
tryl = 0; | |||||
for (i = 0; blessed[i] != NULL; i++) { | |||||
if (!strcmp(blessed[i], td->td_wmesg)) { | |||||
tryl = 1; | |||||
break; | |||||
} | |||||
} | |||||
if (tryl != 0) | |||||
return; | |||||
PROC_UNLOCK(p); | |||||
sx_sunlock(&V_allproc_lock); | |||||
panic("%s: possible deadlock detected for %p, " | |||||
"blocked for %d ticks\n", __func__, td, tticks); | |||||
} | |||||
} | |||||
static void | static void | ||||
deadlres_td_on_lock(struct proc *p, struct thread *td, int blkticks) | deadlres_td_on_lock(struct proc *p, struct thread *td, int blkticks) | ||||
{ | { | ||||
int tticks; | int tticks; | ||||
sx_assert(&allproc_lock, SX_LOCKED); | sx_assert(&V_allproc_lock, SX_LOCKED); | ||||
PROC_LOCK_ASSERT(p, MA_OWNED); | PROC_LOCK_ASSERT(p, MA_OWNED); | ||||
THREAD_LOCK_ASSERT(td, MA_OWNED); | THREAD_LOCK_ASSERT(td, MA_OWNED); | ||||
/* | /* | ||||
* The thread should be blocked on a turnstile, simply check | * The thread should be blocked on a turnstile, simply check | ||||
* if the turnstile channel is in good state. | * if the turnstile channel is in good state. | ||||
*/ | */ | ||||
MPASS(td->td_blocked != NULL); | MPASS(td->td_blocked != NULL); | ||||
tticks = ticks - td->td_blktick; | tticks = ticks - td->td_blktick; | ||||
if (tticks > blkticks) | if (tticks > blkticks) | ||||
/* | /* | ||||
* Accordingly with provided thresholds, this thread is stuck | * Accordingly with provided thresholds, this thread is stuck | ||||
* for too long on a turnstile. | * for too long on a turnstile. | ||||
*/ | */ | ||||
panic("%s: possible deadlock detected for %p, " | panic("%s: possible deadlock detected for %p, " | ||||
"blocked for %d ticks\n", __func__, td, tticks); | "blocked for %d ticks\n", __func__, td, tticks); | ||||
} | } | ||||
static void | static void | ||||
deadlres_td_sleep_q(struct proc *p, struct thread *td, int slpticks) | deadlres_td_sleep_q(struct proc *p, struct thread *td, int slpticks) | ||||
{ | { | ||||
void *wchan; | void *wchan; | ||||
int i, slptype, tticks; | int i, slptype, tticks; | ||||
sx_assert(&allproc_lock, SX_LOCKED); | sx_assert(&V_allproc_lock, SX_LOCKED); | ||||
PROC_LOCK_ASSERT(p, MA_OWNED); | PROC_LOCK_ASSERT(p, MA_OWNED); | ||||
THREAD_LOCK_ASSERT(td, MA_OWNED); | THREAD_LOCK_ASSERT(td, MA_OWNED); | ||||
/* | /* | ||||
* Check if the thread is sleeping on a lock, otherwise skip the check. | * Check if the thread is sleeping on a lock, otherwise skip the check. | ||||
* Drop the thread lock in order to avoid a LOR with the sleepqueue | * Drop the thread lock in order to avoid a LOR with the sleepqueue | ||||
* spinlock. | * spinlock. | ||||
*/ | */ | ||||
wchan = td->td_wchan; | wchan = td->td_wchan; | ||||
Show All 15 Lines | if ((slptype == SLEEPQ_SX || slptype == SLEEPQ_LK) && | ||||
panic("%s: possible deadlock detected for %p, " | panic("%s: possible deadlock detected for %p, " | ||||
"blocked for %d ticks\n", __func__, td, tticks); | "blocked for %d ticks\n", __func__, td, tticks); | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
deadlkres(void) | deadlkres(void) | ||||
{ | { | ||||
VPS_ITERATOR_DECL(vps_iter); | |||||
struct proc *p; | struct proc *p; | ||||
struct thread *td; | struct thread *td; | ||||
int blkticks, slpticks, tryl; | int blkticks, slpticks, tryl; | ||||
tryl = 0; | tryl = 0; | ||||
for (;;) { | for (;;) { | ||||
blkticks = blktime_threshold * hz; | blkticks = blktime_threshold * hz; | ||||
slpticks = slptime_threshold * hz; | slpticks = slptime_threshold * hz; | ||||
VPS_LIST_RLOCK(); | |||||
VPS_FOREACH(vps_iter) { | |||||
again: | |||||
CURVPS_SET_QUIET(vps_iter); | |||||
/* | /* | ||||
* Avoid to sleep on the sx_lock in order to avoid a | * Avoid to sleep on the sx_lock in order to avoid a | ||||
* possible priority inversion problem leading to | * possible priority inversion problem leading to | ||||
* starvation. | * starvation. | ||||
* If the lock can't be held after 100 tries, panic. | * If the lock can't be held after 100 tries, panic. | ||||
*/ | */ | ||||
if (!sx_try_slock(&allproc_lock)) { | if (!sx_try_slock(&V_allproc_lock)) { | ||||
if (tryl > 100) | if (tryl > 100) | ||||
panic("%s: possible deadlock detected " | panic("%s: possible deadlock detected " | ||||
"on allproc_lock\n", __func__); | "on allproc_lock\n", __func__); | ||||
tryl++; | tryl++; | ||||
CURVPS_RESTORE(); | |||||
pause("allproc", sleepfreq * hz); | pause("allproc", sleepfreq * hz); | ||||
continue; | goto again; | ||||
} | } | ||||
tryl = 0; | tryl = 0; | ||||
FOREACH_PROC_IN_SYSTEM(p) { | FOREACH_PROC_IN_SYSTEM(p) { | ||||
PROC_LOCK(p); | PROC_LOCK(p); | ||||
if (p->p_state == PRS_NEW) { | if (p->p_state == PRS_NEW) { | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
continue; | continue; | ||||
} | } | ||||
FOREACH_THREAD_IN_PROC(p, td) { | FOREACH_THREAD_IN_PROC(p, td) { | ||||
thread_lock(td); | thread_lock(td); | ||||
if (TD_ON_LOCK(td)) | if (TD_ON_LOCK(td)) | ||||
deadlres_td_on_lock(p, td, | deadlres_td_on_lock(p, td, | ||||
blkticks); | blkticks); | ||||
else if (TD_IS_SLEEPING(td) && | else if (TD_IS_SLEEPING(td) && | ||||
TD_ON_SLEEPQ(td)) | TD_ON_SLEEPQ(td)) | ||||
deadlres_td_sleep_q(p, td, | deadlres_td_sleep_q(p, td, | ||||
slpticks); | slpticks); | ||||
thread_unlock(td); | thread_unlock(td); | ||||
} | } | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
} | } | ||||
sx_sunlock(&allproc_lock); | sx_sunlock(&V_allproc_lock); | ||||
CURVPS_RESTORE(); | |||||
} | |||||
VPS_LIST_RUNLOCK(); | |||||
/* Sleep for sleepfreq seconds. */ | /* Sleep for sleepfreq seconds. */ | ||||
pause("-", sleepfreq * hz); | pause("-", sleepfreq * hz); | ||||
} | } | ||||
} | } | ||||
static struct kthread_desc deadlkres_kd = { | static struct kthread_desc deadlkres_kd = { | ||||
"deadlkres", | "deadlkres", | ||||
▲ Show 20 Lines • Show All 595 Lines • Show Last 20 Lines |