summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_mutex.c
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2001-03-28 09:03:24 +0000
committerjhb <jhb@FreeBSD.org>2001-03-28 09:03:24 +0000
commit0c490fd02e5b2a2764a94d809ef8be208b646e39 (patch)
tree57041654950234a1d3bb416540f96407a6127e19 /sys/kern/kern_mutex.c
parent3aabb22260cdd728828c80d2439d1ba623be5a51 (diff)
downloadFreeBSD-src-0c490fd02e5b2a2764a94d809ef8be208b646e39.zip
FreeBSD-src-0c490fd02e5b2a2764a94d809ef8be208b646e39.tar.gz
Rework the witness code to work with sx locks as well as mutexes.
- Introduce lock classes and lock objects. Each lock class specifies a name and set of flags (or properties) shared by all locks of a given type. Currently there are three lock classes: spin mutexes, sleep mutexes, and sx locks. A lock object specifies properties of an additional lock along with a lock name and all of the extra stuff needed to make witness work with a given lock. This abstract lock stuff is defined in sys/lock.h. The lockmgr constants, types, and prototypes have been moved to sys/lockmgr.h. For temporary backwards compatability, sys/lock.h includes sys/lockmgr.h. - Replace proc->p_spinlocks with a per-CPU list, PCPU(spinlocks), of spin locks held. By making this per-cpu, we do not have to jump through magic hoops to deal with sched_lock changing ownership during context switches. - Replace proc->p_heldmtx, formerly a list of held sleep mutexes, with proc->p_sleeplocks, which is a list of held sleep locks including sleep mutexes and sx locks. - Add helper macros for logging lock events via the KTR_LOCK KTR logging level so that the log messages are consistent. - Add some new flags that can be passed to mtx_init(): - MTX_NOWITNESS - specifies that this lock should be ignored by witness. This is used for the mutex that blocks a sx lock for example. - MTX_QUIET - this is not new, but you can pass this to mtx_init() now and no events will be logged for this lock, so that one doesn't have to change all the individual mtx_lock/unlock() operations. - All lock objects maintain an initialized flag. Use this flag to export a mtx_initialized() macro that can be safely called from drivers. Also, we on longer walk the all_mtx list if MUTEX_DEBUG is defined as witness performs the corresponding checks using the initialized flag. - The lock order reversal messages have been improved to output slightly more accurate file and line numbers.
Diffstat (limited to 'sys/kern/kern_mutex.c')
-rw-r--r--sys/kern/kern_mutex.c1242
1 files changed, 118 insertions, 1124 deletions
diff --git a/sys/kern/kern_mutex.c b/sys/kern/kern_mutex.c
index ee285af..ba2da45 100644
--- a/sys/kern/kern_mutex.c
+++ b/sys/kern/kern_mutex.c
@@ -56,12 +56,13 @@
*/
#include "opt_ddb.h"
-#include "opt_witness.h"
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
#include <sys/proc.h>
#include <sys/sysctl.h>
#include <sys/systm.h>
@@ -78,25 +79,6 @@
#include <vm/vm.h>
#include <vm/vm_extern.h>
-#include <sys/mutex.h>
-
-/*
- * The WITNESS-enabled mutex debug structure.
- */
-#ifdef WITNESS
-struct mtx_debug {
- struct witness *mtxd_witness;
- LIST_ENTRY(mtx) mtxd_held;
- const char *mtxd_file;
- int mtxd_line;
-};
-
-#define mtx_held mtx_debug->mtxd_held
-#define mtx_file mtx_debug->mtxd_file
-#define mtx_line mtx_debug->mtxd_line
-#define mtx_witness mtx_debug->mtxd_witness
-#endif /* WITNESS */
-
/*
* Internal utility macros.
*/
@@ -108,71 +90,19 @@ struct mtx_debug {
#define SET_PRIO(p, pri) (p)->p_pri.pri_level = (pri)
/*
- * Early WITNESS-enabled declarations.
- */
-#ifdef WITNESS
-
-/*
- * Internal WITNESS routines which must be prototyped early.
- *
- * XXX: When/if witness code is cleaned up, it would be wise to place all
- * witness prototyping early in this file.
- */
-static void witness_init(struct mtx *, int flag);
-static void witness_destroy(struct mtx *);
-static void witness_display(void(*)(const char *fmt, ...));
-
-MALLOC_DEFINE(M_WITNESS, "witness", "witness mtx_debug structure");
-
-/* All mutexes in system (used for debug/panic) */
-static struct mtx_debug all_mtx_debug = { NULL, {NULL, NULL}, NULL, 0 };
-
-/*
- * This global is set to 0 once it becomes safe to use the witness code.
- */
-static int witness_cold = 1;
-
-#else /* WITNESS */
-
-/* XXX XXX XXX
- * flag++ is sleazoid way of shuting up warning
- */
-#define witness_init(m, flag) flag++
-#define witness_destroy(m)
-#define witness_try_enter(m, t, f, l)
-#endif /* WITNESS */
-
-/*
- * All mutex locks in system are kept on the all_mtx list.
+ * Lock classes for sleep and spin mutexes.
*/
-static struct mtx all_mtx = { MTX_UNOWNED, 0, 0, 0, "All mutexes queue head",
- TAILQ_HEAD_INITIALIZER(all_mtx.mtx_blocked),
- { NULL, NULL }, &all_mtx, &all_mtx,
-#ifdef WITNESS
- &all_mtx_debug
-#else
- NULL
-#endif
- };
-
-/*
- * Global variables for book keeping.
- */
-static int mtx_cur_cnt;
-static int mtx_max_cnt;
-
-/*
- * Couple of strings for KTR_LOCK tracing in order to avoid duplicates.
- */
-char STR_mtx_lock_slp[] = "GOT (sleep) %s [%p] r=%d at %s:%d";
-char STR_mtx_unlock_slp[] = "REL (sleep) %s [%p] r=%d at %s:%d";
-char STR_mtx_lock_spn[] = "GOT (spin) %s [%p] r=%d at %s:%d";
-char STR_mtx_unlock_spn[] = "REL (spin) %s [%p] r=%d at %s:%d";
+struct lock_class lock_class_mtx_sleep = {
+ "sleep mutex",
+ LC_SLEEPLOCK | LC_RECURSABLE
+};
+struct lock_class lock_class_mtx_spin = {
+ "spin mutex",
+ LC_SPINLOCK | LC_RECURSABLE
+};
/*
* Prototypes for non-exported routines.
- *
- * NOTE: Prototypes for witness routines are placed at the bottom of the file.
*/
static void propagate_priority(struct proc *);
@@ -241,7 +171,7 @@ propagate_priority(struct proc *p)
KASSERT(p->p_stat == SMTX, (
"process %d(%s):%d holds %s but isn't blocked on a mutex\n",
p->p_pid, p->p_comm, p->p_stat,
- m->mtx_description));
+ m->mtx_object.lo_name));
/*
* Pick up the mutex that p is blocked on.
@@ -280,7 +210,7 @@ propagate_priority(struct proc *p)
TAILQ_INSERT_BEFORE(p1, p, p_procq);
CTR4(KTR_LOCK,
"propagate_priority: p %p moved before %p on [%p] %s",
- p, p1, m, m->mtx_description);
+ p, p1, m, m->mtx_object.lo_name);
}
}
@@ -336,23 +266,19 @@ _mtx_trylock(struct mtx *m, int opts, const char *file, int line)
rval = _obtain_lock(m, curproc);
-#ifdef WITNESS
- if (rval && m->mtx_witness != NULL) {
+ LOCK_LOG_TRY("LOCK", &m->mtx_object, opts, rval, file, line);
+ if (rval) {
/*
* We do not handle recursion in _mtx_trylock; see the
* note at the top of the routine.
*/
KASSERT(!mtx_recursed(m),
("mtx_trylock() called on a recursed mutex"));
- witness_try_enter(m, (opts | m->mtx_flags), file, line);
+ mtx_update_flags(m, 1);
+ WITNESS_LOCK(&m->mtx_object, opts | LOP_TRYLOCK, file, line);
}
-#endif /* WITNESS */
-
- if ((opts & MTX_QUIET) == 0)
- CTR5(KTR_LOCK, "TRY_LOCK %s [%p] result=%d at %s:%d",
- m->mtx_description, m, rval, file, line);
- return rval;
+ return (rval);
}
/*
@@ -369,15 +295,15 @@ _mtx_lock_sleep(struct mtx *m, int opts, const char *file, int line)
if ((m->mtx_lock & MTX_FLAGMASK) == (uintptr_t)p) {
m->mtx_recurse++;
atomic_set_ptr(&m->mtx_lock, MTX_RECURSED);
- if ((opts & MTX_QUIET) == 0)
+ if (LOCK_LOG_TEST(&m->mtx_object, opts))
CTR1(KTR_LOCK, "_mtx_lock_sleep: %p recursing", m);
return;
}
- if ((opts & MTX_QUIET) == 0)
+ if (LOCK_LOG_TEST(&m->mtx_object, opts))
CTR4(KTR_LOCK,
"_mtx_lock_sleep: %s contested (lock=%p) at %s:%d",
- m->mtx_description, (void *)m->mtx_lock, file, line);
+ m->mtx_object.lo_name, (void *)m->mtx_lock, file, line);
while (!_obtain_lock(m, p)) {
uintptr_t v;
@@ -434,7 +360,7 @@ _mtx_lock_sleep(struct mtx *m, int opts, const char *file, int line)
struct ithd *it = p->p_ithd;
if (it->it_interrupted) {
- if ((opts & MTX_QUIET) == 0)
+ if (LOCK_LOG_TEST(&m->mtx_object, opts))
CTR2(KTR_LOCK,
"_mtx_lock_sleep: %p interrupted %p",
it, it->it_interrupted);
@@ -464,21 +390,21 @@ _mtx_lock_sleep(struct mtx *m, int opts, const char *file, int line)
* Save who we're blocked on.
*/
p->p_blocked = m;
- p->p_mtxname = m->mtx_description;
+ p->p_mtxname = m->mtx_object.lo_name;
p->p_stat = SMTX;
propagate_priority(p);
- if ((opts & MTX_QUIET) == 0)
+ if (LOCK_LOG_TEST(&m->mtx_object, opts))
CTR3(KTR_LOCK,
"_mtx_lock_sleep: p %p blocked on [%p] %s", p, m,
- m->mtx_description);
+ m->mtx_object.lo_name);
mi_switch();
- if ((opts & MTX_QUIET) == 0)
+ if (LOCK_LOG_TEST(&m->mtx_object, opts))
CTR3(KTR_LOCK,
"_mtx_lock_sleep: p %p free from blocked on [%p] %s",
- p, m, m->mtx_description);
+ p, m, m->mtx_object.lo_name);
mtx_unlock_spin(&sched_lock);
}
@@ -498,7 +424,7 @@ _mtx_lock_spin(struct mtx *m, int opts, critical_t mtx_crit, const char *file,
{
int i = 0;
- if ((opts & MTX_QUIET) == 0)
+ if (LOCK_LOG_TEST(&m->mtx_object, opts))
CTR1(KTR_LOCK, "_mtx_lock_spin: %p spinning", m);
for (;;) {
@@ -516,12 +442,12 @@ _mtx_lock_spin(struct mtx *m, int opts, critical_t mtx_crit, const char *file,
else
#endif
panic("spin lock %s held by %p for > 5 seconds",
- m->mtx_description, (void *)m->mtx_lock);
+ m->mtx_object.lo_name, (void *)m->mtx_lock);
}
}
m->mtx_savecrit = mtx_crit;
- if ((opts & MTX_QUIET) == 0)
+ if (LOCK_LOG_TEST(&m->mtx_object, opts))
CTR1(KTR_LOCK, "_mtx_lock_spin: %p spin done", m);
return;
@@ -545,13 +471,13 @@ _mtx_unlock_sleep(struct mtx *m, int opts, const char *file, int line)
if (mtx_recursed(m)) {
if (--(m->mtx_recurse) == 0)
atomic_clear_ptr(&m->mtx_lock, MTX_RECURSED);
- if ((opts & MTX_QUIET) == 0)
+ if (LOCK_LOG_TEST(&m->mtx_object, opts))
CTR1(KTR_LOCK, "_mtx_unlock_sleep: %p unrecurse", m);
return;
}
mtx_lock_spin(&sched_lock);
- if ((opts & MTX_QUIET) == 0)
+ if (LOCK_LOG_TEST(&m->mtx_object, opts))
CTR1(KTR_LOCK, "_mtx_unlock_sleep: %p contested", m);
p1 = TAILQ_FIRST(&m->mtx_blocked);
@@ -563,7 +489,7 @@ _mtx_unlock_sleep(struct mtx *m, int opts, const char *file, int line)
if (TAILQ_EMPTY(&m->mtx_blocked)) {
LIST_REMOVE(m, mtx_contested);
_release_lock_quick(m);
- if ((opts & MTX_QUIET) == 0)
+ if (LOCK_LOG_TEST(&m->mtx_object, opts))
CTR1(KTR_LOCK, "_mtx_unlock_sleep: %p not held", m);
} else
atomic_store_rel_ptr(&m->mtx_lock, (void *)MTX_CONTESTED);
@@ -579,7 +505,7 @@ _mtx_unlock_sleep(struct mtx *m, int opts, const char *file, int line)
pri = p->p_pri.pri_native;
SET_PRIO(p, pri);
- if ((opts & MTX_QUIET) == 0)
+ if (LOCK_LOG_TEST(&m->mtx_object, opts))
CTR2(KTR_LOCK, "_mtx_unlock_sleep: %p contested setrunqueue %p",
m, p1);
@@ -593,7 +519,7 @@ _mtx_unlock_sleep(struct mtx *m, int opts, const char *file, int line)
struct ithd *it = p->p_ithd;
if (it->it_interrupted) {
- if ((opts & MTX_QUIET) == 0)
+ if (LOCK_LOG_TEST(&m->mtx_object, opts))
CTR2(KTR_LOCK,
"_mtx_unlock_sleep: %p interrupted %p",
it, it->it_interrupted);
@@ -602,13 +528,13 @@ _mtx_unlock_sleep(struct mtx *m, int opts, const char *file, int line)
}
#endif
setrunqueue(p);
- if ((opts & MTX_QUIET) == 0)
+ if (LOCK_LOG_TEST(&m->mtx_object, opts))
CTR2(KTR_LOCK,
"_mtx_unlock_sleep: %p switching out lock=%p", m,
(void *)m->mtx_lock);
mi_switch();
- if ((opts & MTX_QUIET) == 0)
+ if (LOCK_LOG_TEST(&m->mtx_object, opts))
CTR2(KTR_LOCK, "_mtx_unlock_sleep: %p resuming lock=%p",
m, (void *)m->mtx_lock);
}
@@ -623,6 +549,40 @@ _mtx_unlock_sleep(struct mtx *m, int opts, const char *file, int line)
* See the _rel_spin_lock() macro for the details.
*/
+#ifdef WITNESS
+/*
+ * Update the lock object flags before calling witness. Note that when we
+ * lock a mutex, this is called after getting the lock, but when unlocking
+ * a mutex, this function is called before releasing the lock.
+ */
+void
+_mtx_update_flags(struct mtx *m, int locking)
+{
+
+ mtx_assert(m, MA_OWNED);
+ if (locking) {
+ m->mtx_object.lo_flags |= LO_LOCKED;
+ if (mtx_recursed(m))
+ m->mtx_object.lo_flags |= LO_RECURSED;
+ else
+ /* XXX: we shouldn't need this in theory. */
+ m->mtx_object.lo_flags &= ~LO_RECURSED;
+ } else {
+ switch (m->mtx_recurse) {
+ case 0:
+ /* XXX: we shouldn't need the LO_RECURSED in theory. */
+ m->mtx_object.lo_flags &= ~(LO_LOCKED | LO_RECURSED);
+ break;
+ case 1:
+ m->mtx_object.lo_flags &= ~(LO_RECURSED);
+ break;
+ default:
+ break;
+ }
+ }
+}
+#endif
+
/*
* The backing function for the INVARIANTS-enabled mtx_assert()
*/
@@ -636,20 +596,20 @@ _mtx_assert(struct mtx *m, int what, const char *file, int line)
case MA_OWNED | MA_NOTRECURSED:
if (!mtx_owned(m))
panic("mutex %s not owned at %s:%d",
- m->mtx_description, file, line);
+ m->mtx_object.lo_name, file, line);
if (mtx_recursed(m)) {
if ((what & MA_NOTRECURSED) != 0)
panic("mutex %s recursed at %s:%d",
- m->mtx_description, file, line);
+ m->mtx_object.lo_name, file, line);
} else if ((what & MA_RECURSED) != 0) {
panic("mutex %s unrecursed at %s:%d",
- m->mtx_description, file, line);
+ m->mtx_object.lo_name, file, line);
}
break;
case MA_NOTOWNED:
if (mtx_owned(m))
panic("mutex %s owned at %s:%d",
- m->mtx_description, file, line);
+ m->mtx_object.lo_name, file, line);
break;
default:
panic("unknown mtx_assert at %s:%d", file, line);
@@ -659,1058 +619,92 @@ _mtx_assert(struct mtx *m, int what, const char *file, int line)
/*
* The MUTEX_DEBUG-enabled mtx_validate()
+ *
+ * Most of these checks have been moved off into the LO_INITIALIZED flag
+ * maintained by the witness code.
*/
-#define MV_DESTROY 0 /* validate before destory */
-#define MV_INIT 1 /* validate before init */
-
#ifdef MUTEX_DEBUG
-int mtx_validate __P((struct mtx *, int));
+void mtx_validate __P((struct mtx *));
-int
-mtx_validate(struct mtx *m, int when)
+void
+mtx_validate(struct mtx *m)
{
- struct mtx *mp;
- int i;
- int retval = 0;
-
-#ifdef WITNESS
- if (witness_cold)
- return 0;
-#endif
- if (m == &all_mtx || cold)
- return 0;
- mtx_lock(&all_mtx);
/*
* XXX - When kernacc() is fixed on the alpha to handle K0_SEG memory properly
* we can re-enable the kernacc() checks.
*/
#ifndef __alpha__
- MPASS(kernacc((caddr_t)all_mtx.mtx_next, sizeof(uintptr_t),
- VM_PROT_READ) == 1);
+ if (!kernacc((caddr_t)m, sizeof(m), VM_PROT_READ | VM_PROT_WRITE))
+ panic("Can't read and write to mutex %p", m);
#endif
- MPASS(all_mtx.mtx_next->mtx_prev == &all_mtx);
- for (i = 0, mp = all_mtx.mtx_next; mp != &all_mtx; mp = mp->mtx_next) {
-#ifndef __alpha__
- if (kernacc((caddr_t)mp->mtx_next, sizeof(uintptr_t),
- VM_PROT_READ) != 1) {
- panic("mtx_validate: mp=%p mp->mtx_next=%p",
- mp, mp->mtx_next);
- }
-#endif
- i++;
- if (i > mtx_cur_cnt) {
- panic("mtx_validate: too many in chain, known=%d\n",
- mtx_cur_cnt);
- }
- }
- MPASS(i == mtx_cur_cnt);
- switch (when) {
- case MV_DESTROY:
- for (mp = all_mtx.mtx_next; mp != &all_mtx; mp = mp->mtx_next)
- if (mp == m)
- break;
- MPASS(mp == m);
- break;
- case MV_INIT:
- for (mp = all_mtx.mtx_next; mp != &all_mtx; mp = mp->mtx_next)
- if (mp == m) {
- /*
- * Not good. This mutex already exists.
- */
- printf("re-initing existing mutex %s\n",
- m->mtx_description);
- MPASS(m->mtx_lock == MTX_UNOWNED);
- retval = 1;
- }
- }
- mtx_unlock(&all_mtx);
- return (retval);
}
#endif
/*
* Mutex initialization routine; initialize lock `m' of type contained in
* `opts' with options contained in `opts' and description `description.'
- * Place on "all_mtx" queue.
*/
void
mtx_init(struct mtx *m, const char *description, int opts)
{
+ struct lock_object *lock;
- if ((opts & MTX_QUIET) == 0)
- CTR2(KTR_LOCK, "mtx_init %p (%s)", m, description);
+ MPASS((opts & ~(MTX_SPIN | MTX_QUIET | MTX_RECURSE |
+ MTX_SLEEPABLE | MTX_NOWITNESS)) == 0);
#ifdef MUTEX_DEBUG
/* Diagnostic and error correction */
- if (mtx_validate(m, MV_INIT))
- return;
+ mtx_validate(m);
#endif
- bzero((void *)m, sizeof *m);
- TAILQ_INIT(&m->mtx_blocked);
+ bzero(m, sizeof(*m));
+ lock = &m->mtx_object;
+ if (opts & MTX_SPIN)
+ lock->lo_class = &lock_class_mtx_spin;
+ else
+ lock->lo_class = &lock_class_mtx_sleep;
+ lock->lo_name = description;
+ if (opts & MTX_QUIET)
+ lock->lo_flags = LO_QUIET;
+ if (opts & MTX_RECURSE)
+ lock->lo_flags |= LO_RECURSABLE;
+ if (opts & MTX_SLEEPABLE)
+ lock->lo_flags |= LO_SLEEPABLE;
+ if ((opts & MTX_NOWITNESS) == 0)
+ lock->lo_flags |= LO_WITNESS;
-#ifdef WITNESS
- if (!witness_cold) {
- m->mtx_debug = malloc(sizeof(struct mtx_debug),
- M_WITNESS, M_NOWAIT | M_ZERO);
- MPASS(m->mtx_debug != NULL);
- }
-#endif
-
- m->mtx_description = description;
- m->mtx_flags = opts;
m->mtx_lock = MTX_UNOWNED;
+ TAILQ_INIT(&m->mtx_blocked);
- /* Put on all mutex queue */
- mtx_lock(&all_mtx);
- m->mtx_next = &all_mtx;
- m->mtx_prev = all_mtx.mtx_prev;
- m->mtx_prev->mtx_next = m;
- all_mtx.mtx_prev = m;
- if (++mtx_cur_cnt > mtx_max_cnt)
- mtx_max_cnt = mtx_cur_cnt;
- mtx_unlock(&all_mtx);
+ LOCK_LOG_INIT(lock, opts);
-#ifdef WITNESS
- if (!witness_cold)
- witness_init(m, opts);
-#endif
+ WITNESS_INIT(lock);
}
/*
- * Remove lock `m' from all_mtx queue.
+ * Remove lock `m' from all_mtx queue. We don't allow MTX_QUIET to be
+ * passed in as a flag here because if the corresponding mtx_init() was
+ * called with MTX_QUIET set, then it will already be set in the mutex's
+ * flags.
*/
void
mtx_destroy(struct mtx *m)
{
-#ifdef WITNESS
- KASSERT(!witness_cold, ("%s: Cannot destroy while still cold\n",
- __FUNCTION__));
-#endif
-
- CTR2(KTR_LOCK, "mtx_destroy %p (%s)", m, m->mtx_description);
-
-#ifdef MUTEX_DEBUG
- if (m->mtx_next == NULL)
- panic("mtx_destroy: %p (%s) already destroyed",
- m, m->mtx_description);
+ LOCK_LOG_DESTROY(&m->mtx_object, 0);
- if (!mtx_owned(m)) {
- MPASS(m->mtx_lock == MTX_UNOWNED);
- } else {
+ if (!mtx_owned(m))
+ MPASS(mtx_unowned(m));
+ else {
MPASS((m->mtx_lock & (MTX_RECURSED|MTX_CONTESTED)) == 0);
- }
-
- /* diagnostic */
- mtx_validate(m, MV_DESTROY);
-#endif
-
-#ifdef WITNESS
- if (m->mtx_witness)
- witness_destroy(m);
-#endif /* WITNESS */
-
- /* Remove from the all mutex queue */
- mtx_lock(&all_mtx);
- m->mtx_next->mtx_prev = m->mtx_prev;
- m->mtx_prev->mtx_next = m->mtx_next;
-
-#ifdef MUTEX_DEBUG
- m->mtx_next = m->mtx_prev = NULL;
-#endif
-
-#ifdef WITNESS
- free(m->mtx_debug, M_WITNESS);
- m->mtx_debug = NULL;
-#endif
-
- mtx_cur_cnt--;
- mtx_unlock(&all_mtx);
-}
-
-
-/*
- * The WITNESS-enabled diagnostic code.
- */
-#ifdef WITNESS
-static void
-witness_fixup(void *dummy __unused)
-{
- struct mtx *mp;
-
- /*
- * We have to release Giant before initializing its witness
- * structure so that WITNESS doesn't get confused.
- */
- mtx_unlock(&Giant);
- mtx_assert(&Giant, MA_NOTOWNED);
-
- mtx_lock(&all_mtx);
-
- /* Iterate through all mutexes and finish up mutex initialization. */
- for (mp = all_mtx.mtx_next; mp != &all_mtx; mp = mp->mtx_next) {
-
- mp->mtx_debug = malloc(sizeof(struct mtx_debug),
- M_WITNESS, M_NOWAIT | M_ZERO);
- MPASS(mp->mtx_debug != NULL);
-
- witness_init(mp, mp->mtx_flags);
- }
- mtx_unlock(&all_mtx);
-
- /* Mark the witness code as being ready for use. */
- atomic_store_rel_int(&witness_cold, 0);
-
- mtx_lock(&Giant);
-}
-SYSINIT(wtnsfxup, SI_SUB_MUTEX, SI_ORDER_FIRST, witness_fixup, NULL)
-
-#define WITNESS_COUNT 200
-#define WITNESS_NCHILDREN 2
-
-int witness_watch = 1;
-
-struct witness {
- struct witness *w_next;
- const char *w_description;
- const char *w_file;
- int w_line;
- struct witness *w_morechildren;
- u_char w_childcnt;
- u_char w_Giant_squawked:1;
- u_char w_other_squawked:1;
- u_char w_same_squawked:1;
- u_char w_spin:1; /* MTX_SPIN type mutex. */
- u_int w_level;
- struct witness *w_children[WITNESS_NCHILDREN];
-};
-
-struct witness_blessed {
- char *b_lock1;
- char *b_lock2;
-};
-
-#ifdef DDB
-/*
- * When DDB is enabled and witness_ddb is set to 1, it will cause the system to
- * drop into kdebug() when:
- * - a lock heirarchy violation occurs
- * - locks are held when going to sleep.
- */
-int witness_ddb;
-#ifdef WITNESS_DDB
-TUNABLE_INT_DECL("debug.witness_ddb", 1, witness_ddb);
-#else
-TUNABLE_INT_DECL("debug.witness_ddb", 0, witness_ddb);
-#endif
-SYSCTL_INT(_debug, OID_AUTO, witness_ddb, CTLFLAG_RW, &witness_ddb, 0, "");
-#endif /* DDB */
-
-int witness_skipspin;
-#ifdef WITNESS_SKIPSPIN
-TUNABLE_INT_DECL("debug.witness_skipspin", 1, witness_skipspin);
-#else
-TUNABLE_INT_DECL("debug.witness_skipspin", 0, witness_skipspin);
-#endif
-SYSCTL_INT(_debug, OID_AUTO, witness_skipspin, CTLFLAG_RD, &witness_skipspin, 0,
- "");
-
-/*
- * Witness-enabled globals
- */
-static struct mtx w_mtx;
-static struct witness *w_free;
-static struct witness *w_all;
-static int w_inited;
-static int witness_dead; /* fatal error, probably no memory */
-
-static struct witness w_data[WITNESS_COUNT];
-
-/*
- * Internal witness routine prototypes
- */
-static struct witness *enroll(const char *description, int flag);
-static int itismychild(struct witness *parent, struct witness *child);
-static void removechild(struct witness *parent, struct witness *child);
-static int isitmychild(struct witness *parent, struct witness *child);
-static int isitmydescendant(struct witness *parent, struct witness *child);
-static int dup_ok(struct witness *);
-static int blessed(struct witness *, struct witness *);
-static void
- witness_displaydescendants(void(*)(const char *fmt, ...), struct witness *);
-static void witness_leveldescendents(struct witness *parent, int level);
-static void witness_levelall(void);
-static struct witness * witness_get(void);
-static void witness_free(struct witness *m);
-
-static char *ignore_list[] = {
- "witness lock",
- NULL
-};
-
-static char *spin_order_list[] = {
-#if defined(__i386__) && defined (SMP)
- "com",
-#endif
- "sio",
-#ifdef __i386__
- "cy",
-#endif
- "ng_node",
- "ng_worklist",
- "ithread table lock",
- "ithread list lock",
- "sched lock",
-#ifdef __i386__
- "clk",
-#endif
- "callout",
- /*
- * leaf locks
- */
-#ifdef SMP
-#ifdef __i386__
- "ap boot",
- "imen",
-#endif
- "smp rendezvous",
-#endif
- NULL
-};
-
-static char *order_list[] = {
- "Giant", "proctree", "allproc", "process lock", "uidinfo hash",
- "uidinfo struct", NULL,
- NULL
-};
-static char *dup_list[] = {
- "process lock",
- NULL
-};
-
-static char *sleep_list[] = {
- "Giant",
- NULL
-};
-
-/*
- * Pairs of locks which have been blessed
- * Don't complain about order problems with blessed locks
- */
-static struct witness_blessed blessed_list[] = {
-};
-static int blessed_count =
- sizeof(blessed_list) / sizeof(struct witness_blessed);
-
-static void
-witness_init(struct mtx *m, int flag)
-{
- m->mtx_witness = enroll(m->mtx_description, flag);
-}
-
-static void
-witness_destroy(struct mtx *m)
-{
- struct mtx *m1;
- struct proc *p;
- p = curproc;
- LIST_FOREACH(m1, &p->p_heldmtx, mtx_held) {
- if (m1 == m) {
- LIST_REMOVE(m, mtx_held);
- break;
- }
+ /* Tell witness this isn't locked to make it happy. */
+ m->mtx_object.lo_flags &= ~LO_LOCKED;
+ WITNESS_UNLOCK(&m->mtx_object, MTX_NOSWITCH, __FILE__,
+ __LINE__);
}
- return;
+ WITNESS_DESTROY(&m->mtx_object);
}
-
-static void
-witness_display(void(*prnt)(const char *fmt, ...))
-{
- struct witness *w, *w1;
- int level, found;
-
- KASSERT(!witness_cold, ("%s: witness_cold\n", __FUNCTION__));
- witness_levelall();
-
- /*
- * First, handle sleep mutexes which have been acquired at least
- * once.
- */
- prnt("Sleep mutexes:\n");
- for (w = w_all; w; w = w->w_next) {
- if (w->w_file == NULL || w->w_spin)
- continue;
- for (w1 = w_all; w1; w1 = w1->w_next) {
- if (isitmychild(w1, w))
- break;
- }
- if (w1 != NULL)
- continue;
- /*
- * This lock has no anscestors, display its descendants.
- */
- witness_displaydescendants(prnt, w);
- }
-
- /*
- * Now do spin mutexes which have been acquired at least once.
- */
- prnt("\nSpin mutexes:\n");
- level = 0;
- while (level < sizeof(spin_order_list) / sizeof(char *)) {
- found = 0;
- for (w = w_all; w; w = w->w_next) {
- if (w->w_file == NULL || !w->w_spin)
- continue;
- if (w->w_level == 1 << level) {
- witness_displaydescendants(prnt, w);
- level++;
- found = 1;
- }
- }
- if (found == 0)
- level++;
- }
-
- /*
- * Finally, any mutexes which have not been acquired yet.
- */
- prnt("\nMutexes which were never acquired:\n");
- for (w = w_all; w; w = w->w_next) {
- if (w->w_file != NULL)
- continue;
- prnt("%s\n", w->w_description);
- }
-}
-
-void
-witness_enter(struct mtx *m, int flags, const char *file, int line)
-{
- struct witness *w, *w1;
- struct mtx *m1;
- struct proc *p;
- int i;
-#ifdef DDB
- int go_into_ddb = 0;
-#endif /* DDB */
-
- if (witness_cold || m->mtx_witness == NULL || panicstr)
- return;
- w = m->mtx_witness;
- p = curproc;
-
- if (flags & MTX_SPIN) {
- if ((m->mtx_flags & MTX_SPIN) == 0)
- panic("mutex_enter: MTX_SPIN on MTX_DEF mutex %s @"
- " %s:%d", m->mtx_description, file, line);
- if (mtx_recursed(m)) {
- if ((m->mtx_flags & MTX_RECURSE) == 0)
- panic("mutex_enter: recursion on non-recursive"
- " mutex %s @ %s:%d", m->mtx_description,
- file, line);
- return;
- }
- mtx_lock_spin_flags(&w_mtx, MTX_QUIET);
- i = PCPU_GET(witness_spin_check);
- if (i != 0 && w->w_level < i) {
- mtx_unlock_spin_flags(&w_mtx, MTX_QUIET);
- panic("mutex_enter(%s:%x, MTX_SPIN) out of order @"
- " %s:%d already holding %s:%x",
- m->mtx_description, w->w_level, file, line,
- spin_order_list[ffs(i)-1], i);
- }
- PCPU_SET(witness_spin_check, i | w->w_level);
- mtx_unlock_spin_flags(&w_mtx, MTX_QUIET);
- p->p_spinlocks++;
- MPASS(p->p_spinlocks > 0);
- w->w_file = file;
- w->w_line = line;
- m->mtx_line = line;
- m->mtx_file = file;
- return;
- }
- if ((m->mtx_flags & MTX_SPIN) != 0)
- panic("mutex_enter: MTX_DEF on MTX_SPIN mutex %s @ %s:%d",
- m->mtx_description, file, line);
-
- if (mtx_recursed(m)) {
- if ((m->mtx_flags & MTX_RECURSE) == 0)
- panic("mutex_enter: recursion on non-recursive"
- " mutex %s @ %s:%d", m->mtx_description,
- file, line);
- return;
- }
- if (witness_dead)
- goto out;
- if (cold)
- goto out;
-
- if (p->p_spinlocks != 0)
- panic("blockable mtx_lock() of %s when not legal @ %s:%d",
- m->mtx_description, file, line);
- /*
- * Is this the first mutex acquired
- */
- if ((m1 = LIST_FIRST(&p->p_heldmtx)) == NULL)
- goto out;
-
- if ((w1 = m1->mtx_witness) == w) {
- if (w->w_same_squawked || dup_ok(w))
- goto out;
- w->w_same_squawked = 1;
- printf("acquring duplicate lock of same type: \"%s\"\n",
- m->mtx_description);
- printf(" 1st @ %s:%d\n", w->w_file, w->w_line);
- printf(" 2nd @ %s:%d\n", file, line);
-#ifdef DDB
- go_into_ddb = 1;
-#endif /* DDB */
- goto out;
- }
- MPASS(!mtx_owned(&w_mtx));
- mtx_lock_spin_flags(&w_mtx, MTX_QUIET);
- /*
- * If we have a known higher number just say ok
- */
- if (witness_watch > 1 && w->w_level > w1->w_level) {
- mtx_unlock_spin_flags(&w_mtx, MTX_QUIET);
- goto out;
- }
- if (isitmydescendant(m1->mtx_witness, w)) {
- mtx_unlock_spin_flags(&w_mtx, MTX_QUIET);
- goto out;
- }
- for (i = 0; m1 != NULL; m1 = LIST_NEXT(m1, mtx_held), i++) {
-
- MPASS(i < 200);
- w1 = m1->mtx_witness;
- if (isitmydescendant(w, w1)) {
- mtx_unlock_spin_flags(&w_mtx, MTX_QUIET);
- if (blessed(w, w1))
- goto out;
- if (m1 == &Giant) {
- if (w1->w_Giant_squawked)
- goto out;
- else
- w1->w_Giant_squawked = 1;
- } else {
- if (w1->w_other_squawked)
- goto out;
- else
- w1->w_other_squawked = 1;
- }
- printf("lock order reversal\n");
- printf(" 1st %s last acquired @ %s:%d\n",
- w->w_description, w->w_file, w->w_line);
- printf(" 2nd %p %s @ %s:%d\n",
- m1, w1->w_description, w1->w_file, w1->w_line);
- printf(" 3rd %p %s @ %s:%d\n",
- m, w->w_description, file, line);
-#ifdef DDB
- go_into_ddb = 1;
-#endif /* DDB */
- goto out;
- }
- }
- m1 = LIST_FIRST(&p->p_heldmtx);
- if (!itismychild(m1->mtx_witness, w))
- mtx_unlock_spin_flags(&w_mtx, MTX_QUIET);
-
-out:
-#ifdef DDB
- if (witness_ddb && go_into_ddb)
- Debugger("witness_enter");
-#endif /* DDB */
- w->w_file = file;
- w->w_line = line;
- m->mtx_line = line;
- m->mtx_file = file;
-
- /*
- * If this pays off it likely means that a mutex being witnessed
- * is acquired in hardclock. Put it in the ignore list. It is
- * likely not the mutex this assert fails on.
- */
- MPASS(m->mtx_held.le_prev == NULL);
- LIST_INSERT_HEAD(&p->p_heldmtx, (struct mtx*)m, mtx_held);
-}
-
-void
-witness_try_enter(struct mtx *m, int flags, const char *file, int line)
-{
- struct proc *p;
- struct witness *w = m->mtx_witness;
-
- if (witness_cold)
- return;
- if (panicstr)
- return;
- if (flags & MTX_SPIN) {
- if ((m->mtx_flags & MTX_SPIN) == 0)
- panic("mutex_try_enter: "
- "MTX_SPIN on MTX_DEF mutex %s @ %s:%d",
- m->mtx_description, file, line);
- if (mtx_recursed(m)) {
- if ((m->mtx_flags & MTX_RECURSE) == 0)
- panic("mutex_try_enter: recursion on"
- " non-recursive mutex %s @ %s:%d",
- m->mtx_description, file, line);
- return;
- }
- mtx_lock_spin_flags(&w_mtx, MTX_QUIET);
- PCPU_SET(witness_spin_check,
- PCPU_GET(witness_spin_check) | w->w_level);
- mtx_unlock_spin_flags(&w_mtx, MTX_QUIET);
- w->w_file = file;
- w->w_line = line;
- m->mtx_line = line;
- m->mtx_file = file;
- return;
- }
-
- if ((m->mtx_flags & MTX_SPIN) != 0)
- panic("mutex_try_enter: MTX_DEF on MTX_SPIN mutex %s @ %s:%d",
- m->mtx_description, file, line);
-
- if (mtx_recursed(m)) {
- if ((m->mtx_flags & MTX_RECURSE) == 0)
- panic("mutex_try_enter: recursion on non-recursive"
- " mutex %s @ %s:%d", m->mtx_description, file,
- line);
- return;
- }
- w->w_file = file;
- w->w_line = line;
- m->mtx_line = line;
- m->mtx_file = file;
- p = curproc;
- MPASS(m->mtx_held.le_prev == NULL);
- LIST_INSERT_HEAD(&p->p_heldmtx, (struct mtx*)m, mtx_held);
-}
-
-void
-witness_exit(struct mtx *m, int flags, const char *file, int line)
-{
- struct witness *w;
- struct proc *p;
-
- if (witness_cold || m->mtx_witness == NULL || panicstr)
- return;
- w = m->mtx_witness;
- p = curproc;
-
- if (flags & MTX_SPIN) {
- if ((m->mtx_flags & MTX_SPIN) == 0)
- panic("mutex_exit: MTX_SPIN on MTX_DEF mutex %s @"
- " %s:%d", m->mtx_description, file, line);
- if (mtx_recursed(m)) {
- if ((m->mtx_flags & MTX_RECURSE) == 0)
- panic("mutex_exit: recursion on non-recursive"
- " mutex %s @ %s:%d", m->mtx_description,
- file, line);
- return;
- }
- mtx_lock_spin_flags(&w_mtx, MTX_QUIET);
- PCPU_SET(witness_spin_check,
- PCPU_GET(witness_spin_check) & ~w->w_level);
- mtx_unlock_spin_flags(&w_mtx, MTX_QUIET);
- MPASS(p->p_spinlocks > 0);
- p->p_spinlocks--;
- return;
- }
- if ((m->mtx_flags & MTX_SPIN) != 0)
- panic("mutex_exit: MTX_DEF on MTX_SPIN mutex %s @ %s:%d",
- m->mtx_description, file, line);
-
- if (mtx_recursed(m)) {
- if ((m->mtx_flags & MTX_RECURSE) == 0)
- panic("mutex_exit: recursion on non-recursive"
- " mutex %s @ %s:%d", m->mtx_description,
- file, line);
- return;
- }
-
- if ((flags & MTX_NOSWITCH) == 0 && p->p_spinlocks != 0 && !cold)
- panic("switchable mtx_unlock() of %s when not legal @ %s:%d",
- m->mtx_description, file, line);
- LIST_REMOVE(m, mtx_held);
- m->mtx_held.le_prev = NULL;
-}
-
-int
-witness_sleep(int check_only, struct mtx *mtx, const char *file, int line)
-{
- struct mtx *m;
- struct proc *p;
- char **sleep;
- int n = 0;
-
- KASSERT(!witness_cold, ("%s: witness_cold\n", __FUNCTION__));
- p = curproc;
- LIST_FOREACH(m, &p->p_heldmtx, mtx_held) {
- if (m == mtx)
- continue;
- for (sleep = sleep_list; *sleep!= NULL; sleep++)
- if (strcmp(m->mtx_description, *sleep) == 0)
- goto next;
- if (n == 0)
- printf("Whee!\n");
- printf("%s:%d: %s with \"%s\" locked from %s:%d\n",
- file, line, check_only ? "could sleep" : "sleeping",
- m->mtx_description,
- m->mtx_witness->w_file, m->mtx_witness->w_line);
- n++;
- next:
- }
-#ifdef DDB
- if (witness_ddb && n)
- Debugger("witness_sleep");
-#endif /* DDB */
- return (n);
-}
-
-static struct witness *
-enroll(const char *description, int flag)
-{
- int i;
- struct witness *w, *w1;
- char **ignore;
- char **order;
-
- if (!witness_watch)
- return (NULL);
- for (ignore = ignore_list; *ignore != NULL; ignore++)
- if (strcmp(description, *ignore) == 0)
- return (NULL);
-
- if (w_inited == 0) {
- mtx_init(&w_mtx, "witness lock", MTX_SPIN);
- for (i = 0; i < WITNESS_COUNT; i++) {
- w = &w_data[i];
- witness_free(w);
- }
- w_inited = 1;
- for (order = order_list; *order != NULL; order++) {
- w = enroll(*order, MTX_DEF);
- w->w_file = "order list";
- for (order++; *order != NULL; order++) {
- w1 = enroll(*order, MTX_DEF);
- w1->w_file = "order list";
- itismychild(w, w1);
- w = w1;
- }
- }
- }
- if ((flag & MTX_SPIN) && witness_skipspin)
- return (NULL);
- mtx_lock_spin_flags(&w_mtx, MTX_QUIET);
- for (w = w_all; w; w = w->w_next) {
- if (strcmp(description, w->w_description) == 0) {
- mtx_unlock_spin_flags(&w_mtx, MTX_QUIET);
- return (w);
- }
- }
- if ((w = witness_get()) == NULL)
- return (NULL);
- w->w_next = w_all;
- w_all = w;
- w->w_description = description;
- mtx_unlock_spin_flags(&w_mtx, MTX_QUIET);
- if (flag & MTX_SPIN) {
- w->w_spin = 1;
-
- i = 1;
- for (order = spin_order_list; *order != NULL; order++) {
- if (strcmp(description, *order) == 0)
- break;
- i <<= 1;
- }
- if (*order == NULL)
- panic("spin lock %s not in order list", description);
- w->w_level = i;
- }
-
- return (w);
-}
-
-static int
-itismychild(struct witness *parent, struct witness *child)
-{
- static int recursed;
-
- /*
- * Insert "child" after "parent"
- */
- while (parent->w_morechildren)
- parent = parent->w_morechildren;
-
- if (parent->w_childcnt == WITNESS_NCHILDREN) {
- if ((parent->w_morechildren = witness_get()) == NULL)
- return (1);
- parent = parent->w_morechildren;
- }
- MPASS(child != NULL);
- parent->w_children[parent->w_childcnt++] = child;
- /*
- * now prune whole tree
- */
- if (recursed)
- return (0);
- recursed = 1;
- for (child = w_all; child != NULL; child = child->w_next) {
- for (parent = w_all; parent != NULL;
- parent = parent->w_next) {
- if (!isitmychild(parent, child))
- continue;
- removechild(parent, child);
- if (isitmydescendant(parent, child))
- continue;
- itismychild(parent, child);
- }
- }
- recursed = 0;
- witness_levelall();
- return (0);
-}
-
-static void
-removechild(struct witness *parent, struct witness *child)
-{
- struct witness *w, *w1;
- int i;
-
- for (w = parent; w != NULL; w = w->w_morechildren)
- for (i = 0; i < w->w_childcnt; i++)
- if (w->w_children[i] == child)
- goto found;
- return;
-found:
- for (w1 = w; w1->w_morechildren != NULL; w1 = w1->w_morechildren)
- continue;
- w->w_children[i] = w1->w_children[--w1->w_childcnt];
- MPASS(w->w_children[i] != NULL);
-
- if (w1->w_childcnt != 0)
- return;
-
- if (w1 == parent)
- return;
- for (w = parent; w->w_morechildren != w1; w = w->w_morechildren)
- continue;
- w->w_morechildren = 0;
- witness_free(w1);
-}
-
-static int
-isitmychild(struct witness *parent, struct witness *child)
-{
- struct witness *w;
- int i;
-
- for (w = parent; w != NULL; w = w->w_morechildren) {
- for (i = 0; i < w->w_childcnt; i++) {
- if (w->w_children[i] == child)
- return (1);
- }
- }
- return (0);
-}
-
-static int
-isitmydescendant(struct witness *parent, struct witness *child)
-{
- struct witness *w;
- int i;
- int j;
-
- for (j = 0, w = parent; w != NULL; w = w->w_morechildren, j++) {
- MPASS(j < 1000);
- for (i = 0; i < w->w_childcnt; i++) {
- if (w->w_children[i] == child)
- return (1);
- }
- for (i = 0; i < w->w_childcnt; i++) {
- if (isitmydescendant(w->w_children[i], child))
- return (1);
- }
- }
- return (0);
-}
-
-void
-witness_levelall (void)
-{
- struct witness *w, *w1;
-
- for (w = w_all; w; w = w->w_next)
- if (!(w->w_spin))
- w->w_level = 0;
- for (w = w_all; w; w = w->w_next) {
- if (w->w_spin)
- continue;
- for (w1 = w_all; w1; w1 = w1->w_next) {
- if (isitmychild(w1, w))
- break;
- }
- if (w1 != NULL)
- continue;
- witness_leveldescendents(w, 0);
- }
-}
-
-static void
-witness_leveldescendents(struct witness *parent, int level)
-{
- int i;
- struct witness *w;
-
- if (parent->w_level < level)
- parent->w_level = level;
- level++;
- for (w = parent; w != NULL; w = w->w_morechildren)
- for (i = 0; i < w->w_childcnt; i++)
- witness_leveldescendents(w->w_children[i], level);
-}
-
-static void
-witness_displaydescendants(void(*prnt)(const char *fmt, ...),
- struct witness *parent)
-{
- struct witness *w;
- int i;
- int level;
-
- level = parent->w_spin ? ffs(parent->w_level) : parent->w_level;
-
- prnt("%d", level);
- if (level < 10)
- prnt(" ");
- for (i = 0; i < level; i++)
- prnt(" ");
- prnt("%s", parent->w_description);
- if (parent->w_file != NULL)
- prnt(" -- last acquired @ %s:%d\n", parent->w_file,
- parent->w_line);
-
- for (w = parent; w != NULL; w = w->w_morechildren)
- for (i = 0; i < w->w_childcnt; i++)
- witness_displaydescendants(prnt, w->w_children[i]);
- }
-
-static int
-dup_ok(struct witness *w)
-{
- char **dup;
-
- for (dup = dup_list; *dup!= NULL; dup++)
- if (strcmp(w->w_description, *dup) == 0)
- return (1);
- return (0);
-}
-
-static int
-blessed(struct witness *w1, struct witness *w2)
-{
- int i;
- struct witness_blessed *b;
-
- for (i = 0; i < blessed_count; i++) {
- b = &blessed_list[i];
- if (strcmp(w1->w_description, b->b_lock1) == 0) {
- if (strcmp(w2->w_description, b->b_lock2) == 0)
- return (1);
- continue;
- }
- if (strcmp(w1->w_description, b->b_lock2) == 0)
- if (strcmp(w2->w_description, b->b_lock1) == 0)
- return (1);
- }
- return (0);
-}
-
-static struct witness *
-witness_get()
-{
- struct witness *w;
-
- if ((w = w_free) == NULL) {
- witness_dead = 1;
- mtx_unlock_spin_flags(&w_mtx, MTX_QUIET);
- printf("witness exhausted\n");
- return (NULL);
- }
- w_free = w->w_next;
- bzero(w, sizeof(*w));
- return (w);
-}
-
-static void
-witness_free(struct witness *w)
-{
- w->w_next = w_free;
- w_free = w;
-}
-
-int
-witness_list(struct proc *p)
-{
- struct mtx *m;
- int nheld;
-
- KASSERT(!witness_cold, ("%s: witness_cold\n", __FUNCTION__));
- nheld = 0;
- LIST_FOREACH(m, &p->p_heldmtx, mtx_held) {
- printf("\t\"%s\" (%p) locked at %s:%d\n",
- m->mtx_description, m,
- m->mtx_witness->w_file, m->mtx_witness->w_line);
- nheld++;
- }
-
- return (nheld);
-}
-
-#ifdef DDB
-
-DB_SHOW_COMMAND(mutexes, db_witness_list)
-{
-
- witness_list(curproc);
-}
-
-DB_SHOW_COMMAND(witness, db_witness_display)
-{
-
- witness_display(db_printf);
-}
-#endif
-
-void
-witness_save(struct mtx *m, const char **filep, int *linep)
-{
-
- KASSERT(!witness_cold, ("%s: witness_cold\n", __FUNCTION__));
- if (m->mtx_witness == NULL)
- return;
-
- *filep = m->mtx_witness->w_file;
- *linep = m->mtx_witness->w_line;
-}
-
-void
-witness_restore(struct mtx *m, const char *file, int line)
-{
-
- KASSERT(!witness_cold, ("%s: witness_cold\n", __FUNCTION__));
- if (m->mtx_witness == NULL)
- return;
-
- m->mtx_witness->w_file = file;
- m->mtx_witness->w_line = line;
-}
-
-#endif /* WITNESS */
OpenPOWER on IntegriCloud