MFC: Add a new 'show lock' command to ddb that can dump information about
mutexes and sx locks including current owners, etc.
This commit is contained in:
parent
5b6819c0d6
commit
e4c2908f0b
@ -89,16 +89,26 @@ __FBSDID("$FreeBSD$");
|
||||
#define mtx_owner(m) (mtx_unowned((m)) ? NULL \
|
||||
: (struct thread *)((m)->mtx_lock & MTX_FLAGMASK))
|
||||
|
||||
#ifdef DDB
|
||||
static void db_show_mtx(struct lock_object *lock);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Lock classes for sleep and spin mutexes.
|
||||
*/
|
||||
struct lock_class lock_class_mtx_sleep = {
|
||||
"sleep mutex",
|
||||
LC_SLEEPLOCK | LC_RECURSABLE
|
||||
LC_SLEEPLOCK | LC_RECURSABLE,
|
||||
#ifdef DDB
|
||||
db_show_mtx
|
||||
#endif
|
||||
};
|
||||
struct lock_class lock_class_mtx_spin = {
|
||||
"spin mutex",
|
||||
LC_SPINLOCK | LC_RECURSABLE
|
||||
LC_SPINLOCK | LC_RECURSABLE,
|
||||
#ifdef DDB
|
||||
db_show_mtx
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
@ -905,3 +915,64 @@ mutex_init(void)
|
||||
mtx_init(&devmtx, "cdev", NULL, MTX_DEF);
|
||||
mtx_lock(&Giant);
|
||||
}
|
||||
|
||||
#ifdef DDB
|
||||
/* XXX: This function is not mutex-specific. */
|
||||
DB_SHOW_COMMAND(lock, db_show_lock)
|
||||
{
|
||||
struct lock_object *lock;
|
||||
|
||||
if (!have_addr)
|
||||
return;
|
||||
lock = (struct lock_object *)addr;
|
||||
if (lock->lo_class != &lock_class_mtx_sleep &&
|
||||
lock->lo_class != &lock_class_mtx_spin &&
|
||||
lock->lo_class != &lock_class_sx) {
|
||||
db_printf("Unknown lock class\n");
|
||||
return;
|
||||
}
|
||||
db_printf(" class: %s\n", lock->lo_class->lc_name);
|
||||
db_printf(" name: %s\n", lock->lo_name);
|
||||
if (lock->lo_type && lock->lo_type != lock->lo_name)
|
||||
db_printf(" type: %s\n", lock->lo_type);
|
||||
lock->lo_class->lc_ddb_show(lock);
|
||||
}
|
||||
|
||||
void
|
||||
db_show_mtx(struct lock_object *lock)
|
||||
{
|
||||
struct thread *td;
|
||||
struct mtx *m;
|
||||
|
||||
m = (struct mtx *)lock;
|
||||
|
||||
db_printf(" flags: {");
|
||||
if (m->mtx_object.lo_class == &lock_class_mtx_spin)
|
||||
db_printf("SPIN");
|
||||
else
|
||||
db_printf("DEF");
|
||||
if (m->mtx_object.lo_flags & LO_RECURSABLE)
|
||||
db_printf(", RECURSE");
|
||||
if (m->mtx_object.lo_flags & LO_DUPOK)
|
||||
db_printf(", DUPOK");
|
||||
db_printf("}\n");
|
||||
db_printf(" state: {");
|
||||
if (mtx_unowned(m))
|
||||
db_printf("UNOWNED");
|
||||
else {
|
||||
db_printf("OWNED");
|
||||
if (m->mtx_lock & MTX_CONTESTED)
|
||||
db_printf(", CONTESTED");
|
||||
if (m->mtx_lock & MTX_RECURSED)
|
||||
db_printf(", RECURSED");
|
||||
}
|
||||
db_printf("}\n");
|
||||
if (!mtx_unowned(m)) {
|
||||
td = mtx_owner(m);
|
||||
db_printf(" owner: %p (tid %d, pid %d, \"%s\")\n", td,
|
||||
td->td_tid, td->td_proc->p_pid, td->td_proc->p_comm);
|
||||
if (mtx_recursed(m))
|
||||
db_printf(" recursed: %d\n", m->mtx_recurse);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -36,17 +36,30 @@
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "opt_ddb.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/ktr.h>
|
||||
#include <sys/linker_set.h>
|
||||
#include <sys/condvar.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/sx.h>
|
||||
|
||||
#include <ddb/ddb.h>
|
||||
|
||||
#ifdef DDB
|
||||
static void db_show_sx(struct lock_object *lock);
|
||||
#endif
|
||||
|
||||
struct lock_class lock_class_sx = {
|
||||
"sx",
|
||||
LC_SLEEPLOCK | LC_SLEEPABLE | LC_RECURSABLE | LC_UPGRADABLE
|
||||
LC_SLEEPLOCK | LC_SLEEPABLE | LC_RECURSABLE | LC_UPGRADABLE,
|
||||
#ifdef DDB
|
||||
db_show_sx
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifndef INVARIANTS
|
||||
@ -367,3 +380,26 @@ _sx_assert(struct sx *sx, int what, const char *file, int line)
|
||||
}
|
||||
}
|
||||
#endif /* INVARIANT_SUPPORT */
|
||||
|
||||
#ifdef DDB
|
||||
void
|
||||
db_show_sx(struct lock_object *lock)
|
||||
{
|
||||
struct thread *td;
|
||||
struct sx *sx;
|
||||
|
||||
sx = (struct sx *)lock;
|
||||
|
||||
db_printf(" state: ");
|
||||
if (sx->sx_cnt < 0) {
|
||||
td = sx->sx_xholder;
|
||||
db_printf("XLOCK: %p (tid %d, pid %d, \"%s\")\n", td,
|
||||
td->td_tid, td->td_proc->p_pid, td->td_proc->p_comm);
|
||||
} else if (sx->sx_cnt > 0)
|
||||
db_printf("SLOCK: %d locks\n", sx->sx_cnt);
|
||||
else
|
||||
db_printf("UNLOCKED\n");
|
||||
db_printf(" waiters: %d shared, %d exclusive\n", sx->sx_shrd_wcnt,
|
||||
sx->sx_excl_wcnt);
|
||||
}
|
||||
#endif
|
||||
|
@ -50,6 +50,7 @@ struct thread;
|
||||
struct lock_class {
|
||||
const char *lc_name;
|
||||
u_int lc_flags;
|
||||
void (*lc_ddb_show)(struct lock_object *lock);
|
||||
};
|
||||
|
||||
#define LC_SLEEPLOCK 0x00000001 /* Sleep lock. */
|
||||
|
Loading…
Reference in New Issue
Block a user