summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_sx.c
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2006-08-15 18:29:01 +0000
committerjhb <jhb@FreeBSD.org>2006-08-15 18:29:01 +0000
commit4e96206d8aa504d0b00ace5c45fcb104888b7dc3 (patch)
treecdceb81a7ecf499b8d0d51c3f275b40b0a836064 /sys/kern/kern_sx.c
parente092be01212a8a69fe2f62be7d44c909fe7002bb (diff)
downloadFreeBSD-src-4e96206d8aa504d0b00ace5c45fcb104888b7dc3.zip
FreeBSD-src-4e96206d8aa504d0b00ace5c45fcb104888b7dc3.tar.gz
Add a new 'show sleepchain' ddb command similar to 'show lockchain' except
that it operates on lockmgr and sx locks. This can be useful for tracking down vnode deadlocks in VFS for example. Note that this command is a bit more fragile than 'show lockchain' as we have to poke around at the wait channel of a thread to see if it points to either a struct lock or a condition variable inside of a struct sx. If td_wchan points to something unmapped, then this command will terminate early due to a fault, but no harm will be done.
Diffstat (limited to 'sys/kern/kern_sx.c')
-rw-r--r--sys/kern/kern_sx.c55
1 files changed, 54 insertions, 1 deletions
diff --git a/sys/kern/kern_sx.c b/sys/kern/kern_sx.c
index d215807..fdd8bc9 100644
--- a/sys/kern/kern_sx.c
+++ b/sys/kern/kern_sx.c
@@ -48,9 +48,9 @@ __FBSDID("$FreeBSD$");
#include <sys/proc.h>
#include <sys/sx.h>
+#ifdef DDB
#include <ddb/ddb.h>
-#ifdef DDB
static void db_show_sx(struct lock_object *lock);
#endif
@@ -395,4 +395,57 @@ db_show_sx(struct lock_object *lock)
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
+ * condition variable.
+ */
+ 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
OpenPOWER on IntegriCloud