ddb's "show all locks":
- Make the output easier to scan quickly. - Show every LWP that is blocked on a lock, and the details of the lock.
This commit is contained in:
parent
85e6de746e
commit
a4da18db9d
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: kern_turnstile.c,v 1.35 2019/12/16 19:22:15 ad Exp $ */
|
||||
/* $NetBSD: kern_turnstile.c,v 1.36 2020/01/21 20:31:57 ad Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2002, 2006, 2007, 2009, 2019 The NetBSD Foundation, Inc.
|
||||
|
@ -60,7 +60,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: kern_turnstile.c,v 1.35 2019/12/16 19:22:15 ad Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: kern_turnstile.c,v 1.36 2020/01/21 20:31:57 ad Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/lockdebug.h>
|
||||
|
@ -536,29 +536,25 @@ turnstile_print(volatile void *obj, void (*pr)(const char *, ...))
|
|||
turnstile_t *ts;
|
||||
tschain_t *tc;
|
||||
sleepq_t *rsq, *wsq;
|
||||
kmutex_t *lock;
|
||||
u_int hash;
|
||||
lwp_t *l;
|
||||
|
||||
hash = TS_HASH(obj);
|
||||
tc = &turnstile_chains[hash];
|
||||
lock = &turnstile_locks[hash].lock;
|
||||
|
||||
LIST_FOREACH(ts, tc, ts_chain)
|
||||
if (ts->ts_obj == obj)
|
||||
break;
|
||||
|
||||
(*pr)("Turnstile chain at %p with mutex %p.\n", tc, lock);
|
||||
if (ts == NULL) {
|
||||
(*pr)("=> No active turnstile for this lock.\n");
|
||||
(*pr)("Turnstile: no active turnstile for this lock.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
rsq = &ts->ts_sleepq[TS_READER_Q];
|
||||
wsq = &ts->ts_sleepq[TS_WRITER_Q];
|
||||
|
||||
(*pr)("=> Turnstile at %p (wrq=%p, rdq=%p).\n", ts, rsq, wsq);
|
||||
|
||||
(*pr)("Turnstile:\n");
|
||||
(*pr)("=> %d waiting readers:", TS_WAITERS(ts, TS_READER_Q));
|
||||
TAILQ_FOREACH(l, rsq, l_sleepchain) {
|
||||
(*pr)(" %p", l);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: subr_lockdebug.c,v 1.73 2020/01/08 16:21:34 ad Exp $ */
|
||||
/* $NetBSD: subr_lockdebug.c,v 1.74 2020/01/21 20:31:57 ad Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2006, 2007, 2008, 2020 The NetBSD Foundation, Inc.
|
||||
|
@ -34,7 +34,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: subr_lockdebug.c,v 1.73 2020/01/08 16:21:34 ad Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: subr_lockdebug.c,v 1.74 2020/01/21 20:31:57 ad Exp $");
|
||||
|
||||
#ifdef _KERNEL_OPT
|
||||
#include "opt_ddb.h"
|
||||
|
@ -108,7 +108,8 @@ static void lockdebug_abort1(const char *, size_t, lockdebug_t *, int,
|
|||
const char *, bool);
|
||||
static int lockdebug_more(int);
|
||||
static void lockdebug_init(void);
|
||||
static void lockdebug_dump(lockdebug_t *, void (*)(const char *, ...)
|
||||
static void lockdebug_dump(lwp_t *, lockdebug_t *,
|
||||
void (*)(const char *, ...)
|
||||
__printflike(1, 2));
|
||||
|
||||
static signed int
|
||||
|
@ -468,6 +469,9 @@ lockdebug_wantlock(const char *func, size_t line,
|
|||
true);
|
||||
return;
|
||||
}
|
||||
if (l->l_ld_wanted == NULL) {
|
||||
l->l_ld_wanted = ld;
|
||||
}
|
||||
__cpu_simple_unlock(&ld->ld_spinlock);
|
||||
splx(s);
|
||||
}
|
||||
|
@ -529,6 +533,9 @@ lockdebug_locked(const char *func, size_t line,
|
|||
ld->ld_cpu = (uint16_t)cpu_index(curcpu());
|
||||
ld->ld_lwp = l;
|
||||
__cpu_simple_unlock(&ld->ld_spinlock);
|
||||
if (l->l_ld_wanted == ld) {
|
||||
l->l_ld_wanted = NULL;
|
||||
}
|
||||
splx(s);
|
||||
}
|
||||
|
||||
|
@ -692,7 +699,7 @@ lockdebug_barrier(const char *func, size_t line, volatile void *onelock,
|
|||
if (ld->ld_lockops->lo_type == LOCKOPS_CV)
|
||||
continue;
|
||||
if (ld->ld_lwp == l)
|
||||
lockdebug_dump(ld, printf);
|
||||
lockdebug_dump(l, ld, printf);
|
||||
}
|
||||
panic("%s,%zu: holding %d shared locks", func, line,
|
||||
l->l_shlocks);
|
||||
|
@ -744,7 +751,7 @@ lockdebug_mem_check(const char *func, size_t line, void *base, size_t sz)
|
|||
* Dump information about a lock on panic, or for DDB.
|
||||
*/
|
||||
static void
|
||||
lockdebug_dump(lockdebug_t *ld, void (*pr)(const char *, ...)
|
||||
lockdebug_dump(lwp_t *l, lockdebug_t *ld, void (*pr)(const char *, ...)
|
||||
__printflike(1, 2))
|
||||
{
|
||||
int sleeper = (ld->ld_flags & LD_SLEEPER);
|
||||
|
@ -761,13 +768,13 @@ lockdebug_dump(lockdebug_t *ld, void (*pr)(const char *, ...)
|
|||
(*pr)("\n"
|
||||
"shared holds : %18u exclusive: %18u\n"
|
||||
"shares wanted: %18u exclusive: %18u\n"
|
||||
"current cpu : %18u last held: %18u\n"
|
||||
"current lwp : %#018lx last held: %#018lx\n"
|
||||
"relevant cpu : %18u last held: %18u\n"
|
||||
"relevant lwp : %#018lx last held: %#018lx\n"
|
||||
"last locked%c : %#018lx unlocked%c: %#018lx\n",
|
||||
(unsigned)ld->ld_shares, ((ld->ld_flags & LD_LOCKED) != 0),
|
||||
(unsigned)ld->ld_shwant, (unsigned)ld->ld_exwant,
|
||||
(unsigned)cpu_index(curcpu()), (unsigned)ld->ld_cpu,
|
||||
(long)curlwp, (long)ld->ld_lwp,
|
||||
(unsigned)cpu_index(l->l_cpu), (unsigned)ld->ld_cpu,
|
||||
(long)l, (long)ld->ld_lwp,
|
||||
((ld->ld_flags & LD_LOCKED) ? '*' : ' '),
|
||||
(long)ld->ld_locked,
|
||||
((ld->ld_flags & LD_LOCKED) ? ' ' : '*'),
|
||||
|
@ -778,7 +785,6 @@ lockdebug_dump(lockdebug_t *ld, void (*pr)(const char *, ...)
|
|||
(*ld->ld_lockops->lo_dump)(ld->ld_lock, pr);
|
||||
|
||||
if (sleeper) {
|
||||
(*pr)("\n");
|
||||
turnstile_print(ld->ld_lock, pr);
|
||||
}
|
||||
}
|
||||
|
@ -806,7 +812,7 @@ lockdebug_abort1(const char *func, size_t line, lockdebug_t *ld, int s,
|
|||
|
||||
printf_nolog("%s error: %s,%zu: %s\n\n", ld->ld_lockops->lo_name,
|
||||
func, line, msg);
|
||||
lockdebug_dump(ld, printf_nolog);
|
||||
lockdebug_dump(curlwp, ld, printf_nolog);
|
||||
__cpu_simple_unlock(&ld->ld_spinlock);
|
||||
splx(s);
|
||||
printf_nolog("\n");
|
||||
|
@ -837,7 +843,7 @@ lockdebug_lock_print(void *addr,
|
|||
if (ld->ld_lock == NULL)
|
||||
continue;
|
||||
if (addr == NULL || ld->ld_lock == addr) {
|
||||
lockdebug_dump(ld, pr);
|
||||
lockdebug_dump(curlwp, ld, pr);
|
||||
if (addr != NULL)
|
||||
return;
|
||||
}
|
||||
|
@ -853,15 +859,15 @@ lockdebug_lock_print(void *addr,
|
|||
|
||||
#ifdef LOCKDEBUG
|
||||
static void
|
||||
lockdebug_show_one(lockdebug_t *ld, int i,
|
||||
lockdebug_show_one(lwp_t *l, lockdebug_t *ld, int i,
|
||||
void (*pr)(const char *, ...) __printflike(1, 2))
|
||||
{
|
||||
const char *sym;
|
||||
|
||||
ksyms_getname(NULL, &sym, (vaddr_t)ld->ld_initaddr,
|
||||
KSYMS_CLOSEST|KSYMS_PROC|KSYMS_ANY);
|
||||
(*pr)("Lock %d (initialized at %s)\n", i++, sym);
|
||||
lockdebug_dump(ld, pr);
|
||||
(*pr)("* Lock %d (initialized at %s)\n", i++, sym);
|
||||
lockdebug_dump(l, ld, pr);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -882,16 +888,34 @@ lockdebug_show_all_locks_lwp(void (*pr)(const char *, ...) __printflike(1, 2),
|
|||
LIST_FOREACH(l, &p->p_lwps, l_sibling) {
|
||||
lockdebug_t *ld;
|
||||
int i = 0;
|
||||
if (TAILQ_EMPTY(&l->l_ld_locks))
|
||||
continue;
|
||||
(*pr)("Locks held by an LWP (%s):\n",
|
||||
l->l_name ? l->l_name : p->p_comm);
|
||||
TAILQ_FOREACH(ld, &l->l_ld_locks, ld_chain) {
|
||||
lockdebug_show_one(ld, i++, pr);
|
||||
if (TAILQ_EMPTY(&l->l_ld_locks) &&
|
||||
l->l_ld_wanted == NULL) {
|
||||
continue;
|
||||
}
|
||||
if (show_trace)
|
||||
(*pr)("\n****** LWP %d.%d (%s) @ %p, l_stat=%d\n",
|
||||
p->p_pid, l->l_lid,
|
||||
l->l_name ? l->l_name : p->p_comm, l, l->l_stat);
|
||||
if (!TAILQ_EMPTY(&l->l_ld_locks)) {
|
||||
(*pr)("\n*** Locks held: \n");
|
||||
TAILQ_FOREACH(ld, &l->l_ld_locks, ld_chain) {
|
||||
(*pr)("\n");
|
||||
lockdebug_show_one(l, ld, i++, pr);
|
||||
}
|
||||
} else {
|
||||
(*pr)("\n*** Locks held: none\n");
|
||||
}
|
||||
|
||||
if (l->l_ld_wanted != NULL) {
|
||||
(*pr)("\n*** Locks wanted: \n\n");
|
||||
lockdebug_show_one(l, l->l_ld_wanted, 0, pr);
|
||||
} else {
|
||||
(*pr)("\n*** Locks wanted: none\n");
|
||||
}
|
||||
if (show_trace) {
|
||||
(*pr)("\n*** Traceback: \n\n");
|
||||
lockdebug_show_trace(l, pr);
|
||||
(*pr)("\n");
|
||||
(*pr)("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -908,16 +932,18 @@ lockdebug_show_all_locks_cpu(void (*pr)(const char *, ...) __printflike(1, 2),
|
|||
int i = 0;
|
||||
if (TAILQ_EMPTY(&ci->ci_data.cpu_ld_locks))
|
||||
continue;
|
||||
(*pr)("Locks held on CPU %u:\n", ci->ci_index);
|
||||
(*pr)("\n******* Locks held on %s:\n", cpu_name(ci));
|
||||
TAILQ_FOREACH(ld, &ci->ci_data.cpu_ld_locks, ld_chain) {
|
||||
lockdebug_show_one(ld, i++, pr);
|
||||
if (show_trace)
|
||||
(*pr)("\n");
|
||||
#ifdef MULTIPROCESSOR
|
||||
lockdebug_show_one(ci->ci_curlwp, ld, i++, pr);
|
||||
if (show_trace)
|
||||
lockdebug_show_trace(ci->ci_curlwp, pr);
|
||||
#else
|
||||
lockdebug_show_one(curlwp, ld, i++, pr);
|
||||
if (show_trace)
|
||||
lockdebug_show_trace(curlwp, pr);
|
||||
#endif
|
||||
(*pr)("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: lwp.h,v 1.196 2020/01/12 22:03:23 ad Exp $ */
|
||||
/* $NetBSD: lwp.h,v 1.197 2020/01/21 20:31:57 ad Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001, 2006, 2007, 2008, 2009, 2010, 2019
|
||||
|
@ -196,6 +196,7 @@ struct lwp {
|
|||
uintptr_t l_pfailaddr; /* !: for kernel preemption */
|
||||
uintptr_t l_pfaillock; /* !: for kernel preemption */
|
||||
_TAILQ_HEAD(,struct lockdebug,volatile) l_ld_locks;/* !: locks held by LWP */
|
||||
volatile void *l_ld_wanted; /* !: lock currently wanted by LWP */
|
||||
uintptr_t l_rwcallsite; /* !: rwlock actual callsite */
|
||||
int l_tcgen; /* !: for timecounter removal */
|
||||
|
||||
|
|
Loading…
Reference in New Issue