1
0
mirror of https://git.FreeBSD.org/src.git synced 2025-01-16 15:11:52 +00:00

Merge print_lockchain and print_sleepchain

When debugging a deadlock, it is useful to follow the full chain of locks as
far as possible.

Reviewed by:	jhb
Sponsored by:	Dell EMC Isilon
Differential Revision:	https://reviews.freebsd.org/D12115
This commit is contained in:
Conrad Meyer 2017-08-24 15:12:16 +00:00
parent 2624320fcc
commit 0c1d923efb
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=322836

View File

@ -1096,7 +1096,7 @@ DB_SHOW_COMMAND(turnstile, db_show_turnstile)
/* /*
* Show all the threads a particular thread is waiting on based on * Show all the threads a particular thread is waiting on based on
* non-sleepable and non-spin locks. * non-spin locks.
*/ */
static void static void
print_lockchain(struct thread *td, const char *prefix) print_lockchain(struct thread *td, const char *prefix)
@ -1104,10 +1104,11 @@ print_lockchain(struct thread *td, const char *prefix)
struct lock_object *lock; struct lock_object *lock;
struct lock_class *class; struct lock_class *class;
struct turnstile *ts; struct turnstile *ts;
struct thread *owner;
/* /*
* Follow the chain. We keep walking as long as the thread is * Follow the chain. We keep walking as long as the thread is
* blocked on a turnstile that has an owner. * blocked on a lock that has an owner.
*/ */
while (!db_pager_quit) { while (!db_pager_quit) {
db_printf("%sthread %d (pid %d, %s) ", prefix, td->td_tid, db_printf("%sthread %d (pid %d, %s) ", prefix, td->td_tid,
@ -1136,6 +1137,17 @@ print_lockchain(struct thread *td, const char *prefix)
return; return;
td = ts->ts_owner; td = ts->ts_owner;
break; break;
} else if (TD_ON_SLEEPQ(td)) {
if (!lockmgr_chain(td, &owner) &&
!sx_chain(td, &owner)) {
db_printf("sleeping on %p \"%s\"\n",
td->td_wchan, td->td_wmesg);
return;
}
if (owner == NULL)
return;
td = owner;
break;
} }
db_printf("inhibited\n"); db_printf("inhibited\n");
return; return;
@ -1158,6 +1170,7 @@ DB_SHOW_COMMAND(lockchain, db_show_lockchain)
print_lockchain(td, ""); print_lockchain(td, "");
} }
DB_SHOW_ALIAS(sleepchain, db_show_lockchain);
DB_SHOW_ALL_COMMAND(chains, db_show_allchains) DB_SHOW_ALL_COMMAND(chains, db_show_allchains)
{ {
@ -1168,14 +1181,11 @@ DB_SHOW_ALL_COMMAND(chains, db_show_allchains)
i = 1; i = 1;
FOREACH_PROC_IN_SYSTEM(p) { FOREACH_PROC_IN_SYSTEM(p) {
FOREACH_THREAD_IN_PROC(p, td) { FOREACH_THREAD_IN_PROC(p, td) {
if (TD_ON_LOCK(td) && LIST_EMPTY(&td->td_contested)) { if ((TD_ON_LOCK(td) && LIST_EMPTY(&td->td_contested))
|| (TD_IS_INHIBITED(td) && TD_ON_SLEEPQ(td))) {
db_printf("chain %d:\n", i++); db_printf("chain %d:\n", i++);
print_lockchain(td, " "); print_lockchain(td, " ");
} }
if (TD_IS_INHIBITED(td) && TD_ON_SLEEPQ(td)) {
db_printf("chain %d:\n", i++);
print_sleepchain(td, " ");
}
if (db_pager_quit) if (db_pager_quit)
return; return;
} }
@ -1183,70 +1193,6 @@ DB_SHOW_ALL_COMMAND(chains, db_show_allchains)
} }
DB_SHOW_ALIAS(allchains, db_show_allchains) DB_SHOW_ALIAS(allchains, db_show_allchains)
/*
* Show all the threads a particular thread is waiting on based on
* sleepable locks.
*/
static void
print_sleepchain(struct thread *td, const char *prefix)
{
struct thread *owner;
/*
* Follow the chain. We keep walking as long as the thread is
* blocked on a sleep lock that has an owner.
*/
while (!db_pager_quit) {
db_printf("%sthread %d (pid %d, %s) ", prefix, td->td_tid,
td->td_proc->p_pid, td->td_name);
switch (td->td_state) {
case TDS_INACTIVE:
db_printf("is inactive\n");
return;
case TDS_CAN_RUN:
db_printf("can run\n");
return;
case TDS_RUNQ:
db_printf("is on a run queue\n");
return;
case TDS_RUNNING:
db_printf("running on CPU %d\n", td->td_oncpu);
return;
case TDS_INHIBITED:
if (TD_ON_SLEEPQ(td)) {
if (lockmgr_chain(td, &owner) ||
sx_chain(td, &owner)) {
if (owner == NULL)
return;
td = owner;
break;
}
db_printf("sleeping on %p \"%s\"\n",
td->td_wchan, td->td_wmesg);
return;
}
db_printf("inhibited\n");
return;
default:
db_printf("??? (%#x)\n", td->td_state);
return;
}
}
}
DB_SHOW_COMMAND(sleepchain, db_show_sleepchain)
{
struct thread *td;
/* Figure out which thread to start with. */
if (have_addr)
td = db_lookup_thread(addr, true);
else
td = kdb_thread;
print_sleepchain(td, "");
}
static void print_waiters(struct turnstile *ts, int indent); static void print_waiters(struct turnstile *ts, int indent);
static void static void