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