From owner-p4-projects@FreeBSD.ORG Thu Aug 3 21:36:29 2006 Return-Path: X-Original-To: p4-projects@freebsd.org Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id CB70116A4E6; Thu, 3 Aug 2006 21:36:28 +0000 (UTC) X-Original-To: perforce@freebsd.org Delivered-To: perforce@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id A711016A4E0 for ; Thu, 3 Aug 2006 21:36:28 +0000 (UTC) (envelope-from jhb@freebsd.org) Received: from repoman.freebsd.org (repoman.freebsd.org [216.136.204.115]) by mx1.FreeBSD.org (Postfix) with ESMTP id 1B10543D5F for ; Thu, 3 Aug 2006 21:36:28 +0000 (GMT) (envelope-from jhb@freebsd.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.13.6/8.13.6) with ESMTP id k73LaR9d080688 for ; Thu, 3 Aug 2006 21:36:28 GMT (envelope-from jhb@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.13.6/8.13.4/Submit) id k73LaRER080685 for perforce@freebsd.org; Thu, 3 Aug 2006 21:36:27 GMT (envelope-from jhb@freebsd.org) Date: Thu, 3 Aug 2006 21:36:27 GMT Message-Id: <200608032136.k73LaRER080685@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to jhb@freebsd.org using -f From: John Baldwin To: Perforce Change Reviews Cc: Subject: PERFORCE change 103140 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 03 Aug 2006 21:36:29 -0000 http://perforce.freebsd.org/chv.cgi?CH=103140 Change 103140 by jhb@jhb_mutex on 2006/08/03 21:35:31 - Rename 'show threadchain' to 'show lockchain' and 'show lockchain' to 'show locktree'. - Add a new 'show sleepchain' that attempts to do 'show lockchain' for sleepable locks (i.e. sx and lockmgr). I've had much help tracking down vnode deadlocks at work using a gdb version of this that just grokked lockmgr locks. Affected files ... .. //depot/projects/smpng/sys/kern/kern_lock.c#48 edit .. //depot/projects/smpng/sys/kern/kern_sx.c#36 edit .. //depot/projects/smpng/sys/kern/subr_turnstile.c#31 edit .. //depot/projects/smpng/sys/sys/lockmgr.h#16 edit .. //depot/projects/smpng/sys/sys/sx.h#20 edit Differences ... ==== //depot/projects/smpng/sys/kern/kern_lock.c#48 (text+ko) ==== @@ -43,6 +43,8 @@ #include __FBSDID("$FreeBSD: src/sys/kern/kern_lock.c,v 1.97 2006/07/14 17:55:36 pjd Exp $"); +#include "opt_ddb.h" + #include #include #include @@ -56,6 +58,10 @@ #include #endif +#ifdef DDB +#include +#endif + /* * Locking primitives implementation. * Locks provide shared/exclusive sychronization. @@ -581,3 +587,33 @@ stack_print(&lkp->lk_stack); #endif } + +#ifdef DDB +/* + * Check to see if a thread that is blocked on a sleep queue is actually + * blocked on a 'struct lock'. If so, output some details and return true. + * If the lock has an exclusive owner, return that in *ownerp. + */ +int +lockmgr_chain(struct thread *td, struct thread **ownerp) +{ + struct lock *lkp; + + lkp = td->td_wchan; + + /* Simple test to see if wchan points to a lockmgr lock. */ + if (lkp->lk_wmesg != td->td_wmesg) + return (0); + + /* Ok, we think we have a lockmgr lock, so output some details. */ + db_printf("blocked on \"%s\" ", lkp->lk_wmesg); + if (lkp->lk_sharecount) { + db_printf("SHARED (count %d)\n", lkp->lk_sharecount); + *ownerp = NULL; + } else { + db_printf("EXCL (count %d)\n", lkp->lk_exclusivecount); + *ownerp = lkp->lk_lockholder; + } + return (1); +} +#endif ==== //depot/projects/smpng/sys/kern/kern_sx.c#36 (text+ko) ==== @@ -48,9 +48,9 @@ #include #include +#ifdef DDB #include -#ifdef DDB static void db_show_sx(struct lock_object *lock); #endif @@ -395,4 +395,57 @@ db_printf(" waiters: %d shared, %d exclusive\n", sx->sx_shrd_wcnt, sx->sx_excl_wcnt); } + +/* + * Check to see if a thread that is blocked on a sleep queue is actually + * blocked on an sx lock. If so, output some details and return true. + * If the lock has an exclusive owner, return that in *ownerp. + */ +int +sx_chain(struct thread *td, struct thread **ownerp) +{ + struct sx *sx; + struct cv *cv; + + /* + * First, see if it looks like td is blocked on a condition + * variable. + */ + cv = td->td_wchan; + if (cv->cv_description != td->td_wmesg) + return (0); + + /* + * Ok, see if it looks like td is blocked on the exclusive + * condition variable. + */ + sx = (struct sx *)((char *)cv - offsetof(struct sx, sx_excl_cv)); + if (LOCK_CLASS(&sx->sx_object) == &lock_class_sx && + sx->sx_excl_wcnt > 0) + goto ok; + + /* + * Second, see if it looks like td is blocked on the shared + * condvar. + */ + sx = (struct sx *)((char *)cv - offsetof(struct sx, sx_shrd_cv)); + if (LOCK_CLASS(&sx->sx_object) == &lock_class_sx && + sx->sx_shrd_wcnt > 0) + goto ok; + + /* Doesn't seem to be an sx lock. */ + return (0); + +ok: + /* We think we have an sx lock, so output some details. */ + db_printf("blocked on sx \"%s\" ", td->td_wmesg); + if (sx->sx_cnt >= 0) { + db_printf("SLOCK (count %d)\n", sx->sx_cnt); + *ownerp = NULL; + } else { + db_printf("XLOCK\n"); + *ownerp = sx->sx_xholder; + } + return (1); +} #endif ==== //depot/projects/smpng/sys/kern/subr_turnstile.c#31 (text+ko) ==== @@ -78,6 +78,8 @@ #ifdef DDB #include #include +#include +#include #endif /* @@ -1035,8 +1037,12 @@ } +/* + * Show all the threads a particular thread is waiting on based on + * non-sleepable and non-spin locks. + */ static void -print_threadchain(struct thread *td, const char *prefix) +print_lockchain(struct thread *td, const char *prefix) { struct lock_object *lock; struct lock_class *class; @@ -1084,7 +1090,7 @@ } } -DB_SHOW_COMMAND(threadchain, db_show_threadchain) +DB_SHOW_COMMAND(lockchain, db_show_lockchain) { struct thread *td; @@ -1094,7 +1100,7 @@ else td = kdb_thread; - print_threadchain(td, ""); + print_lockchain(td, ""); } DB_SHOW_COMMAND(allchains, db_show_allchains) @@ -1108,7 +1114,7 @@ FOREACH_THREAD_IN_PROC(p, td) { if (TD_ON_LOCK(td) && LIST_EMPTY(&td->td_contested)) { db_printf("chain %d:\n", i++); - print_threadchain(td, " "); + print_lockchain(td, " "); } if (db_pager_quit) return; @@ -1116,6 +1122,72 @@ } } + +/* + * 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[0] != '\0' ? td->td_name : + td->td_proc->p_comm); + 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 @@ -1156,7 +1228,7 @@ print_waiter(td, indent + 1); } -DB_SHOW_COMMAND(lockchain, db_show_lockchain) +DB_SHOW_COMMAND(locktree, db_show_locktree) { struct lock_object *lock; struct lock_class *class; ==== //depot/projects/smpng/sys/sys/lockmgr.h#16 (text+ko) ==== @@ -203,5 +203,8 @@ void lockmgr_printinfo(struct lock *); int lockstatus(struct lock *, struct thread *); int lockcount(struct lock *); +#ifdef DDB +int lockmgr_chain(struct thread *td, struct thread **ownerp); +#endif #endif /* !_SYS_LOCKMGR_H_ */ ==== //depot/projects/smpng/sys/sys/sx.h#20 (text+ko) ==== @@ -60,6 +60,9 @@ #ifdef INVARIANT_SUPPORT void _sx_assert(struct sx *sx, int what, const char *file, int line); #endif +#ifdef DDB +int sx_chain(struct thread *td, struct thread **ownerp); +#endif struct sx_args { struct sx *sa_sx;