xref: /freebsd/sys/kern/kern_mutex.c (revision 9c36c934a108cfbbbb68f69ce8d3b91ffcbaa6a7)
10384fff8SJason Evans /*-
20384fff8SJason Evans  * Copyright (c) 1998 Berkeley Software Design, Inc. All rights reserved.
30384fff8SJason Evans  *
40384fff8SJason Evans  * Redistribution and use in source and binary forms, with or without
50384fff8SJason Evans  * modification, are permitted provided that the following conditions
60384fff8SJason Evans  * are met:
70384fff8SJason Evans  * 1. Redistributions of source code must retain the above copyright
80384fff8SJason Evans  *    notice, this list of conditions and the following disclaimer.
90384fff8SJason Evans  * 2. Redistributions in binary form must reproduce the above copyright
100384fff8SJason Evans  *    notice, this list of conditions and the following disclaimer in the
110384fff8SJason Evans  *    documentation and/or other materials provided with the distribution.
120384fff8SJason Evans  * 3. Berkeley Software Design Inc's name may not be used to endorse or
130384fff8SJason Evans  *    promote products derived from this software without specific prior
140384fff8SJason Evans  *    written permission.
150384fff8SJason Evans  *
160384fff8SJason Evans  * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN INC ``AS IS'' AND
170384fff8SJason Evans  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
180384fff8SJason Evans  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
190384fff8SJason Evans  * ARE DISCLAIMED.  IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN INC BE LIABLE
200384fff8SJason Evans  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
210384fff8SJason Evans  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
220384fff8SJason Evans  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
230384fff8SJason Evans  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
240384fff8SJason Evans  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
250384fff8SJason Evans  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
260384fff8SJason Evans  * SUCH DAMAGE.
270384fff8SJason Evans  *
280384fff8SJason Evans  *	from BSDI $Id: mutex_witness.c,v 1.1.2.20 2000/04/27 03:10:27 cp Exp $
2936412d79SJohn Baldwin  *	and BSDI $Id: synch_machdep.c,v 2.3.2.39 2000/04/27 03:10:25 cp Exp $
300384fff8SJason Evans  * $FreeBSD$
310384fff8SJason Evans  */
320384fff8SJason Evans 
330384fff8SJason Evans /*
340384fff8SJason Evans  *	Main Entry: witness
350384fff8SJason Evans  *	Pronunciation: 'wit-n&s
360384fff8SJason Evans  *	Function: noun
370384fff8SJason Evans  *	Etymology: Middle English witnesse, from Old English witnes knowledge,
380384fff8SJason Evans  *	    testimony, witness, from 2wit
390384fff8SJason Evans  *	Date: before 12th century
400384fff8SJason Evans  *	1 : attestation of a fact or event : TESTIMONY
410384fff8SJason Evans  *	2 : one that gives evidence; specifically : one who testifies in
420384fff8SJason Evans  *	    a cause or before a judicial tribunal
430384fff8SJason Evans  *	3 : one asked to be present at a transaction so as to be able to
440384fff8SJason Evans  *	    testify to its having taken place
450384fff8SJason Evans  *	4 : one who has personal knowledge of something
460384fff8SJason Evans  *	5 a : something serving as evidence or proof : SIGN
470384fff8SJason Evans  *	  b : public affirmation by word or example of usually
480384fff8SJason Evans  *	      religious faith or conviction <the heroic witness to divine
490384fff8SJason Evans  *	      life -- Pilot>
500384fff8SJason Evans  *	6 capitalized : a member of the Jehovah's Witnesses
510384fff8SJason Evans  */
520384fff8SJason Evans 
539c36c934SJohn Baldwin #include "opt_ddb.h"
54a5a96a19SJohn Baldwin #include "opt_witness.h"
55a5a96a19SJohn Baldwin 
560384fff8SJason Evans #include <sys/param.h>
5736412d79SJohn Baldwin #include <sys/bus.h>
5836412d79SJohn Baldwin #include <sys/kernel.h>
5936412d79SJohn Baldwin #include <sys/malloc.h>
600384fff8SJason Evans #include <sys/proc.h>
61a5a96a19SJohn Baldwin #include <sys/sysctl.h>
620384fff8SJason Evans #include <sys/systm.h>
6336412d79SJohn Baldwin #include <sys/vmmeter.h>
640384fff8SJason Evans #include <sys/ktr.h>
650384fff8SJason Evans 
6636412d79SJohn Baldwin #include <machine/atomic.h>
6736412d79SJohn Baldwin #include <machine/bus.h>
6836412d79SJohn Baldwin #include <machine/clock.h>
690384fff8SJason Evans #include <machine/cpu.h>
7036412d79SJohn Baldwin 
719c36c934SJohn Baldwin #include <ddb/ddb.h>
729c36c934SJohn Baldwin 
7336412d79SJohn Baldwin #include <vm/vm.h>
7436412d79SJohn Baldwin #include <vm/vm_extern.h>
7536412d79SJohn Baldwin 
760384fff8SJason Evans #define _KERN_MUTEX_C_		/* Cause non-inlined mtx_*() to be compiled. */
7736412d79SJohn Baldwin #include <sys/mutex.h>
7836412d79SJohn Baldwin 
7936412d79SJohn Baldwin /*
8036412d79SJohn Baldwin  * Machine independent bits of the mutex implementation
8136412d79SJohn Baldwin  */
8236412d79SJohn Baldwin /* All mutexes in system (used for debug/panic) */
8336412d79SJohn Baldwin #ifdef MUTEX_DEBUG
8436412d79SJohn Baldwin static struct mtx_debug all_mtx_debug = { NULL, {NULL, NULL}, NULL, 0,
8536412d79SJohn Baldwin 	"All mutexes queue head" };
8636412d79SJohn Baldwin static struct mtx all_mtx = { MTX_UNOWNED, 0, 0, &all_mtx_debug,
8736412d79SJohn Baldwin 	TAILQ_HEAD_INITIALIZER(all_mtx.mtx_blocked),
8836412d79SJohn Baldwin 	{ NULL, NULL }, &all_mtx, &all_mtx };
8936412d79SJohn Baldwin #else	/* MUTEX_DEBUG */
9036412d79SJohn Baldwin static struct mtx all_mtx = { MTX_UNOWNED, 0, 0, "All mutexes queue head",
9136412d79SJohn Baldwin 	TAILQ_HEAD_INITIALIZER(all_mtx.mtx_blocked),
9236412d79SJohn Baldwin 	{ NULL, NULL }, &all_mtx, &all_mtx };
9336412d79SJohn Baldwin #endif	/* MUTEX_DEBUG */
9436412d79SJohn Baldwin 
9536412d79SJohn Baldwin static int	mtx_cur_cnt;
9636412d79SJohn Baldwin static int	mtx_max_cnt;
9736412d79SJohn Baldwin 
9836412d79SJohn Baldwin void	_mtx_enter_giant_def(void);
9936412d79SJohn Baldwin void	_mtx_exit_giant_def(void);
10036412d79SJohn Baldwin static void propagate_priority(struct proc *) __unused;
10136412d79SJohn Baldwin 
10236412d79SJohn Baldwin #define	mtx_unowned(m)	((m)->mtx_lock == MTX_UNOWNED)
10336412d79SJohn Baldwin #define	mtx_owner(m)	(mtx_unowned(m) ? NULL \
10436412d79SJohn Baldwin 			    : (struct proc *)((m)->mtx_lock & MTX_FLAGMASK))
10536412d79SJohn Baldwin 
10636412d79SJohn Baldwin #define RETIP(x)		*(((uintptr_t *)(&x)) - 1)
10736412d79SJohn Baldwin #define	SET_PRIO(p, pri)	(p)->p_priority = (pri)
10836412d79SJohn Baldwin 
10936412d79SJohn Baldwin /*
11036412d79SJohn Baldwin  * XXX Temporary, for use from assembly language
11136412d79SJohn Baldwin  */
11236412d79SJohn Baldwin 
11336412d79SJohn Baldwin void
11436412d79SJohn Baldwin _mtx_enter_giant_def(void)
11536412d79SJohn Baldwin {
11636412d79SJohn Baldwin 
11736412d79SJohn Baldwin 	mtx_enter(&Giant, MTX_DEF);
11836412d79SJohn Baldwin }
11936412d79SJohn Baldwin 
12036412d79SJohn Baldwin void
12136412d79SJohn Baldwin _mtx_exit_giant_def(void)
12236412d79SJohn Baldwin {
12336412d79SJohn Baldwin 
12436412d79SJohn Baldwin 	mtx_exit(&Giant, MTX_DEF);
12536412d79SJohn Baldwin }
12636412d79SJohn Baldwin 
12736412d79SJohn Baldwin static void
12836412d79SJohn Baldwin propagate_priority(struct proc *p)
12936412d79SJohn Baldwin {
13036412d79SJohn Baldwin 	int pri = p->p_priority;
13136412d79SJohn Baldwin 	struct mtx *m = p->p_blocked;
13236412d79SJohn Baldwin 
13336412d79SJohn Baldwin 	for (;;) {
13436412d79SJohn Baldwin 		struct proc *p1;
13536412d79SJohn Baldwin 
13636412d79SJohn Baldwin 		p = mtx_owner(m);
13736412d79SJohn Baldwin 
13836412d79SJohn Baldwin 		if (p == NULL) {
13936412d79SJohn Baldwin 			/*
14036412d79SJohn Baldwin 			 * This really isn't quite right. Really
14136412d79SJohn Baldwin 			 * ought to bump priority of process that
14236412d79SJohn Baldwin 			 * next acquires the mutex.
14336412d79SJohn Baldwin 			 */
14436412d79SJohn Baldwin 			MPASS(m->mtx_lock == MTX_CONTESTED);
14536412d79SJohn Baldwin 			return;
14636412d79SJohn Baldwin 		}
14736412d79SJohn Baldwin 		MPASS(p->p_magic == P_MAGIC);
14836412d79SJohn Baldwin 		if (p->p_priority <= pri)
14936412d79SJohn Baldwin 			return;
15036412d79SJohn Baldwin 		/*
15136412d79SJohn Baldwin 		 * If lock holder is actually running, just bump priority.
15236412d79SJohn Baldwin 		 */
15336412d79SJohn Baldwin 		if (TAILQ_NEXT(p, p_procq) == NULL) {
15436412d79SJohn Baldwin 			MPASS(p->p_stat == SRUN || p->p_stat == SZOMB);
15536412d79SJohn Baldwin 			SET_PRIO(p, pri);
15636412d79SJohn Baldwin 			return;
15736412d79SJohn Baldwin 		}
15836412d79SJohn Baldwin 		/*
15936412d79SJohn Baldwin 		 * If on run queue move to new run queue, and
16036412d79SJohn Baldwin 		 * quit.
16136412d79SJohn Baldwin 		 */
16236412d79SJohn Baldwin 		if (p->p_stat == SRUN) {
16336412d79SJohn Baldwin 			MPASS(p->p_blocked == NULL);
16436412d79SJohn Baldwin 			remrunqueue(p);
16536412d79SJohn Baldwin 			SET_PRIO(p, pri);
16636412d79SJohn Baldwin 			setrunqueue(p);
16736412d79SJohn Baldwin 			return;
16836412d79SJohn Baldwin 		}
16936412d79SJohn Baldwin 
17036412d79SJohn Baldwin 		/*
17136412d79SJohn Baldwin 		 * If we aren't blocked on a mutex, give up and quit.
17236412d79SJohn Baldwin 		 */
17336412d79SJohn Baldwin 		if (p->p_stat != SMTX) {
17436412d79SJohn Baldwin 			printf(
17536412d79SJohn Baldwin 	"XXX: process %d(%s):%d holds %s but isn't blocked on a mutex\n",
17636412d79SJohn Baldwin 			    p->p_pid, p->p_comm, p->p_stat, m->mtx_description);
17736412d79SJohn Baldwin 			return;
17836412d79SJohn Baldwin 		}
17936412d79SJohn Baldwin 
18036412d79SJohn Baldwin 		/*
18136412d79SJohn Baldwin 		 * Pick up the mutex that p is blocked on.
18236412d79SJohn Baldwin 		 */
18336412d79SJohn Baldwin 		m = p->p_blocked;
18436412d79SJohn Baldwin 		MPASS(m != NULL);
18536412d79SJohn Baldwin 
18636412d79SJohn Baldwin 		printf("XXX: process %d(%s) is blocked on %s\n", p->p_pid,
18736412d79SJohn Baldwin 		    p->p_comm, m->mtx_description);
18836412d79SJohn Baldwin 		/*
18936412d79SJohn Baldwin 		 * Check if the proc needs to be moved up on
19036412d79SJohn Baldwin 		 * the blocked chain
19136412d79SJohn Baldwin 		 */
19236412d79SJohn Baldwin 		if ((p1 = TAILQ_PREV(p, rq, p_procq)) == NULL ||
19336412d79SJohn Baldwin 		    p1->p_priority <= pri) {
19436412d79SJohn Baldwin 			if (p1)
19536412d79SJohn Baldwin 				printf(
19636412d79SJohn Baldwin 	"XXX: previous process %d(%s) has higher priority\n",
19736412d79SJohn Baldwin 				    p->p_pid, p->p_comm);
19836412d79SJohn Baldwin 			else
19936412d79SJohn Baldwin 				printf("XXX: process at head of run queue\n");
20036412d79SJohn Baldwin 			continue;
20136412d79SJohn Baldwin 		}
20236412d79SJohn Baldwin 
20336412d79SJohn Baldwin 		/*
20436412d79SJohn Baldwin 		 * Remove proc from blocked chain
20536412d79SJohn Baldwin 		 */
20636412d79SJohn Baldwin 		TAILQ_REMOVE(&m->mtx_blocked, p, p_procq);
20736412d79SJohn Baldwin 		TAILQ_FOREACH(p1, &m->mtx_blocked, p_procq) {
20836412d79SJohn Baldwin 			MPASS(p1->p_magic == P_MAGIC);
20936412d79SJohn Baldwin 			if (p1->p_priority > pri)
21036412d79SJohn Baldwin 				break;
21136412d79SJohn Baldwin 		}
21236412d79SJohn Baldwin 		if (p1)
21336412d79SJohn Baldwin 			TAILQ_INSERT_BEFORE(p1, p, p_procq);
21436412d79SJohn Baldwin 		else
21536412d79SJohn Baldwin 			TAILQ_INSERT_TAIL(&m->mtx_blocked, p, p_procq);
21636412d79SJohn Baldwin 		CTR4(KTR_LOCK,
21736412d79SJohn Baldwin 		    "propagate priority: p 0x%p moved before 0x%p on [0x%p] %s",
21836412d79SJohn Baldwin 		    p, p1, m, m->mtx_description);
21936412d79SJohn Baldwin 	}
22036412d79SJohn Baldwin }
22136412d79SJohn Baldwin 
22236412d79SJohn Baldwin void
22336412d79SJohn Baldwin mtx_enter_hard(struct mtx *m, int type, int saveintr)
22436412d79SJohn Baldwin {
22536412d79SJohn Baldwin 	struct proc *p = CURPROC;
22636412d79SJohn Baldwin 	struct timeval new_switchtime;
22736412d79SJohn Baldwin 
22836412d79SJohn Baldwin 	KASSERT(p != NULL, ("curproc is NULL in mutex"));
22936412d79SJohn Baldwin 
23036412d79SJohn Baldwin 	switch (type) {
23136412d79SJohn Baldwin 	case MTX_DEF:
23236412d79SJohn Baldwin 		if ((m->mtx_lock & MTX_FLAGMASK) == (uintptr_t)p) {
23336412d79SJohn Baldwin 			m->mtx_recurse++;
23436412d79SJohn Baldwin 			atomic_set_ptr(&m->mtx_lock, MTX_RECURSE);
23536412d79SJohn Baldwin 			CTR1(KTR_LOCK, "mtx_enter: 0x%p recurse", m);
23636412d79SJohn Baldwin 			return;
23736412d79SJohn Baldwin 		}
23836412d79SJohn Baldwin 		CTR3(KTR_LOCK, "mtx_enter: 0x%p contested (lock=%p) [0x%p]",
23931271627SJohn Baldwin 		    m, (void *)m->mtx_lock, (void *)RETIP(m));
24036412d79SJohn Baldwin 		while (!_obtain_lock(m, p)) {
241f5271ebcSJohn Baldwin 			uintptr_t v;
24236412d79SJohn Baldwin 			struct proc *p1;
24336412d79SJohn Baldwin 
24436412d79SJohn Baldwin 			mtx_enter(&sched_lock, MTX_SPIN | MTX_RLIKELY);
24536412d79SJohn Baldwin 			/*
24636412d79SJohn Baldwin 			 * check if the lock has been released while
24736412d79SJohn Baldwin 			 * waiting for the schedlock.
24836412d79SJohn Baldwin 			 */
24936412d79SJohn Baldwin 			if ((v = m->mtx_lock) == MTX_UNOWNED) {
25036412d79SJohn Baldwin 				mtx_exit(&sched_lock, MTX_SPIN);
25136412d79SJohn Baldwin 				continue;
25236412d79SJohn Baldwin 			}
25336412d79SJohn Baldwin 			/*
25436412d79SJohn Baldwin 			 * The mutex was marked contested on release. This
25536412d79SJohn Baldwin 			 * means that there are processes blocked on it.
25636412d79SJohn Baldwin 			 */
25736412d79SJohn Baldwin 			if (v == MTX_CONTESTED) {
25836412d79SJohn Baldwin 				p1 = TAILQ_FIRST(&m->mtx_blocked);
25936412d79SJohn Baldwin 				KASSERT(p1 != NULL, ("contested mutex has no contesters"));
26036412d79SJohn Baldwin 				KASSERT(p != NULL, ("curproc is NULL for contested mutex"));
26136412d79SJohn Baldwin 				m->mtx_lock = (uintptr_t)p | MTX_CONTESTED;
26236412d79SJohn Baldwin 				if (p1->p_priority < p->p_priority) {
26336412d79SJohn Baldwin 					SET_PRIO(p, p1->p_priority);
26436412d79SJohn Baldwin 				}
26536412d79SJohn Baldwin 				mtx_exit(&sched_lock, MTX_SPIN);
26636412d79SJohn Baldwin 				return;
26736412d79SJohn Baldwin 			}
26836412d79SJohn Baldwin 			/*
26936412d79SJohn Baldwin 			 * If the mutex isn't already contested and
27036412d79SJohn Baldwin 			 * a failure occurs setting the contested bit the
27136412d79SJohn Baldwin 			 * mutex was either release or the
27236412d79SJohn Baldwin 			 * state of the RECURSION bit changed.
27336412d79SJohn Baldwin 			 */
27436412d79SJohn Baldwin 			if ((v & MTX_CONTESTED) == 0 &&
27536412d79SJohn Baldwin 			    !atomic_cmpset_ptr(&m->mtx_lock, (void *)v,
27636412d79SJohn Baldwin 				               (void *)(v | MTX_CONTESTED))) {
27736412d79SJohn Baldwin 				mtx_exit(&sched_lock, MTX_SPIN);
27836412d79SJohn Baldwin 				continue;
27936412d79SJohn Baldwin 			}
28036412d79SJohn Baldwin 
28136412d79SJohn Baldwin 			/* We definitely have to sleep for this lock */
28236412d79SJohn Baldwin 			mtx_assert(m, MA_NOTOWNED);
28336412d79SJohn Baldwin 
28436412d79SJohn Baldwin #ifdef notyet
28536412d79SJohn Baldwin 			/*
28636412d79SJohn Baldwin 			 * If we're borrowing an interrupted thread's VM
28736412d79SJohn Baldwin 			 * context must clean up before going to sleep.
28836412d79SJohn Baldwin 			 */
28936412d79SJohn Baldwin 			if (p->p_flag & (P_ITHD | P_SITHD)) {
29036412d79SJohn Baldwin 				ithd_t *it = (ithd_t *)p;
29136412d79SJohn Baldwin 
29236412d79SJohn Baldwin 				if (it->it_interrupted) {
29336412d79SJohn Baldwin 					CTR2(KTR_LOCK,
29436412d79SJohn Baldwin 					    "mtx_enter: 0x%x interrupted 0x%x",
29536412d79SJohn Baldwin 					    it, it->it_interrupted);
29636412d79SJohn Baldwin 					intr_thd_fixup(it);
29736412d79SJohn Baldwin 				}
29836412d79SJohn Baldwin 			}
29936412d79SJohn Baldwin #endif
30036412d79SJohn Baldwin 
30136412d79SJohn Baldwin 			/* Put us on the list of procs blocked on this mutex */
30236412d79SJohn Baldwin 			if (TAILQ_EMPTY(&m->mtx_blocked)) {
30336412d79SJohn Baldwin 				p1 = (struct proc *)(m->mtx_lock &
30436412d79SJohn Baldwin 						     MTX_FLAGMASK);
30536412d79SJohn Baldwin 				LIST_INSERT_HEAD(&p1->p_contested, m,
30636412d79SJohn Baldwin 						 mtx_contested);
30736412d79SJohn Baldwin 				TAILQ_INSERT_TAIL(&m->mtx_blocked, p, p_procq);
30836412d79SJohn Baldwin 			} else {
30936412d79SJohn Baldwin 				TAILQ_FOREACH(p1, &m->mtx_blocked, p_procq)
31036412d79SJohn Baldwin 					if (p1->p_priority > p->p_priority)
31136412d79SJohn Baldwin 						break;
31236412d79SJohn Baldwin 				if (p1)
31336412d79SJohn Baldwin 					TAILQ_INSERT_BEFORE(p1, p, p_procq);
31436412d79SJohn Baldwin 				else
31536412d79SJohn Baldwin 					TAILQ_INSERT_TAIL(&m->mtx_blocked, p,
31636412d79SJohn Baldwin 							  p_procq);
31736412d79SJohn Baldwin 			}
31836412d79SJohn Baldwin 
31936412d79SJohn Baldwin 			p->p_blocked = m;	/* Who we're blocked on */
32036412d79SJohn Baldwin 			p->p_stat = SMTX;
32136412d79SJohn Baldwin #if 0
32236412d79SJohn Baldwin 			propagate_priority(p);
32336412d79SJohn Baldwin #endif
32436412d79SJohn Baldwin 			CTR3(KTR_LOCK, "mtx_enter: p 0x%p blocked on [0x%p] %s",
32536412d79SJohn Baldwin 			    p, m, m->mtx_description);
32636412d79SJohn Baldwin 			/*
32736412d79SJohn Baldwin 			 * Blatantly copied from mi_switch nearly verbatim.
32836412d79SJohn Baldwin 			 * When Giant goes away and we stop dinking with it
32936412d79SJohn Baldwin 			 * in mi_switch, we can go back to calling mi_switch
33036412d79SJohn Baldwin 			 * directly here.
33136412d79SJohn Baldwin 			 */
33236412d79SJohn Baldwin 
33336412d79SJohn Baldwin 			/*
33436412d79SJohn Baldwin 			 * Compute the amount of time during which the current
33536412d79SJohn Baldwin 			 * process was running, and add that to its total so
33636412d79SJohn Baldwin 			 * far.
33736412d79SJohn Baldwin 			 */
33836412d79SJohn Baldwin 			microuptime(&new_switchtime);
33936412d79SJohn Baldwin 			if (timevalcmp(&new_switchtime, &switchtime, <)) {
34036412d79SJohn Baldwin 				printf(
34136412d79SJohn Baldwin 		    "microuptime() went backwards (%ld.%06ld -> %ld.%06ld)\n",
34236412d79SJohn Baldwin 		    		    switchtime.tv_sec, switchtime.tv_usec,
34336412d79SJohn Baldwin 		    		    new_switchtime.tv_sec,
34436412d79SJohn Baldwin 		    		    new_switchtime.tv_usec);
34536412d79SJohn Baldwin 				new_switchtime = switchtime;
34636412d79SJohn Baldwin 			} else {
34736412d79SJohn Baldwin 				p->p_runtime += (new_switchtime.tv_usec -
34836412d79SJohn Baldwin 				    switchtime.tv_usec) +
34936412d79SJohn Baldwin 				    (new_switchtime.tv_sec - switchtime.tv_sec) *
35036412d79SJohn Baldwin 				    (int64_t)1000000;
35136412d79SJohn Baldwin 			}
35236412d79SJohn Baldwin 
35336412d79SJohn Baldwin 			/*
35436412d79SJohn Baldwin 			 * Pick a new current process and record its start time.
35536412d79SJohn Baldwin 			 */
35636412d79SJohn Baldwin 			cnt.v_swtch++;
35736412d79SJohn Baldwin 			switchtime = new_switchtime;
35836412d79SJohn Baldwin 			cpu_switch();
35936412d79SJohn Baldwin 			if (switchtime.tv_sec == 0)
36036412d79SJohn Baldwin 				microuptime(&switchtime);
36136412d79SJohn Baldwin 			switchticks = ticks;
36236412d79SJohn Baldwin 			CTR3(KTR_LOCK,
36336412d79SJohn Baldwin 			    "mtx_enter: p 0x%p free from blocked on [0x%p] %s",
36436412d79SJohn Baldwin 			    p, m, m->mtx_description);
36536412d79SJohn Baldwin 			mtx_exit(&sched_lock, MTX_SPIN);
36636412d79SJohn Baldwin 		}
36736412d79SJohn Baldwin 		return;
36836412d79SJohn Baldwin 	case MTX_SPIN:
36936412d79SJohn Baldwin 	case MTX_SPIN | MTX_FIRST:
37036412d79SJohn Baldwin 	case MTX_SPIN | MTX_TOPHALF:
37136412d79SJohn Baldwin 	    {
37236412d79SJohn Baldwin 		int i = 0;
37336412d79SJohn Baldwin 
37436412d79SJohn Baldwin 		if (m->mtx_lock == (uintptr_t)p) {
37536412d79SJohn Baldwin 			m->mtx_recurse++;
37636412d79SJohn Baldwin 			return;
37736412d79SJohn Baldwin 		}
37836412d79SJohn Baldwin 		CTR1(KTR_LOCK, "mtx_enter: %p spinning", m);
37936412d79SJohn Baldwin 		for (;;) {
38036412d79SJohn Baldwin 			if (_obtain_lock(m, p))
38136412d79SJohn Baldwin 				break;
38236412d79SJohn Baldwin 			while (m->mtx_lock != MTX_UNOWNED) {
38336412d79SJohn Baldwin 				if (i++ < 1000000)
38436412d79SJohn Baldwin 					continue;
38536412d79SJohn Baldwin 				if (i++ < 6000000)
38636412d79SJohn Baldwin 					DELAY (1);
38736412d79SJohn Baldwin #ifdef DDB
38836412d79SJohn Baldwin 				else if (!db_active)
38936412d79SJohn Baldwin #else
39036412d79SJohn Baldwin 				else
39136412d79SJohn Baldwin #endif
39236412d79SJohn Baldwin 					panic(
39336412d79SJohn Baldwin 				"spin lock %s held by 0x%p for > 5 seconds",
39436412d79SJohn Baldwin 					    m->mtx_description,
39536412d79SJohn Baldwin 					    (void *)m->mtx_lock);
39636412d79SJohn Baldwin 			}
39736412d79SJohn Baldwin 		}
39836412d79SJohn Baldwin 
39936412d79SJohn Baldwin #ifdef MUTEX_DEBUG
40036412d79SJohn Baldwin 		if (type != MTX_SPIN)
40136412d79SJohn Baldwin 			m->mtx_saveintr = 0xbeefface;
40236412d79SJohn Baldwin 		else
40336412d79SJohn Baldwin #endif
40436412d79SJohn Baldwin 			m->mtx_saveintr = saveintr;
40536412d79SJohn Baldwin 		CTR1(KTR_LOCK, "mtx_enter: 0x%p spin done", m);
40636412d79SJohn Baldwin 		return;
40736412d79SJohn Baldwin 	    }
40836412d79SJohn Baldwin 	}
40936412d79SJohn Baldwin }
41036412d79SJohn Baldwin 
41136412d79SJohn Baldwin void
41236412d79SJohn Baldwin mtx_exit_hard(struct mtx *m, int type)
41336412d79SJohn Baldwin {
41436412d79SJohn Baldwin 	struct proc *p, *p1;
41536412d79SJohn Baldwin 	struct mtx *m1;
41636412d79SJohn Baldwin 	int pri;
41736412d79SJohn Baldwin 
41836412d79SJohn Baldwin 	p = CURPROC;
41936412d79SJohn Baldwin 	switch (type) {
42036412d79SJohn Baldwin 	case MTX_DEF:
42136412d79SJohn Baldwin 	case MTX_DEF | MTX_NOSWITCH:
42236412d79SJohn Baldwin 		if (m->mtx_recurse != 0) {
42336412d79SJohn Baldwin 			if (--(m->mtx_recurse) == 0)
42436412d79SJohn Baldwin 				atomic_clear_ptr(&m->mtx_lock, MTX_RECURSE);
42536412d79SJohn Baldwin 			CTR1(KTR_LOCK, "mtx_exit: 0x%p unrecurse", m);
42636412d79SJohn Baldwin 			return;
42736412d79SJohn Baldwin 		}
42836412d79SJohn Baldwin 		mtx_enter(&sched_lock, MTX_SPIN);
42936412d79SJohn Baldwin 		CTR1(KTR_LOCK, "mtx_exit: 0x%p contested", m);
43036412d79SJohn Baldwin 		p1 = TAILQ_FIRST(&m->mtx_blocked);
43136412d79SJohn Baldwin 		MPASS(p->p_magic == P_MAGIC);
43236412d79SJohn Baldwin 		MPASS(p1->p_magic == P_MAGIC);
43336412d79SJohn Baldwin 		TAILQ_REMOVE(&m->mtx_blocked, p1, p_procq);
43436412d79SJohn Baldwin 		if (TAILQ_EMPTY(&m->mtx_blocked)) {
43536412d79SJohn Baldwin 			LIST_REMOVE(m, mtx_contested);
43636412d79SJohn Baldwin 			_release_lock_quick(m);
43736412d79SJohn Baldwin 			CTR1(KTR_LOCK, "mtx_exit: 0x%p not held", m);
43836412d79SJohn Baldwin 		} else
43936412d79SJohn Baldwin 			m->mtx_lock = MTX_CONTESTED;
44036412d79SJohn Baldwin 		pri = MAXPRI;
44136412d79SJohn Baldwin 		LIST_FOREACH(m1, &p->p_contested, mtx_contested) {
44236412d79SJohn Baldwin 			int cp = TAILQ_FIRST(&m1->mtx_blocked)->p_priority;
44336412d79SJohn Baldwin 			if (cp < pri)
44436412d79SJohn Baldwin 				pri = cp;
44536412d79SJohn Baldwin 		}
44636412d79SJohn Baldwin 		if (pri > p->p_nativepri)
44736412d79SJohn Baldwin 			pri = p->p_nativepri;
44836412d79SJohn Baldwin 		SET_PRIO(p, pri);
44936412d79SJohn Baldwin 		CTR2(KTR_LOCK, "mtx_exit: 0x%p contested setrunqueue 0x%p",
45036412d79SJohn Baldwin 		    m, p1);
45136412d79SJohn Baldwin 		p1->p_blocked = NULL;
45236412d79SJohn Baldwin 		p1->p_stat = SRUN;
45336412d79SJohn Baldwin 		setrunqueue(p1);
45436412d79SJohn Baldwin 		if ((type & MTX_NOSWITCH) == 0 && p1->p_priority < pri) {
45536412d79SJohn Baldwin #ifdef notyet
45636412d79SJohn Baldwin 			if (p->p_flag & (P_ITHD | P_SITHD)) {
45736412d79SJohn Baldwin 				ithd_t *it = (ithd_t *)p;
45836412d79SJohn Baldwin 
45936412d79SJohn Baldwin 				if (it->it_interrupted) {
46036412d79SJohn Baldwin 					CTR2(KTR_LOCK,
46136412d79SJohn Baldwin 					    "mtx_exit: 0x%x interruped 0x%x",
46236412d79SJohn Baldwin 					    it, it->it_interrupted);
46336412d79SJohn Baldwin 					intr_thd_fixup(it);
46436412d79SJohn Baldwin 				}
46536412d79SJohn Baldwin 			}
46636412d79SJohn Baldwin #endif
46736412d79SJohn Baldwin 			setrunqueue(p);
46836412d79SJohn Baldwin 			CTR2(KTR_LOCK, "mtx_exit: 0x%p switching out lock=0x%p",
46931271627SJohn Baldwin 			    m, (void *)m->mtx_lock);
47036412d79SJohn Baldwin 			mi_switch();
47136412d79SJohn Baldwin 			CTR2(KTR_LOCK, "mtx_exit: 0x%p resuming lock=0x%p",
47231271627SJohn Baldwin 			    m, (void *)m->mtx_lock);
47336412d79SJohn Baldwin 		}
47436412d79SJohn Baldwin 		mtx_exit(&sched_lock, MTX_SPIN);
47536412d79SJohn Baldwin 		break;
47636412d79SJohn Baldwin 	case MTX_SPIN:
47736412d79SJohn Baldwin 	case MTX_SPIN | MTX_FIRST:
47836412d79SJohn Baldwin 		if (m->mtx_recurse != 0) {
47936412d79SJohn Baldwin 			m->mtx_recurse--;
48036412d79SJohn Baldwin 			return;
48136412d79SJohn Baldwin 		}
48236412d79SJohn Baldwin 		MPASS(mtx_owned(m));
48336412d79SJohn Baldwin 		_release_lock_quick(m);
48436412d79SJohn Baldwin 		if (type & MTX_FIRST)
48536412d79SJohn Baldwin 			enable_intr();	/* XXX is this kosher? */
48636412d79SJohn Baldwin 		else {
48736412d79SJohn Baldwin 			MPASS(m->mtx_saveintr != 0xbeefface);
48836412d79SJohn Baldwin 			restore_intr(m->mtx_saveintr);
48936412d79SJohn Baldwin 		}
49036412d79SJohn Baldwin 		break;
49136412d79SJohn Baldwin 	case MTX_SPIN | MTX_TOPHALF:
49236412d79SJohn Baldwin 		if (m->mtx_recurse != 0) {
49336412d79SJohn Baldwin 			m->mtx_recurse--;
49436412d79SJohn Baldwin 			return;
49536412d79SJohn Baldwin 		}
49636412d79SJohn Baldwin 		MPASS(mtx_owned(m));
49736412d79SJohn Baldwin 		_release_lock_quick(m);
49836412d79SJohn Baldwin 		break;
49936412d79SJohn Baldwin 	default:
50036412d79SJohn Baldwin 		panic("mtx_exit_hard: unsupported type 0x%x\n", type);
50136412d79SJohn Baldwin 	}
50236412d79SJohn Baldwin }
50336412d79SJohn Baldwin 
50436412d79SJohn Baldwin #define MV_DESTROY	0	/* validate before destory */
50536412d79SJohn Baldwin #define MV_INIT		1	/* validate before init */
50636412d79SJohn Baldwin 
50736412d79SJohn Baldwin #ifdef MUTEX_DEBUG
50836412d79SJohn Baldwin 
50936412d79SJohn Baldwin int mtx_validate __P((struct mtx *, int));
51036412d79SJohn Baldwin 
51136412d79SJohn Baldwin int
51236412d79SJohn Baldwin mtx_validate(struct mtx *m, int when)
51336412d79SJohn Baldwin {
51436412d79SJohn Baldwin 	struct mtx *mp;
51536412d79SJohn Baldwin 	int i;
51636412d79SJohn Baldwin 	int retval = 0;
51736412d79SJohn Baldwin 
51836412d79SJohn Baldwin 	if (m == &all_mtx || cold)
51936412d79SJohn Baldwin 		return 0;
52036412d79SJohn Baldwin 
52136412d79SJohn Baldwin 	mtx_enter(&all_mtx, MTX_DEF);
52236412d79SJohn Baldwin /*
52336412d79SJohn Baldwin  * XXX - When kernacc() is fixed on the alpha to handle K0_SEG memory properly
52436412d79SJohn Baldwin  * we can re-enable the kernacc() checks.
52536412d79SJohn Baldwin  */
52636412d79SJohn Baldwin #ifndef __alpha__
52736412d79SJohn Baldwin 	MPASS(kernacc((caddr_t)all_mtx.mtx_next, sizeof(uintptr_t),
52836412d79SJohn Baldwin 	    VM_PROT_READ) == 1);
52936412d79SJohn Baldwin #endif
53036412d79SJohn Baldwin 	MPASS(all_mtx.mtx_next->mtx_prev == &all_mtx);
53136412d79SJohn Baldwin 	for (i = 0, mp = all_mtx.mtx_next; mp != &all_mtx; mp = mp->mtx_next) {
53236412d79SJohn Baldwin #ifndef __alpha__
53336412d79SJohn Baldwin 		if (kernacc((caddr_t)mp->mtx_next, sizeof(uintptr_t),
53436412d79SJohn Baldwin 		    VM_PROT_READ) != 1) {
53536412d79SJohn Baldwin 			panic("mtx_validate: mp=%p mp->mtx_next=%p",
53636412d79SJohn Baldwin 			    mp, mp->mtx_next);
53736412d79SJohn Baldwin 		}
53836412d79SJohn Baldwin #endif
53936412d79SJohn Baldwin 		i++;
54036412d79SJohn Baldwin 		if (i > mtx_cur_cnt) {
54136412d79SJohn Baldwin 			panic("mtx_validate: too many in chain, known=%d\n",
54236412d79SJohn Baldwin 			    mtx_cur_cnt);
54336412d79SJohn Baldwin 		}
54436412d79SJohn Baldwin 	}
54536412d79SJohn Baldwin 	MPASS(i == mtx_cur_cnt);
54636412d79SJohn Baldwin 	switch (when) {
54736412d79SJohn Baldwin 	case MV_DESTROY:
54836412d79SJohn Baldwin 		for (mp = all_mtx.mtx_next; mp != &all_mtx; mp = mp->mtx_next)
54936412d79SJohn Baldwin 			if (mp == m)
55036412d79SJohn Baldwin 				break;
55136412d79SJohn Baldwin 		MPASS(mp == m);
55236412d79SJohn Baldwin 		break;
55336412d79SJohn Baldwin 	case MV_INIT:
55436412d79SJohn Baldwin 		for (mp = all_mtx.mtx_next; mp != &all_mtx; mp = mp->mtx_next)
55536412d79SJohn Baldwin 		if (mp == m) {
55636412d79SJohn Baldwin 			/*
55736412d79SJohn Baldwin 			 * Not good. This mutex already exists.
55836412d79SJohn Baldwin 			 */
55936412d79SJohn Baldwin 			printf("re-initing existing mutex %s\n",
56036412d79SJohn Baldwin 			    m->mtx_description);
56136412d79SJohn Baldwin 			MPASS(m->mtx_lock == MTX_UNOWNED);
56236412d79SJohn Baldwin 			retval = 1;
56336412d79SJohn Baldwin 		}
56436412d79SJohn Baldwin 	}
56536412d79SJohn Baldwin 	mtx_exit(&all_mtx, MTX_DEF);
56636412d79SJohn Baldwin 	return (retval);
56736412d79SJohn Baldwin }
56836412d79SJohn Baldwin #endif
56936412d79SJohn Baldwin 
57036412d79SJohn Baldwin void
57136412d79SJohn Baldwin mtx_init(struct mtx *m, const char *t, int flag)
57236412d79SJohn Baldwin {
57336412d79SJohn Baldwin #ifdef MUTEX_DEBUG
57436412d79SJohn Baldwin 	struct mtx_debug *debug;
57536412d79SJohn Baldwin #endif
57636412d79SJohn Baldwin 
57736412d79SJohn Baldwin 	CTR2(KTR_LOCK, "mtx_init 0x%p (%s)", m, t);
57836412d79SJohn Baldwin #ifdef MUTEX_DEBUG
57936412d79SJohn Baldwin 	if (mtx_validate(m, MV_INIT))	/* diagnostic and error correction */
58036412d79SJohn Baldwin 		return;
58136412d79SJohn Baldwin 	if (flag & MTX_COLD)
58236412d79SJohn Baldwin 		debug = m->mtx_debug;
58336412d79SJohn Baldwin 	else
58436412d79SJohn Baldwin 		debug = NULL;
58536412d79SJohn Baldwin 	if (debug == NULL) {
58636412d79SJohn Baldwin #ifdef DIAGNOSTIC
58736412d79SJohn Baldwin 		if(cold && bootverbose)
58836412d79SJohn Baldwin 			printf("malloc'ing mtx_debug while cold for %s\n", t);
58936412d79SJohn Baldwin #endif
59036412d79SJohn Baldwin 
59136412d79SJohn Baldwin 		/* XXX - should not use DEVBUF */
59236412d79SJohn Baldwin 		debug = malloc(sizeof(struct mtx_debug), M_DEVBUF, M_NOWAIT);
59336412d79SJohn Baldwin 		MPASS(debug != NULL);
59436412d79SJohn Baldwin 		bzero(debug, sizeof(struct mtx_debug));
59536412d79SJohn Baldwin 	}
59636412d79SJohn Baldwin #endif
59736412d79SJohn Baldwin 	bzero((void *)m, sizeof *m);
59836412d79SJohn Baldwin 	TAILQ_INIT(&m->mtx_blocked);
59936412d79SJohn Baldwin #ifdef MUTEX_DEBUG
60036412d79SJohn Baldwin 	m->mtx_debug = debug;
60136412d79SJohn Baldwin #endif
60236412d79SJohn Baldwin 	m->mtx_description = t;
60336412d79SJohn Baldwin 	m->mtx_lock = MTX_UNOWNED;
60436412d79SJohn Baldwin 	/* Put on all mutex queue */
60536412d79SJohn Baldwin 	mtx_enter(&all_mtx, MTX_DEF);
60636412d79SJohn Baldwin 	m->mtx_next = &all_mtx;
60736412d79SJohn Baldwin 	m->mtx_prev = all_mtx.mtx_prev;
60836412d79SJohn Baldwin 	m->mtx_prev->mtx_next = m;
60936412d79SJohn Baldwin 	all_mtx.mtx_prev = m;
61036412d79SJohn Baldwin 	if (++mtx_cur_cnt > mtx_max_cnt)
61136412d79SJohn Baldwin 		mtx_max_cnt = mtx_cur_cnt;
61236412d79SJohn Baldwin 	mtx_exit(&all_mtx, MTX_DEF);
61336412d79SJohn Baldwin 	witness_init(m, flag);
61436412d79SJohn Baldwin }
61536412d79SJohn Baldwin 
61636412d79SJohn Baldwin void
61736412d79SJohn Baldwin mtx_destroy(struct mtx *m)
61836412d79SJohn Baldwin {
61936412d79SJohn Baldwin 
62036412d79SJohn Baldwin 	CTR2(KTR_LOCK, "mtx_destroy 0x%p (%s)", m, m->mtx_description);
62136412d79SJohn Baldwin #ifdef MUTEX_DEBUG
62236412d79SJohn Baldwin 	if (m->mtx_next == NULL)
62336412d79SJohn Baldwin 		panic("mtx_destroy: %p (%s) already destroyed",
62436412d79SJohn Baldwin 		    m, m->mtx_description);
62536412d79SJohn Baldwin 
62636412d79SJohn Baldwin 	if (!mtx_owned(m)) {
62736412d79SJohn Baldwin 		MPASS(m->mtx_lock == MTX_UNOWNED);
62836412d79SJohn Baldwin 	} else {
62936412d79SJohn Baldwin 		MPASS((m->mtx_lock & (MTX_RECURSE|MTX_CONTESTED)) == 0);
63036412d79SJohn Baldwin 	}
63136412d79SJohn Baldwin 	mtx_validate(m, MV_DESTROY);		/* diagnostic */
63236412d79SJohn Baldwin #endif
63336412d79SJohn Baldwin 
63436412d79SJohn Baldwin #ifdef WITNESS
63536412d79SJohn Baldwin 	if (m->mtx_witness)
63636412d79SJohn Baldwin 		witness_destroy(m);
63736412d79SJohn Baldwin #endif /* WITNESS */
63836412d79SJohn Baldwin 
63936412d79SJohn Baldwin 	/* Remove from the all mutex queue */
64036412d79SJohn Baldwin 	mtx_enter(&all_mtx, MTX_DEF);
64136412d79SJohn Baldwin 	m->mtx_next->mtx_prev = m->mtx_prev;
64236412d79SJohn Baldwin 	m->mtx_prev->mtx_next = m->mtx_next;
64336412d79SJohn Baldwin #ifdef MUTEX_DEBUG
64436412d79SJohn Baldwin 	m->mtx_next = m->mtx_prev = NULL;
64536412d79SJohn Baldwin 	free(m->mtx_debug, M_DEVBUF);
64636412d79SJohn Baldwin 	m->mtx_debug = NULL;
64736412d79SJohn Baldwin #endif
64836412d79SJohn Baldwin 	mtx_cur_cnt--;
64936412d79SJohn Baldwin 	mtx_exit(&all_mtx, MTX_DEF);
65036412d79SJohn Baldwin }
6510384fff8SJason Evans 
6520384fff8SJason Evans /*
6530384fff8SJason Evans  * The non-inlined versions of the mtx_*() functions are always built (above),
65436412d79SJohn Baldwin  * but the witness code depends on the MUTEX_DEBUG and WITNESS kernel options
6550384fff8SJason Evans  * being specified.
6560384fff8SJason Evans  */
65736412d79SJohn Baldwin #if (defined(MUTEX_DEBUG) && defined(WITNESS))
6580384fff8SJason Evans 
6590384fff8SJason Evans #define WITNESS_COUNT 200
6600384fff8SJason Evans #define	WITNESS_NCHILDREN 2
6610384fff8SJason Evans 
66278f0da03SJohn Baldwin int witness_watch = 1;
6630384fff8SJason Evans 
664606f8eb2SJohn Baldwin struct witness {
6650384fff8SJason Evans 	struct witness	*w_next;
666b67a3e6eSJohn Baldwin 	const char	*w_description;
66712473b76SJason Evans 	const char	*w_file;
6680384fff8SJason Evans 	int		 w_line;
6690384fff8SJason Evans 	struct witness	*w_morechildren;
6700384fff8SJason Evans 	u_char		 w_childcnt;
6710384fff8SJason Evans 	u_char		 w_Giant_squawked:1;
6720384fff8SJason Evans 	u_char		 w_other_squawked:1;
6730384fff8SJason Evans 	u_char		 w_same_squawked:1;
6740384fff8SJason Evans 	u_char		 w_sleep:1;
6750384fff8SJason Evans 	u_char		 w_spin:1;	/* this is a spin mutex */
6760384fff8SJason Evans 	u_int		 w_level;
6770384fff8SJason Evans 	struct witness	*w_children[WITNESS_NCHILDREN];
678606f8eb2SJohn Baldwin };
6790384fff8SJason Evans 
680606f8eb2SJohn Baldwin struct witness_blessed {
6810384fff8SJason Evans 	char 	*b_lock1;
6820384fff8SJason Evans 	char	*b_lock2;
683606f8eb2SJohn Baldwin };
6840384fff8SJason Evans 
685a5a96a19SJohn Baldwin #ifdef DDB
6860384fff8SJason Evans /*
687a5a96a19SJohn Baldwin  * When DDB is enabled and witness_ddb is set to 1, it will cause the system to
6880384fff8SJason Evans  * drop into kdebug() when:
6890384fff8SJason Evans  *	- a lock heirarchy violation occurs
6900384fff8SJason Evans  *	- locks are held when going to sleep.
6910384fff8SJason Evans  */
692a5a96a19SJohn Baldwin #ifdef WITNESS_DDB
693a5a96a19SJohn Baldwin int	witness_ddb = 1;
694a5a96a19SJohn Baldwin #else
695a5a96a19SJohn Baldwin int	witness_ddb = 0;
6960384fff8SJason Evans #endif
697a5a96a19SJohn Baldwin SYSCTL_INT(_debug, OID_AUTO, witness_ddb, CTLFLAG_RW, &witness_ddb, 0, "");
698a5a96a19SJohn Baldwin #endif /* DDB */
6990384fff8SJason Evans 
700a5a96a19SJohn Baldwin #ifdef WITNESS_SKIPSPIN
701a5a96a19SJohn Baldwin int	witness_skipspin = 1;
702a5a96a19SJohn Baldwin #else
703a5a96a19SJohn Baldwin int	witness_skipspin = 0;
7040384fff8SJason Evans #endif
705a5a96a19SJohn Baldwin SYSCTL_INT(_debug, OID_AUTO, witness_skipspin, CTLFLAG_RD, &witness_skipspin, 0,
706a5a96a19SJohn Baldwin     "");
7070384fff8SJason Evans 
708a5a96a19SJohn Baldwin MUTEX_DECLARE(static,w_mtx);
709606f8eb2SJohn Baldwin static struct witness	*w_free;
710606f8eb2SJohn Baldwin static struct witness	*w_all;
7110384fff8SJason Evans static int		 w_inited;
7120384fff8SJason Evans static int		 witness_dead;	/* fatal error, probably no memory */
7130384fff8SJason Evans 
714606f8eb2SJohn Baldwin static struct witness	 w_data[WITNESS_COUNT];
7150384fff8SJason Evans 
716b67a3e6eSJohn Baldwin static struct witness	 *enroll __P((const char *description, int flag));
717606f8eb2SJohn Baldwin static int itismychild __P((struct witness *parent, struct witness *child));
718606f8eb2SJohn Baldwin static void removechild __P((struct witness *parent, struct witness *child));
719606f8eb2SJohn Baldwin static int isitmychild __P((struct witness *parent, struct witness *child));
720606f8eb2SJohn Baldwin static int isitmydescendant __P((struct witness *parent, struct witness *child));
721606f8eb2SJohn Baldwin static int dup_ok __P((struct witness *));
722606f8eb2SJohn Baldwin static int blessed __P((struct witness *, struct witness *));
7230384fff8SJason Evans static void witness_displaydescendants
724606f8eb2SJohn Baldwin     __P((void(*)(const char *fmt, ...), struct witness *));
725606f8eb2SJohn Baldwin static void witness_leveldescendents __P((struct witness *parent, int level));
7260384fff8SJason Evans static void witness_levelall __P((void));
727606f8eb2SJohn Baldwin static struct witness * witness_get __P((void));
728606f8eb2SJohn Baldwin static void witness_free __P((struct witness *m));
7290384fff8SJason Evans 
7300384fff8SJason Evans 
7310384fff8SJason Evans static char *ignore_list[] = {
7320384fff8SJason Evans 	"witness lock",
7330384fff8SJason Evans 	NULL
7340384fff8SJason Evans };
7350384fff8SJason Evans 
7360384fff8SJason Evans static char *spin_order_list[] = {
7370384fff8SJason Evans 	"sched lock",
738a5a96a19SJohn Baldwin 	"clk",
739a5a96a19SJohn Baldwin 	"sio",
7400384fff8SJason Evans 	/*
7410384fff8SJason Evans 	 * leaf locks
7420384fff8SJason Evans 	 */
7430384fff8SJason Evans 	NULL
7440384fff8SJason Evans };
7450384fff8SJason Evans 
7460384fff8SJason Evans static char *order_list[] = {
7470384fff8SJason Evans 	NULL
7480384fff8SJason Evans };
7490384fff8SJason Evans 
7500384fff8SJason Evans static char *dup_list[] = {
7510384fff8SJason Evans 	NULL
7520384fff8SJason Evans };
7530384fff8SJason Evans 
7540384fff8SJason Evans static char *sleep_list[] = {
7550384fff8SJason Evans 	"Giant lock",
7560384fff8SJason Evans 	NULL
7570384fff8SJason Evans };
7580384fff8SJason Evans 
7590384fff8SJason Evans /*
7600384fff8SJason Evans  * Pairs of locks which have been blessed
7610384fff8SJason Evans  * Don't complain about order problems with blessed locks
7620384fff8SJason Evans  */
763606f8eb2SJohn Baldwin static struct witness_blessed blessed_list[] = {
7640384fff8SJason Evans };
765606f8eb2SJohn Baldwin static int blessed_count = sizeof(blessed_list) / sizeof(struct witness_blessed);
7660384fff8SJason Evans 
7670384fff8SJason Evans void
768606f8eb2SJohn Baldwin witness_init(struct mtx *m, int flag)
7690384fff8SJason Evans {
7700384fff8SJason Evans 	m->mtx_witness = enroll(m->mtx_description, flag);
7710384fff8SJason Evans }
7720384fff8SJason Evans 
7730384fff8SJason Evans void
774606f8eb2SJohn Baldwin witness_destroy(struct mtx *m)
7750384fff8SJason Evans {
776606f8eb2SJohn Baldwin 	struct mtx *m1;
7770384fff8SJason Evans 	struct proc *p;
7780384fff8SJason Evans 	p = CURPROC;
7790384fff8SJason Evans 	for ((m1 = LIST_FIRST(&p->p_heldmtx)); m1 != NULL;
7800384fff8SJason Evans 		m1 = LIST_NEXT(m1, mtx_held)) {
7810384fff8SJason Evans 		if (m1 == m) {
7820384fff8SJason Evans 			LIST_REMOVE(m, mtx_held);
7830384fff8SJason Evans 			break;
7840384fff8SJason Evans 		}
7850384fff8SJason Evans 	}
7860384fff8SJason Evans 	return;
7870384fff8SJason Evans 
7880384fff8SJason Evans }
7890384fff8SJason Evans 
7900384fff8SJason Evans void
791606f8eb2SJohn Baldwin witness_enter(struct mtx *m, int flags, const char *file, int line)
7920384fff8SJason Evans {
793606f8eb2SJohn Baldwin 	struct witness *w, *w1;
794606f8eb2SJohn Baldwin 	struct mtx *m1;
7950384fff8SJason Evans 	struct proc *p;
7960384fff8SJason Evans 	int i;
797a5a96a19SJohn Baldwin #ifdef DDB
798a5a96a19SJohn Baldwin 	int go_into_ddb = 0;
799a5a96a19SJohn Baldwin #endif /* DDB */
8000384fff8SJason Evans 
8010384fff8SJason Evans 	w = m->mtx_witness;
8020384fff8SJason Evans 	p = CURPROC;
8030384fff8SJason Evans 
8040384fff8SJason Evans 	if (flags & MTX_SPIN) {
8050384fff8SJason Evans 		if (!w->w_spin)
8065340642aSJason Evans 			panic("mutex_enter: MTX_SPIN on MTX_DEF mutex %s @"
8075340642aSJason Evans 			    " %s:%d", m->mtx_description, file, line);
8080384fff8SJason Evans 		if (m->mtx_recurse != 0)
8090384fff8SJason Evans 			return;
8100384fff8SJason Evans 		mtx_enter(&w_mtx, MTX_SPIN);
8110384fff8SJason Evans 		i = witness_spin_check;
8120384fff8SJason Evans 		if (i != 0 && w->w_level < i) {
8130384fff8SJason Evans 			mtx_exit(&w_mtx, MTX_SPIN);
8145340642aSJason Evans 			panic("mutex_enter(%s:%x, MTX_SPIN) out of order @"
8155340642aSJason Evans 			    " %s:%d already holding %s:%x",
8160384fff8SJason Evans 			    m->mtx_description, w->w_level, file, line,
8170384fff8SJason Evans 			    spin_order_list[ffs(i)-1], i);
8180384fff8SJason Evans 		}
8190384fff8SJason Evans 		PCPU_SET(witness_spin_check, i | w->w_level);
8200384fff8SJason Evans 		mtx_exit(&w_mtx, MTX_SPIN);
8210384fff8SJason Evans 		return;
8220384fff8SJason Evans 	}
8230384fff8SJason Evans 	if (w->w_spin)
8240384fff8SJason Evans 		panic("mutex_enter: MTX_DEF on MTX_SPIN mutex %s @ %s:%d",
8250384fff8SJason Evans 		    m->mtx_description, file, line);
8260384fff8SJason Evans 
8270384fff8SJason Evans 	if (m->mtx_recurse != 0)
8280384fff8SJason Evans 		return;
8290384fff8SJason Evans 	if (witness_dead)
8300384fff8SJason Evans 		goto out;
831ecbd8e37SJohn Baldwin 	if (cold || panicstr)
8320384fff8SJason Evans 		goto out;
8330384fff8SJason Evans 
8340384fff8SJason Evans 	if (!mtx_legal2block())
8350384fff8SJason Evans 		panic("blockable mtx_enter() of %s when not legal @ %s:%d",
8360384fff8SJason Evans 			    m->mtx_description, file, line);
8370384fff8SJason Evans 	/*
8380384fff8SJason Evans 	 * Is this the first mutex acquired
8390384fff8SJason Evans 	 */
8400384fff8SJason Evans 	if ((m1 = LIST_FIRST(&p->p_heldmtx)) == NULL)
8410384fff8SJason Evans 		goto out;
8420384fff8SJason Evans 
8430384fff8SJason Evans 	if ((w1 = m1->mtx_witness) == w) {
8440384fff8SJason Evans 		if (w->w_same_squawked || dup_ok(w))
8450384fff8SJason Evans 			goto out;
8460384fff8SJason Evans 		w->w_same_squawked = 1;
8470384fff8SJason Evans 		printf("acquring duplicate lock of same type: \"%s\"\n",
8480384fff8SJason Evans 			m->mtx_description);
8490384fff8SJason Evans 		printf(" 1st @ %s:%d\n", w->w_file, w->w_line);
8500384fff8SJason Evans 		printf(" 2nd @ %s:%d\n", file, line);
851a5a96a19SJohn Baldwin #ifdef DDB
852a5a96a19SJohn Baldwin 		go_into_ddb = 1;
853a5a96a19SJohn Baldwin #endif /* DDB */
8540384fff8SJason Evans 		goto out;
8550384fff8SJason Evans 	}
8560384fff8SJason Evans 	MPASS(!mtx_owned(&w_mtx));
8570384fff8SJason Evans 	mtx_enter(&w_mtx, MTX_SPIN);
8580384fff8SJason Evans 	/*
8590384fff8SJason Evans 	 * If we have a known higher number just say ok
8600384fff8SJason Evans 	 */
8610384fff8SJason Evans 	if (witness_watch > 1 && w->w_level > w1->w_level) {
8620384fff8SJason Evans 		mtx_exit(&w_mtx, MTX_SPIN);
8630384fff8SJason Evans 		goto out;
8640384fff8SJason Evans 	}
8650384fff8SJason Evans 	if (isitmydescendant(m1->mtx_witness, w)) {
8660384fff8SJason Evans 		mtx_exit(&w_mtx, MTX_SPIN);
8670384fff8SJason Evans 		goto out;
8680384fff8SJason Evans 	}
8690384fff8SJason Evans 	for (i = 0; m1 != NULL; m1 = LIST_NEXT(m1, mtx_held), i++) {
8700384fff8SJason Evans 
87136412d79SJohn Baldwin 		MPASS(i < 200);
8720384fff8SJason Evans 		w1 = m1->mtx_witness;
8730384fff8SJason Evans 		if (isitmydescendant(w, w1)) {
8740384fff8SJason Evans 			mtx_exit(&w_mtx, MTX_SPIN);
8750384fff8SJason Evans 			if (blessed(w, w1))
8760384fff8SJason Evans 				goto out;
8770384fff8SJason Evans 			if (m1 == &Giant) {
8780384fff8SJason Evans 				if (w1->w_Giant_squawked)
8790384fff8SJason Evans 					goto out;
8800384fff8SJason Evans 				else
8810384fff8SJason Evans 					w1->w_Giant_squawked = 1;
8820384fff8SJason Evans 			} else {
8830384fff8SJason Evans 				if (w1->w_other_squawked)
8840384fff8SJason Evans 					goto out;
8850384fff8SJason Evans 				else
8860384fff8SJason Evans 					w1->w_other_squawked = 1;
8870384fff8SJason Evans 			}
8880384fff8SJason Evans 			printf("lock order reversal\n");
8890384fff8SJason Evans 			printf(" 1st %s last acquired @ %s:%d\n",
8900384fff8SJason Evans 			    w->w_description, w->w_file, w->w_line);
8910384fff8SJason Evans 			printf(" 2nd %p %s @ %s:%d\n",
8920384fff8SJason Evans 			    m1, w1->w_description, w1->w_file, w1->w_line);
8930384fff8SJason Evans 			printf(" 3rd %p %s @ %s:%d\n",
8940384fff8SJason Evans 			    m, w->w_description, file, line);
895a5a96a19SJohn Baldwin #ifdef DDB
896a5a96a19SJohn Baldwin 			go_into_ddb = 1;
897a5a96a19SJohn Baldwin #endif /* DDB */
8980384fff8SJason Evans 			goto out;
8990384fff8SJason Evans 		}
9000384fff8SJason Evans 	}
9010384fff8SJason Evans 	m1 = LIST_FIRST(&p->p_heldmtx);
9020384fff8SJason Evans 	if (!itismychild(m1->mtx_witness, w))
9030384fff8SJason Evans 		mtx_exit(&w_mtx, MTX_SPIN);
9040384fff8SJason Evans 
9050384fff8SJason Evans out:
906a5a96a19SJohn Baldwin #ifdef DDB
907a5a96a19SJohn Baldwin 	if (witness_ddb && go_into_ddb)
908a5a96a19SJohn Baldwin 		Debugger("witness_enter");
909a5a96a19SJohn Baldwin #endif /* DDB */
9100384fff8SJason Evans 	w->w_file = file;
9110384fff8SJason Evans 	w->w_line = line;
9120384fff8SJason Evans 	m->mtx_line = line;
9130384fff8SJason Evans 	m->mtx_file = file;
9140384fff8SJason Evans 
9150384fff8SJason Evans 	/*
9160384fff8SJason Evans 	 * If this pays off it likely means that a mutex being witnessed
9170384fff8SJason Evans 	 * is acquired in hardclock. Put it in the ignore list. It is
9180384fff8SJason Evans 	 * likely not the mutex this assert fails on.
9190384fff8SJason Evans 	 */
92036412d79SJohn Baldwin 	MPASS(m->mtx_held.le_prev == NULL);
9210384fff8SJason Evans 	LIST_INSERT_HEAD(&p->p_heldmtx, (struct mtx*)m, mtx_held);
9220384fff8SJason Evans }
9230384fff8SJason Evans 
9240384fff8SJason Evans void
925606f8eb2SJohn Baldwin witness_exit(struct mtx *m, int flags, const char *file, int line)
9260384fff8SJason Evans {
927606f8eb2SJohn Baldwin 	struct witness *w;
9280384fff8SJason Evans 
9290384fff8SJason Evans 	w = m->mtx_witness;
9300384fff8SJason Evans 
9310384fff8SJason Evans 	if (flags & MTX_SPIN) {
9320384fff8SJason Evans 		if (!w->w_spin)
9335340642aSJason Evans 			panic("mutex_exit: MTX_SPIN on MTX_DEF mutex %s @"
9345340642aSJason Evans 			    " %s:%d", m->mtx_description, file, line);
9350384fff8SJason Evans 		if (m->mtx_recurse != 0)
9360384fff8SJason Evans 			return;
9370384fff8SJason Evans 		mtx_enter(&w_mtx, MTX_SPIN);
9380384fff8SJason Evans 		PCPU_SET(witness_spin_check, witness_spin_check & ~w->w_level);
9390384fff8SJason Evans 		mtx_exit(&w_mtx, MTX_SPIN);
9400384fff8SJason Evans 		return;
9410384fff8SJason Evans 	}
9420384fff8SJason Evans 	if (w->w_spin)
9430384fff8SJason Evans 		panic("mutex_exit: MTX_DEF on MTX_SPIN mutex %s @ %s:%d",
9440384fff8SJason Evans 		    m->mtx_description, file, line);
9450384fff8SJason Evans 
9460384fff8SJason Evans 	if (m->mtx_recurse != 0)
9470384fff8SJason Evans 		return;
9480384fff8SJason Evans 
9490384fff8SJason Evans 	if ((flags & MTX_NOSWITCH) == 0 && !mtx_legal2block() && !cold)
9500384fff8SJason Evans 		panic("switchable mtx_exit() of %s when not legal @ %s:%d",
9510384fff8SJason Evans 			    m->mtx_description, file, line);
9520384fff8SJason Evans 	LIST_REMOVE(m, mtx_held);
9530384fff8SJason Evans 	m->mtx_held.le_prev = NULL;
9540384fff8SJason Evans }
9550384fff8SJason Evans 
9560384fff8SJason Evans void
957606f8eb2SJohn Baldwin witness_try_enter(struct mtx *m, int flags, const char *file, int line)
9580384fff8SJason Evans {
9590384fff8SJason Evans 	struct proc *p;
960606f8eb2SJohn Baldwin 	struct witness *w = m->mtx_witness;
9610384fff8SJason Evans 
9620384fff8SJason Evans 	if (flags & MTX_SPIN) {
9630384fff8SJason Evans 		if (!w->w_spin)
9640384fff8SJason Evans 			panic("mutex_try_enter: "
9650384fff8SJason Evans 			    "MTX_SPIN on MTX_DEF mutex %s @ %s:%d",
9660384fff8SJason Evans 			    m->mtx_description, file, line);
9670384fff8SJason Evans 		if (m->mtx_recurse != 0)
9680384fff8SJason Evans 			return;
9690384fff8SJason Evans 		mtx_enter(&w_mtx, MTX_SPIN);
9700384fff8SJason Evans 		PCPU_SET(witness_spin_check, witness_spin_check | w->w_level);
9710384fff8SJason Evans 		mtx_exit(&w_mtx, MTX_SPIN);
9720384fff8SJason Evans 		return;
9730384fff8SJason Evans 	}
9740384fff8SJason Evans 
9750384fff8SJason Evans 	if (w->w_spin)
9760384fff8SJason Evans 		panic("mutex_try_enter: MTX_DEF on MTX_SPIN mutex %s @ %s:%d",
9770384fff8SJason Evans 		    m->mtx_description, file, line);
9780384fff8SJason Evans 
9790384fff8SJason Evans 	if (m->mtx_recurse != 0)
9800384fff8SJason Evans 		return;
9810384fff8SJason Evans 
9820384fff8SJason Evans 	w->w_file = file;
9830384fff8SJason Evans 	w->w_line = line;
9840384fff8SJason Evans 	m->mtx_line = line;
9850384fff8SJason Evans 	m->mtx_file = file;
9860384fff8SJason Evans 	p = CURPROC;
98736412d79SJohn Baldwin 	MPASS(m->mtx_held.le_prev == NULL);
9880384fff8SJason Evans 	LIST_INSERT_HEAD(&p->p_heldmtx, (struct mtx*)m, mtx_held);
9890384fff8SJason Evans }
9900384fff8SJason Evans 
9910384fff8SJason Evans void
9920384fff8SJason Evans witness_display(void(*prnt)(const char *fmt, ...))
9930384fff8SJason Evans {
994606f8eb2SJohn Baldwin 	struct witness *w, *w1;
9950384fff8SJason Evans 
9960384fff8SJason Evans 	witness_levelall();
9970384fff8SJason Evans 
9980384fff8SJason Evans 	for (w = w_all; w; w = w->w_next) {
9990384fff8SJason Evans 		if (w->w_file == NULL)
10000384fff8SJason Evans 			continue;
10010384fff8SJason Evans 		for (w1 = w_all; w1; w1 = w1->w_next) {
10020384fff8SJason Evans 			if (isitmychild(w1, w))
10030384fff8SJason Evans 				break;
10040384fff8SJason Evans 		}
10050384fff8SJason Evans 		if (w1 != NULL)
10060384fff8SJason Evans 			continue;
10070384fff8SJason Evans 		/*
10080384fff8SJason Evans 		 * This lock has no anscestors, display its descendants.
10090384fff8SJason Evans 		 */
10100384fff8SJason Evans 		witness_displaydescendants(prnt, w);
10110384fff8SJason Evans 	}
10120384fff8SJason Evans 	prnt("\nMutex which were never acquired\n");
10130384fff8SJason Evans 	for (w = w_all; w; w = w->w_next) {
10140384fff8SJason Evans 		if (w->w_file != NULL)
10150384fff8SJason Evans 			continue;
10160384fff8SJason Evans 		prnt("%s\n", w->w_description);
10170384fff8SJason Evans 	}
10180384fff8SJason Evans }
10190384fff8SJason Evans 
10200384fff8SJason Evans int
1021606f8eb2SJohn Baldwin witness_sleep(int check_only, struct mtx *mtx, const char *file, int line)
10220384fff8SJason Evans {
1023606f8eb2SJohn Baldwin 	struct mtx *m;
10240384fff8SJason Evans 	struct proc *p;
10250384fff8SJason Evans 	char **sleep;
10260384fff8SJason Evans 	int n = 0;
10270384fff8SJason Evans 
10280384fff8SJason Evans 	p = CURPROC;
10290384fff8SJason Evans 	for ((m = LIST_FIRST(&p->p_heldmtx)); m != NULL;
10300384fff8SJason Evans 	    m = LIST_NEXT(m, mtx_held)) {
10310384fff8SJason Evans 		if (m == mtx)
10320384fff8SJason Evans 			continue;
10330384fff8SJason Evans 		for (sleep = sleep_list; *sleep!= NULL; sleep++)
10340384fff8SJason Evans 			if (strcmp(m->mtx_description, *sleep) == 0)
10350384fff8SJason Evans 				goto next;
10360384fff8SJason Evans 		printf("%s:%d: %s with \"%s\" locked from %s:%d\n",
10370384fff8SJason Evans 			file, line, check_only ? "could sleep" : "sleeping",
10380384fff8SJason Evans 			m->mtx_description,
10390384fff8SJason Evans 			m->mtx_witness->w_file, m->mtx_witness->w_line);
10400384fff8SJason Evans 		n++;
10410384fff8SJason Evans 	next:
10420384fff8SJason Evans 	}
1043a5a96a19SJohn Baldwin #ifdef DDB
1044a5a96a19SJohn Baldwin 	if (witness_ddb && n)
1045a5a96a19SJohn Baldwin 		Debugger("witness_sleep");
1046a5a96a19SJohn Baldwin #endif /* DDB */
10470384fff8SJason Evans 	return (n);
10480384fff8SJason Evans }
10490384fff8SJason Evans 
1050606f8eb2SJohn Baldwin static struct witness *
1051b67a3e6eSJohn Baldwin enroll(const char *description, int flag)
10520384fff8SJason Evans {
10530384fff8SJason Evans 	int i;
1054606f8eb2SJohn Baldwin 	struct witness *w, *w1;
10550384fff8SJason Evans 	char **ignore;
10560384fff8SJason Evans 	char **order;
10570384fff8SJason Evans 
10580384fff8SJason Evans 	if (!witness_watch)
10590384fff8SJason Evans 		return (NULL);
10600384fff8SJason Evans 	for (ignore = ignore_list; *ignore != NULL; ignore++)
10610384fff8SJason Evans 		if (strcmp(description, *ignore) == 0)
10620384fff8SJason Evans 			return (NULL);
10630384fff8SJason Evans 
10640384fff8SJason Evans 	if (w_inited == 0) {
1065a5a96a19SJohn Baldwin 		mtx_init(&w_mtx, "witness lock", MTX_COLD | MTX_DEF);
10660384fff8SJason Evans 		for (i = 0; i < WITNESS_COUNT; i++) {
10670384fff8SJason Evans 			w = &w_data[i];
10680384fff8SJason Evans 			witness_free(w);
10690384fff8SJason Evans 		}
10700384fff8SJason Evans 		w_inited = 1;
10710384fff8SJason Evans 		for (order = order_list; *order != NULL; order++) {
10720384fff8SJason Evans 			w = enroll(*order, MTX_DEF);
10730384fff8SJason Evans 			w->w_file = "order list";
10740384fff8SJason Evans 			for (order++; *order != NULL; order++) {
10750384fff8SJason Evans 				w1 = enroll(*order, MTX_DEF);
10760384fff8SJason Evans 				w1->w_file = "order list";
10770384fff8SJason Evans 				itismychild(w, w1);
10780384fff8SJason Evans 				w = w1;
10790384fff8SJason Evans     	    	    	}
10800384fff8SJason Evans 		}
10810384fff8SJason Evans 	}
10820384fff8SJason Evans 	if ((flag & MTX_SPIN) && witness_skipspin)
10830384fff8SJason Evans 		return (NULL);
10840384fff8SJason Evans 	mtx_enter(&w_mtx, MTX_SPIN);
10850384fff8SJason Evans 	for (w = w_all; w; w = w->w_next) {
10860384fff8SJason Evans 		if (strcmp(description, w->w_description) == 0) {
10870384fff8SJason Evans 			mtx_exit(&w_mtx, MTX_SPIN);
10880384fff8SJason Evans 			return (w);
10890384fff8SJason Evans 		}
10900384fff8SJason Evans 	}
10910384fff8SJason Evans 	if ((w = witness_get()) == NULL)
10920384fff8SJason Evans 		return (NULL);
10930384fff8SJason Evans 	w->w_next = w_all;
10940384fff8SJason Evans 	w_all = w;
10950384fff8SJason Evans 	w->w_description = description;
10960384fff8SJason Evans 	mtx_exit(&w_mtx, MTX_SPIN);
10970384fff8SJason Evans 	if (flag & MTX_SPIN) {
10980384fff8SJason Evans 		w->w_spin = 1;
10990384fff8SJason Evans 
11000384fff8SJason Evans 		i = 1;
11010384fff8SJason Evans 		for (order = spin_order_list; *order != NULL; order++) {
11020384fff8SJason Evans 			if (strcmp(description, *order) == 0)
11030384fff8SJason Evans 				break;
11040384fff8SJason Evans 			i <<= 1;
11050384fff8SJason Evans 		}
11060384fff8SJason Evans 		if (*order == NULL)
11070384fff8SJason Evans 			panic("spin lock %s not in order list", description);
11080384fff8SJason Evans 		w->w_level = i;
11090384fff8SJason Evans 	}
11100384fff8SJason Evans 	return (w);
11110384fff8SJason Evans }
11120384fff8SJason Evans 
11130384fff8SJason Evans static int
1114606f8eb2SJohn Baldwin itismychild(struct witness *parent, struct witness *child)
11150384fff8SJason Evans {
11160384fff8SJason Evans 	static int recursed;
11170384fff8SJason Evans 
11180384fff8SJason Evans 	/*
11190384fff8SJason Evans 	 * Insert "child" after "parent"
11200384fff8SJason Evans 	 */
11210384fff8SJason Evans 	while (parent->w_morechildren)
11220384fff8SJason Evans 		parent = parent->w_morechildren;
11230384fff8SJason Evans 
11240384fff8SJason Evans 	if (parent->w_childcnt == WITNESS_NCHILDREN) {
11250384fff8SJason Evans 		if ((parent->w_morechildren = witness_get()) == NULL)
11260384fff8SJason Evans 			return (1);
11270384fff8SJason Evans 		parent = parent->w_morechildren;
11280384fff8SJason Evans 	}
112936412d79SJohn Baldwin 	MPASS(child != NULL);
11300384fff8SJason Evans 	parent->w_children[parent->w_childcnt++] = child;
11310384fff8SJason Evans 	/*
11320384fff8SJason Evans 	 * now prune whole tree
11330384fff8SJason Evans 	 */
11340384fff8SJason Evans 	if (recursed)
11350384fff8SJason Evans 		return (0);
11360384fff8SJason Evans 	recursed = 1;
11370384fff8SJason Evans 	for (child = w_all; child != NULL; child = child->w_next) {
11380384fff8SJason Evans 		for (parent = w_all; parent != NULL;
11390384fff8SJason Evans 		    parent = parent->w_next) {
11400384fff8SJason Evans 			if (!isitmychild(parent, child))
11410384fff8SJason Evans 				continue;
11420384fff8SJason Evans 			removechild(parent, child);
11430384fff8SJason Evans 			if (isitmydescendant(parent, child))
11440384fff8SJason Evans 				continue;
11450384fff8SJason Evans 			itismychild(parent, child);
11460384fff8SJason Evans 		}
11470384fff8SJason Evans 	}
11480384fff8SJason Evans 	recursed = 0;
11490384fff8SJason Evans 	witness_levelall();
11500384fff8SJason Evans 	return (0);
11510384fff8SJason Evans }
11520384fff8SJason Evans 
11530384fff8SJason Evans static void
1154606f8eb2SJohn Baldwin removechild(struct witness *parent, struct witness *child)
11550384fff8SJason Evans {
1156606f8eb2SJohn Baldwin 	struct witness *w, *w1;
11570384fff8SJason Evans 	int i;
11580384fff8SJason Evans 
11590384fff8SJason Evans 	for (w = parent; w != NULL; w = w->w_morechildren)
11600384fff8SJason Evans 		for (i = 0; i < w->w_childcnt; i++)
11610384fff8SJason Evans 			if (w->w_children[i] == child)
11620384fff8SJason Evans 				goto found;
11630384fff8SJason Evans 	return;
11640384fff8SJason Evans found:
11650384fff8SJason Evans 	for (w1 = w; w1->w_morechildren != NULL; w1 = w1->w_morechildren)
11660384fff8SJason Evans 		continue;
11670384fff8SJason Evans 	w->w_children[i] = w1->w_children[--w1->w_childcnt];
116836412d79SJohn Baldwin 	MPASS(w->w_children[i] != NULL);
11690384fff8SJason Evans 
11700384fff8SJason Evans 	if (w1->w_childcnt != 0)
11710384fff8SJason Evans 		return;
11720384fff8SJason Evans 
11730384fff8SJason Evans 	if (w1 == parent)
11740384fff8SJason Evans 		return;
11750384fff8SJason Evans 	for (w = parent; w->w_morechildren != w1; w = w->w_morechildren)
11760384fff8SJason Evans 		continue;
11770384fff8SJason Evans 	w->w_morechildren = 0;
11780384fff8SJason Evans 	witness_free(w1);
11790384fff8SJason Evans }
11800384fff8SJason Evans 
11810384fff8SJason Evans static int
1182606f8eb2SJohn Baldwin isitmychild(struct witness *parent, struct witness *child)
11830384fff8SJason Evans {
1184606f8eb2SJohn Baldwin 	struct witness *w;
11850384fff8SJason Evans 	int i;
11860384fff8SJason Evans 
11870384fff8SJason Evans 	for (w = parent; w != NULL; w = w->w_morechildren) {
11880384fff8SJason Evans 		for (i = 0; i < w->w_childcnt; i++) {
11890384fff8SJason Evans 			if (w->w_children[i] == child)
11900384fff8SJason Evans 				return (1);
11910384fff8SJason Evans 		}
11920384fff8SJason Evans 	}
11930384fff8SJason Evans 	return (0);
11940384fff8SJason Evans }
11950384fff8SJason Evans 
11960384fff8SJason Evans static int
1197606f8eb2SJohn Baldwin isitmydescendant(struct witness *parent, struct witness *child)
11980384fff8SJason Evans {
1199606f8eb2SJohn Baldwin 	struct witness *w;
12000384fff8SJason Evans 	int i;
12010384fff8SJason Evans 	int j;
12020384fff8SJason Evans 
12030384fff8SJason Evans 	for (j = 0, w = parent; w != NULL; w = w->w_morechildren, j++) {
120436412d79SJohn Baldwin 		MPASS(j < 1000);
12050384fff8SJason Evans 		for (i = 0; i < w->w_childcnt; i++) {
12060384fff8SJason Evans 			if (w->w_children[i] == child)
12070384fff8SJason Evans 				return (1);
12080384fff8SJason Evans 		}
12090384fff8SJason Evans 		for (i = 0; i < w->w_childcnt; i++) {
12100384fff8SJason Evans 			if (isitmydescendant(w->w_children[i], child))
12110384fff8SJason Evans 				return (1);
12120384fff8SJason Evans 		}
12130384fff8SJason Evans 	}
12140384fff8SJason Evans 	return (0);
12150384fff8SJason Evans }
12160384fff8SJason Evans 
12170384fff8SJason Evans void
12180384fff8SJason Evans witness_levelall (void)
12190384fff8SJason Evans {
1220606f8eb2SJohn Baldwin 	struct witness *w, *w1;
12210384fff8SJason Evans 
12220384fff8SJason Evans 	for (w = w_all; w; w = w->w_next)
12230384fff8SJason Evans 		if (!w->w_spin)
12240384fff8SJason Evans 			w->w_level = 0;
12250384fff8SJason Evans 	for (w = w_all; w; w = w->w_next) {
12260384fff8SJason Evans 		if (w->w_spin)
12270384fff8SJason Evans 			continue;
12280384fff8SJason Evans 		for (w1 = w_all; w1; w1 = w1->w_next) {
12290384fff8SJason Evans 			if (isitmychild(w1, w))
12300384fff8SJason Evans 				break;
12310384fff8SJason Evans 		}
12320384fff8SJason Evans 		if (w1 != NULL)
12330384fff8SJason Evans 			continue;
12340384fff8SJason Evans 		witness_leveldescendents(w, 0);
12350384fff8SJason Evans 	}
12360384fff8SJason Evans }
12370384fff8SJason Evans 
12380384fff8SJason Evans static void
1239606f8eb2SJohn Baldwin witness_leveldescendents(struct witness *parent, int level)
12400384fff8SJason Evans {
12410384fff8SJason Evans 	int i;
1242606f8eb2SJohn Baldwin 	struct witness *w;
12430384fff8SJason Evans 
12440384fff8SJason Evans 	if (parent->w_level < level)
12450384fff8SJason Evans 		parent->w_level = level;
12460384fff8SJason Evans 	level++;
12470384fff8SJason Evans 	for (w = parent; w != NULL; w = w->w_morechildren)
12480384fff8SJason Evans 		for (i = 0; i < w->w_childcnt; i++)
12490384fff8SJason Evans 			witness_leveldescendents(w->w_children[i], level);
12500384fff8SJason Evans }
12510384fff8SJason Evans 
12520384fff8SJason Evans static void
1253606f8eb2SJohn Baldwin witness_displaydescendants(void(*prnt)(const char *fmt, ...),
1254606f8eb2SJohn Baldwin 			   struct witness *parent)
12550384fff8SJason Evans {
1256606f8eb2SJohn Baldwin 	struct witness *w;
12570384fff8SJason Evans 	int i;
12580384fff8SJason Evans 	int level = parent->w_level;
12590384fff8SJason Evans 
12600384fff8SJason Evans 	prnt("%d", level);
12610384fff8SJason Evans 	if (level < 10)
12620384fff8SJason Evans 		prnt(" ");
12630384fff8SJason Evans 	for (i = 0; i < level; i++)
12640384fff8SJason Evans 		prnt(" ");
12650384fff8SJason Evans 	prnt("%s", parent->w_description);
12660384fff8SJason Evans 	if (parent->w_file != NULL) {
12670384fff8SJason Evans 		prnt(" -- last acquired @ %s", parent->w_file);
12680384fff8SJason Evans #ifndef W_USE_WHERE
12690384fff8SJason Evans 		prnt(":%d", parent->w_line);
12700384fff8SJason Evans #endif
12710384fff8SJason Evans 		prnt("\n");
12720384fff8SJason Evans 	}
12730384fff8SJason Evans 
12740384fff8SJason Evans 	for (w = parent; w != NULL; w = w->w_morechildren)
12750384fff8SJason Evans 		for (i = 0; i < w->w_childcnt; i++)
12760384fff8SJason Evans 			    witness_displaydescendants(prnt, w->w_children[i]);
12770384fff8SJason Evans     }
12780384fff8SJason Evans 
12790384fff8SJason Evans static int
1280606f8eb2SJohn Baldwin dup_ok(struct witness *w)
12810384fff8SJason Evans {
12820384fff8SJason Evans 	char **dup;
12830384fff8SJason Evans 
12840384fff8SJason Evans 	for (dup = dup_list; *dup!= NULL; dup++)
12850384fff8SJason Evans 		if (strcmp(w->w_description, *dup) == 0)
12860384fff8SJason Evans 			return (1);
12870384fff8SJason Evans 	return (0);
12880384fff8SJason Evans }
12890384fff8SJason Evans 
12900384fff8SJason Evans static int
1291606f8eb2SJohn Baldwin blessed(struct witness *w1, struct witness *w2)
12920384fff8SJason Evans {
12930384fff8SJason Evans 	int i;
1294606f8eb2SJohn Baldwin 	struct witness_blessed *b;
12950384fff8SJason Evans 
12960384fff8SJason Evans 	for (i = 0; i < blessed_count; i++) {
12970384fff8SJason Evans 		b = &blessed_list[i];
12980384fff8SJason Evans 		if (strcmp(w1->w_description, b->b_lock1) == 0) {
12990384fff8SJason Evans 			if (strcmp(w2->w_description, b->b_lock2) == 0)
13000384fff8SJason Evans 				return (1);
13010384fff8SJason Evans 			continue;
13020384fff8SJason Evans 		}
13030384fff8SJason Evans 		if (strcmp(w1->w_description, b->b_lock2) == 0)
13040384fff8SJason Evans 			if (strcmp(w2->w_description, b->b_lock1) == 0)
13050384fff8SJason Evans 				return (1);
13060384fff8SJason Evans 	}
13070384fff8SJason Evans 	return (0);
13080384fff8SJason Evans }
13090384fff8SJason Evans 
1310606f8eb2SJohn Baldwin static struct witness *
13110384fff8SJason Evans witness_get()
13120384fff8SJason Evans {
1313606f8eb2SJohn Baldwin 	struct witness *w;
13140384fff8SJason Evans 
13150384fff8SJason Evans 	if ((w = w_free) == NULL) {
13160384fff8SJason Evans 		witness_dead = 1;
13170384fff8SJason Evans 		mtx_exit(&w_mtx, MTX_SPIN);
13180384fff8SJason Evans 		printf("witness exhausted\n");
13190384fff8SJason Evans 		return (NULL);
13200384fff8SJason Evans 	}
13210384fff8SJason Evans 	w_free = w->w_next;
13220384fff8SJason Evans 	bzero(w, sizeof(*w));
13230384fff8SJason Evans 	return (w);
13240384fff8SJason Evans }
13250384fff8SJason Evans 
13260384fff8SJason Evans static void
1327606f8eb2SJohn Baldwin witness_free(struct witness *w)
13280384fff8SJason Evans {
13290384fff8SJason Evans 	w->w_next = w_free;
13300384fff8SJason Evans 	w_free = w;
13310384fff8SJason Evans }
13320384fff8SJason Evans 
13330384fff8SJason Evans void
13340384fff8SJason Evans witness_list(struct proc *p)
13350384fff8SJason Evans {
1336606f8eb2SJohn Baldwin 	struct mtx *m;
13370384fff8SJason Evans 
13380384fff8SJason Evans 	for ((m = LIST_FIRST(&p->p_heldmtx)); m != NULL;
13390384fff8SJason Evans 	    m = LIST_NEXT(m, mtx_held)) {
13400384fff8SJason Evans 		printf("\t\"%s\" (%p) locked at %s:%d\n",
13410384fff8SJason Evans 		    m->mtx_description, m,
13420384fff8SJason Evans 		    m->mtx_witness->w_file, m->mtx_witness->w_line);
13430384fff8SJason Evans 	}
13440384fff8SJason Evans }
13450384fff8SJason Evans 
13460384fff8SJason Evans void
1347606f8eb2SJohn Baldwin witness_save(struct mtx *m, const char **filep, int *linep)
13480384fff8SJason Evans {
13490384fff8SJason Evans 	*filep = m->mtx_witness->w_file;
13500384fff8SJason Evans 	*linep = m->mtx_witness->w_line;
13510384fff8SJason Evans }
13520384fff8SJason Evans 
13530384fff8SJason Evans void
1354606f8eb2SJohn Baldwin witness_restore(struct mtx *m, const char *file, int line)
13550384fff8SJason Evans {
13560384fff8SJason Evans 	m->mtx_witness->w_file = file;
13570384fff8SJason Evans 	m->mtx_witness->w_line = line;
13580384fff8SJason Evans }
13590384fff8SJason Evans 
136036412d79SJohn Baldwin #endif	/* (defined(MUTEX_DEBUG) && defined(WITNESS)) */
1361