svn commit: r322836 - head/sys/kern
Conrad Meyer
cem at FreeBSD.org
Thu Aug 24 15:12:18 UTC 2017
Author: cem
Date: Thu Aug 24 15:12:16 2017
New Revision: 322836
URL: https://svnweb.freebsd.org/changeset/base/322836
Log:
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
Modified:
head/sys/kern/subr_turnstile.c
Modified: head/sys/kern/subr_turnstile.c
==============================================================================
--- head/sys/kern/subr_turnstile.c Thu Aug 24 13:39:24 2017 (r322835)
+++ head/sys/kern/subr_turnstile.c Thu Aug 24 15:12:16 2017 (r322836)
@@ -1096,7 +1096,7 @@ found:
/*
* Show all the threads a particular thread is waiting on based on
- * non-sleepable and non-spin locks.
+ * non-spin locks.
*/
static void
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_class *class;
struct turnstile *ts;
+ struct thread *owner;
/*
* 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) {
db_printf("%sthread %d (pid %d, %s) ", prefix, td->td_tid,
@@ -1136,6 +1137,17 @@ print_lockchain(struct thread *td, const char *prefix)
return;
td = ts->ts_owner;
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");
return;
@@ -1158,6 +1170,7 @@ DB_SHOW_COMMAND(lockchain, db_show_lockchain)
print_lockchain(td, "");
}
+DB_SHOW_ALIAS(sleepchain, db_show_lockchain);
DB_SHOW_ALL_COMMAND(chains, db_show_allchains)
{
@@ -1168,84 +1181,17 @@ DB_SHOW_ALL_COMMAND(chains, db_show_allchains)
i = 1;
FOREACH_PROC_IN_SYSTEM(p) {
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++);
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)
return;
}
}
}
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);
More information about the svn-src-all
mailing list