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);
        
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "[email protected]"

Reply via email to