xref: /freebsd/sys/kern/kern_mutex.c (revision 36412d79b401fbd3fccb8827480407cc7602e210)
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 
530384fff8SJason Evans #include <sys/param.h>
5436412d79SJohn Baldwin #include <sys/bus.h>
5536412d79SJohn Baldwin #include <sys/kernel.h>
5636412d79SJohn Baldwin #include <sys/malloc.h>
570384fff8SJason Evans #include <sys/proc.h>
580384fff8SJason Evans #include <sys/systm.h>
5936412d79SJohn Baldwin #include <sys/vmmeter.h>
600384fff8SJason Evans #include <sys/ktr.h>
610384fff8SJason Evans 
6236412d79SJohn Baldwin #include <machine/atomic.h>
6336412d79SJohn Baldwin #include <machine/bus.h>
6436412d79SJohn Baldwin #include <machine/clock.h>
650384fff8SJason Evans #include <machine/cpu.h>
6636412d79SJohn Baldwin 
6736412d79SJohn Baldwin #include <vm/vm.h>
6836412d79SJohn Baldwin #include <vm/vm_extern.h>
6936412d79SJohn Baldwin 
700384fff8SJason Evans #define _KERN_MUTEX_C_		/* Cause non-inlined mtx_*() to be compiled. */
7136412d79SJohn Baldwin #include <sys/mutex.h>
7236412d79SJohn Baldwin 
7336412d79SJohn Baldwin /*
7436412d79SJohn Baldwin  * Machine independent bits of the mutex implementation
7536412d79SJohn Baldwin  */
7636412d79SJohn Baldwin /* All mutexes in system (used for debug/panic) */
7736412d79SJohn Baldwin #ifdef MUTEX_DEBUG
7836412d79SJohn Baldwin static struct mtx_debug all_mtx_debug = { NULL, {NULL, NULL}, NULL, 0,
7936412d79SJohn Baldwin 	"All mutexes queue head" };
8036412d79SJohn Baldwin static struct mtx all_mtx = { MTX_UNOWNED, 0, 0, &all_mtx_debug,
8136412d79SJohn Baldwin 	TAILQ_HEAD_INITIALIZER(all_mtx.mtx_blocked),
8236412d79SJohn Baldwin 	{ NULL, NULL }, &all_mtx, &all_mtx };
8336412d79SJohn Baldwin #else	/* MUTEX_DEBUG */
8436412d79SJohn Baldwin static struct mtx all_mtx = { MTX_UNOWNED, 0, 0, "All mutexes queue head",
8536412d79SJohn Baldwin 	TAILQ_HEAD_INITIALIZER(all_mtx.mtx_blocked),
8636412d79SJohn Baldwin 	{ NULL, NULL }, &all_mtx, &all_mtx };
8736412d79SJohn Baldwin #endif	/* MUTEX_DEBUG */
8836412d79SJohn Baldwin 
8936412d79SJohn Baldwin static int	mtx_cur_cnt;
9036412d79SJohn Baldwin static int	mtx_max_cnt;
9136412d79SJohn Baldwin 
9236412d79SJohn Baldwin void	_mtx_enter_giant_def(void);
9336412d79SJohn Baldwin void	_mtx_exit_giant_def(void);
9436412d79SJohn Baldwin static void propagate_priority(struct proc *) __unused;
9536412d79SJohn Baldwin 
9636412d79SJohn Baldwin #define	mtx_unowned(m)	((m)->mtx_lock == MTX_UNOWNED)
9736412d79SJohn Baldwin #define	mtx_owner(m)	(mtx_unowned(m) ? NULL \
9836412d79SJohn Baldwin 			    : (struct proc *)((m)->mtx_lock & MTX_FLAGMASK))
9936412d79SJohn Baldwin 
10036412d79SJohn Baldwin #define RETIP(x)		*(((uintptr_t *)(&x)) - 1)
10136412d79SJohn Baldwin #define	SET_PRIO(p, pri)	(p)->p_priority = (pri)
10236412d79SJohn Baldwin 
10336412d79SJohn Baldwin /*
10436412d79SJohn Baldwin  * XXX Temporary, for use from assembly language
10536412d79SJohn Baldwin  */
10636412d79SJohn Baldwin 
10736412d79SJohn Baldwin void
10836412d79SJohn Baldwin _mtx_enter_giant_def(void)
10936412d79SJohn Baldwin {
11036412d79SJohn Baldwin 
11136412d79SJohn Baldwin 	mtx_enter(&Giant, MTX_DEF);
11236412d79SJohn Baldwin }
11336412d79SJohn Baldwin 
11436412d79SJohn Baldwin void
11536412d79SJohn Baldwin _mtx_exit_giant_def(void)
11636412d79SJohn Baldwin {
11736412d79SJohn Baldwin 
11836412d79SJohn Baldwin 	mtx_exit(&Giant, MTX_DEF);
11936412d79SJohn Baldwin }
12036412d79SJohn Baldwin 
12136412d79SJohn Baldwin static void
12236412d79SJohn Baldwin propagate_priority(struct proc *p)
12336412d79SJohn Baldwin {
12436412d79SJohn Baldwin 	int pri = p->p_priority;
12536412d79SJohn Baldwin 	struct mtx *m = p->p_blocked;
12636412d79SJohn Baldwin 
12736412d79SJohn Baldwin 	for (;;) {
12836412d79SJohn Baldwin 		struct proc *p1;
12936412d79SJohn Baldwin 
13036412d79SJohn Baldwin 		p = mtx_owner(m);
13136412d79SJohn Baldwin 
13236412d79SJohn Baldwin 		if (p == NULL) {
13336412d79SJohn Baldwin 			/*
13436412d79SJohn Baldwin 			 * This really isn't quite right. Really
13536412d79SJohn Baldwin 			 * ought to bump priority of process that
13636412d79SJohn Baldwin 			 * next acquires the mutex.
13736412d79SJohn Baldwin 			 */
13836412d79SJohn Baldwin 			MPASS(m->mtx_lock == MTX_CONTESTED);
13936412d79SJohn Baldwin 			return;
14036412d79SJohn Baldwin 		}
14136412d79SJohn Baldwin 		MPASS(p->p_magic == P_MAGIC);
14236412d79SJohn Baldwin 		if (p->p_priority <= pri)
14336412d79SJohn Baldwin 			return;
14436412d79SJohn Baldwin 		/*
14536412d79SJohn Baldwin 		 * If lock holder is actually running, just bump priority.
14636412d79SJohn Baldwin 		 */
14736412d79SJohn Baldwin 		if (TAILQ_NEXT(p, p_procq) == NULL) {
14836412d79SJohn Baldwin 			MPASS(p->p_stat == SRUN || p->p_stat == SZOMB);
14936412d79SJohn Baldwin 			SET_PRIO(p, pri);
15036412d79SJohn Baldwin 			return;
15136412d79SJohn Baldwin 		}
15236412d79SJohn Baldwin 		/*
15336412d79SJohn Baldwin 		 * If on run queue move to new run queue, and
15436412d79SJohn Baldwin 		 * quit.
15536412d79SJohn Baldwin 		 */
15636412d79SJohn Baldwin 		if (p->p_stat == SRUN) {
15736412d79SJohn Baldwin 			MPASS(p->p_blocked == NULL);
15836412d79SJohn Baldwin 			remrunqueue(p);
15936412d79SJohn Baldwin 			SET_PRIO(p, pri);
16036412d79SJohn Baldwin 			setrunqueue(p);
16136412d79SJohn Baldwin 			return;
16236412d79SJohn Baldwin 		}
16336412d79SJohn Baldwin 
16436412d79SJohn Baldwin 		/*
16536412d79SJohn Baldwin 		 * If we aren't blocked on a mutex, give up and quit.
16636412d79SJohn Baldwin 		 */
16736412d79SJohn Baldwin 		if (p->p_stat != SMTX) {
16836412d79SJohn Baldwin 			printf(
16936412d79SJohn Baldwin 	"XXX: process %d(%s):%d holds %s but isn't blocked on a mutex\n",
17036412d79SJohn Baldwin 			    p->p_pid, p->p_comm, p->p_stat, m->mtx_description);
17136412d79SJohn Baldwin 			return;
17236412d79SJohn Baldwin 		}
17336412d79SJohn Baldwin 
17436412d79SJohn Baldwin 		/*
17536412d79SJohn Baldwin 		 * Pick up the mutex that p is blocked on.
17636412d79SJohn Baldwin 		 */
17736412d79SJohn Baldwin 		m = p->p_blocked;
17836412d79SJohn Baldwin 		MPASS(m != NULL);
17936412d79SJohn Baldwin 
18036412d79SJohn Baldwin 		printf("XXX: process %d(%s) is blocked on %s\n", p->p_pid,
18136412d79SJohn Baldwin 		    p->p_comm, m->mtx_description);
18236412d79SJohn Baldwin 		/*
18336412d79SJohn Baldwin 		 * Check if the proc needs to be moved up on
18436412d79SJohn Baldwin 		 * the blocked chain
18536412d79SJohn Baldwin 		 */
18636412d79SJohn Baldwin 		if ((p1 = TAILQ_PREV(p, rq, p_procq)) == NULL ||
18736412d79SJohn Baldwin 		    p1->p_priority <= pri) {
18836412d79SJohn Baldwin 			if (p1)
18936412d79SJohn Baldwin 				printf(
19036412d79SJohn Baldwin 	"XXX: previous process %d(%s) has higher priority\n",
19136412d79SJohn Baldwin 				    p->p_pid, p->p_comm);
19236412d79SJohn Baldwin 			else
19336412d79SJohn Baldwin 				printf("XXX: process at head of run queue\n");
19436412d79SJohn Baldwin 			continue;
19536412d79SJohn Baldwin 		}
19636412d79SJohn Baldwin 
19736412d79SJohn Baldwin 		/*
19836412d79SJohn Baldwin 		 * Remove proc from blocked chain
19936412d79SJohn Baldwin 		 */
20036412d79SJohn Baldwin 		TAILQ_REMOVE(&m->mtx_blocked, p, p_procq);
20136412d79SJohn Baldwin 		TAILQ_FOREACH(p1, &m->mtx_blocked, p_procq) {
20236412d79SJohn Baldwin 			MPASS(p1->p_magic == P_MAGIC);
20336412d79SJohn Baldwin 			if (p1->p_priority > pri)
20436412d79SJohn Baldwin 				break;
20536412d79SJohn Baldwin 		}
20636412d79SJohn Baldwin 		if (p1)
20736412d79SJohn Baldwin 			TAILQ_INSERT_BEFORE(p1, p, p_procq);
20836412d79SJohn Baldwin 		else
20936412d79SJohn Baldwin 			TAILQ_INSERT_TAIL(&m->mtx_blocked, p, p_procq);
21036412d79SJohn Baldwin 		CTR4(KTR_LOCK,
21136412d79SJohn Baldwin 		    "propagate priority: p 0x%p moved before 0x%p on [0x%p] %s",
21236412d79SJohn Baldwin 		    p, p1, m, m->mtx_description);
21336412d79SJohn Baldwin 	}
21436412d79SJohn Baldwin }
21536412d79SJohn Baldwin 
21636412d79SJohn Baldwin void
21736412d79SJohn Baldwin mtx_enter_hard(struct mtx *m, int type, int saveintr)
21836412d79SJohn Baldwin {
21936412d79SJohn Baldwin 	struct proc *p = CURPROC;
22036412d79SJohn Baldwin 	struct timeval new_switchtime;
22136412d79SJohn Baldwin 
22236412d79SJohn Baldwin 	KASSERT(p != NULL, ("curproc is NULL in mutex"));
22336412d79SJohn Baldwin 
22436412d79SJohn Baldwin 	switch (type) {
22536412d79SJohn Baldwin 	case MTX_DEF:
22636412d79SJohn Baldwin 		if ((m->mtx_lock & MTX_FLAGMASK) == (uintptr_t)p) {
22736412d79SJohn Baldwin 			m->mtx_recurse++;
22836412d79SJohn Baldwin 			atomic_set_ptr(&m->mtx_lock, MTX_RECURSE);
22936412d79SJohn Baldwin 			CTR1(KTR_LOCK, "mtx_enter: 0x%p recurse", m);
23036412d79SJohn Baldwin 			return;
23136412d79SJohn Baldwin 		}
23236412d79SJohn Baldwin 		CTR3(KTR_LOCK, "mtx_enter: 0x%p contested (lock=%p) [0x%p]",
23336412d79SJohn Baldwin 		    m, m->mtx_lock, RETIP(m));
23436412d79SJohn Baldwin 		while (!_obtain_lock(m, p)) {
23536412d79SJohn Baldwin 			int v;
23636412d79SJohn Baldwin 			struct proc *p1;
23736412d79SJohn Baldwin 
23836412d79SJohn Baldwin 			mtx_enter(&sched_lock, MTX_SPIN | MTX_RLIKELY);
23936412d79SJohn Baldwin 			/*
24036412d79SJohn Baldwin 			 * check if the lock has been released while
24136412d79SJohn Baldwin 			 * waiting for the schedlock.
24236412d79SJohn Baldwin 			 */
24336412d79SJohn Baldwin 			if ((v = m->mtx_lock) == MTX_UNOWNED) {
24436412d79SJohn Baldwin 				mtx_exit(&sched_lock, MTX_SPIN);
24536412d79SJohn Baldwin 				continue;
24636412d79SJohn Baldwin 			}
24736412d79SJohn Baldwin 			/*
24836412d79SJohn Baldwin 			 * The mutex was marked contested on release. This
24936412d79SJohn Baldwin 			 * means that there are processes blocked on it.
25036412d79SJohn Baldwin 			 */
25136412d79SJohn Baldwin 			if (v == MTX_CONTESTED) {
25236412d79SJohn Baldwin 				p1 = TAILQ_FIRST(&m->mtx_blocked);
25336412d79SJohn Baldwin 				KASSERT(p1 != NULL, ("contested mutex has no contesters"));
25436412d79SJohn Baldwin 				KASSERT(p != NULL, ("curproc is NULL for contested mutex"));
25536412d79SJohn Baldwin 				m->mtx_lock = (uintptr_t)p | MTX_CONTESTED;
25636412d79SJohn Baldwin 				if (p1->p_priority < p->p_priority) {
25736412d79SJohn Baldwin 					SET_PRIO(p, p1->p_priority);
25836412d79SJohn Baldwin 				}
25936412d79SJohn Baldwin 				mtx_exit(&sched_lock, MTX_SPIN);
26036412d79SJohn Baldwin 				return;
26136412d79SJohn Baldwin 			}
26236412d79SJohn Baldwin 			/*
26336412d79SJohn Baldwin 			 * If the mutex isn't already contested and
26436412d79SJohn Baldwin 			 * a failure occurs setting the contested bit the
26536412d79SJohn Baldwin 			 * mutex was either release or the
26636412d79SJohn Baldwin 			 * state of the RECURSION bit changed.
26736412d79SJohn Baldwin 			 */
26836412d79SJohn Baldwin 			if ((v & MTX_CONTESTED) == 0 &&
26936412d79SJohn Baldwin 			    !atomic_cmpset_ptr(&m->mtx_lock, (void *)v,
27036412d79SJohn Baldwin 				               (void *)(v | MTX_CONTESTED))) {
27136412d79SJohn Baldwin 				mtx_exit(&sched_lock, MTX_SPIN);
27236412d79SJohn Baldwin 				continue;
27336412d79SJohn Baldwin 			}
27436412d79SJohn Baldwin 
27536412d79SJohn Baldwin 			/* We definitely have to sleep for this lock */
27636412d79SJohn Baldwin 			mtx_assert(m, MA_NOTOWNED);
27736412d79SJohn Baldwin 
27836412d79SJohn Baldwin #ifdef notyet
27936412d79SJohn Baldwin 			/*
28036412d79SJohn Baldwin 			 * If we're borrowing an interrupted thread's VM
28136412d79SJohn Baldwin 			 * context must clean up before going to sleep.
28236412d79SJohn Baldwin 			 */
28336412d79SJohn Baldwin 			if (p->p_flag & (P_ITHD | P_SITHD)) {
28436412d79SJohn Baldwin 				ithd_t *it = (ithd_t *)p;
28536412d79SJohn Baldwin 
28636412d79SJohn Baldwin 				if (it->it_interrupted) {
28736412d79SJohn Baldwin 					CTR2(KTR_LOCK,
28836412d79SJohn Baldwin 					    "mtx_enter: 0x%x interrupted 0x%x",
28936412d79SJohn Baldwin 					    it, it->it_interrupted);
29036412d79SJohn Baldwin 					intr_thd_fixup(it);
29136412d79SJohn Baldwin 				}
29236412d79SJohn Baldwin 			}
29336412d79SJohn Baldwin #endif
29436412d79SJohn Baldwin 
29536412d79SJohn Baldwin 			/* Put us on the list of procs blocked on this mutex */
29636412d79SJohn Baldwin 			if (TAILQ_EMPTY(&m->mtx_blocked)) {
29736412d79SJohn Baldwin 				p1 = (struct proc *)(m->mtx_lock &
29836412d79SJohn Baldwin 						     MTX_FLAGMASK);
29936412d79SJohn Baldwin 				LIST_INSERT_HEAD(&p1->p_contested, m,
30036412d79SJohn Baldwin 						 mtx_contested);
30136412d79SJohn Baldwin 				TAILQ_INSERT_TAIL(&m->mtx_blocked, p, p_procq);
30236412d79SJohn Baldwin 			} else {
30336412d79SJohn Baldwin 				TAILQ_FOREACH(p1, &m->mtx_blocked, p_procq)
30436412d79SJohn Baldwin 					if (p1->p_priority > p->p_priority)
30536412d79SJohn Baldwin 						break;
30636412d79SJohn Baldwin 				if (p1)
30736412d79SJohn Baldwin 					TAILQ_INSERT_BEFORE(p1, p, p_procq);
30836412d79SJohn Baldwin 				else
30936412d79SJohn Baldwin 					TAILQ_INSERT_TAIL(&m->mtx_blocked, p,
31036412d79SJohn Baldwin 							  p_procq);
31136412d79SJohn Baldwin 			}
31236412d79SJohn Baldwin 
31336412d79SJohn Baldwin 			p->p_blocked = m;	/* Who we're blocked on */
31436412d79SJohn Baldwin 			p->p_stat = SMTX;
31536412d79SJohn Baldwin #if 0
31636412d79SJohn Baldwin 			propagate_priority(p);
31736412d79SJohn Baldwin #endif
31836412d79SJohn Baldwin 			CTR3(KTR_LOCK, "mtx_enter: p 0x%p blocked on [0x%p] %s",
31936412d79SJohn Baldwin 			    p, m, m->mtx_description);
32036412d79SJohn Baldwin 			/*
32136412d79SJohn Baldwin 			 * Blatantly copied from mi_switch nearly verbatim.
32236412d79SJohn Baldwin 			 * When Giant goes away and we stop dinking with it
32336412d79SJohn Baldwin 			 * in mi_switch, we can go back to calling mi_switch
32436412d79SJohn Baldwin 			 * directly here.
32536412d79SJohn Baldwin 			 */
32636412d79SJohn Baldwin 
32736412d79SJohn Baldwin 			/*
32836412d79SJohn Baldwin 			 * Compute the amount of time during which the current
32936412d79SJohn Baldwin 			 * process was running, and add that to its total so
33036412d79SJohn Baldwin 			 * far.
33136412d79SJohn Baldwin 			 */
33236412d79SJohn Baldwin 			microuptime(&new_switchtime);
33336412d79SJohn Baldwin 			if (timevalcmp(&new_switchtime, &switchtime, <)) {
33436412d79SJohn Baldwin 				printf(
33536412d79SJohn Baldwin 		    "microuptime() went backwards (%ld.%06ld -> %ld.%06ld)\n",
33636412d79SJohn Baldwin 		    		    switchtime.tv_sec, switchtime.tv_usec,
33736412d79SJohn Baldwin 		    		    new_switchtime.tv_sec,
33836412d79SJohn Baldwin 		    		    new_switchtime.tv_usec);
33936412d79SJohn Baldwin 				new_switchtime = switchtime;
34036412d79SJohn Baldwin 			} else {
34136412d79SJohn Baldwin 				p->p_runtime += (new_switchtime.tv_usec -
34236412d79SJohn Baldwin 				    switchtime.tv_usec) +
34336412d79SJohn Baldwin 				    (new_switchtime.tv_sec - switchtime.tv_sec) *
34436412d79SJohn Baldwin 				    (int64_t)1000000;
34536412d79SJohn Baldwin 			}
34636412d79SJohn Baldwin 
34736412d79SJohn Baldwin 			/*
34836412d79SJohn Baldwin 			 * Pick a new current process and record its start time.
34936412d79SJohn Baldwin 			 */
35036412d79SJohn Baldwin 			cnt.v_swtch++;
35136412d79SJohn Baldwin 			switchtime = new_switchtime;
35236412d79SJohn Baldwin 			cpu_switch();
35336412d79SJohn Baldwin 			if (switchtime.tv_sec == 0)
35436412d79SJohn Baldwin 				microuptime(&switchtime);
35536412d79SJohn Baldwin 			switchticks = ticks;
35636412d79SJohn Baldwin 			CTR3(KTR_LOCK,
35736412d79SJohn Baldwin 			    "mtx_enter: p 0x%p free from blocked on [0x%p] %s",
35836412d79SJohn Baldwin 			    p, m, m->mtx_description);
35936412d79SJohn Baldwin 			mtx_exit(&sched_lock, MTX_SPIN);
36036412d79SJohn Baldwin 		}
36136412d79SJohn Baldwin 		return;
36236412d79SJohn Baldwin 	case MTX_SPIN:
36336412d79SJohn Baldwin 	case MTX_SPIN | MTX_FIRST:
36436412d79SJohn Baldwin 	case MTX_SPIN | MTX_TOPHALF:
36536412d79SJohn Baldwin 	    {
36636412d79SJohn Baldwin 		int i = 0;
36736412d79SJohn Baldwin 
36836412d79SJohn Baldwin 		if (m->mtx_lock == (uintptr_t)p) {
36936412d79SJohn Baldwin 			m->mtx_recurse++;
37036412d79SJohn Baldwin 			return;
37136412d79SJohn Baldwin 		}
37236412d79SJohn Baldwin 		CTR1(KTR_LOCK, "mtx_enter: %p spinning", m);
37336412d79SJohn Baldwin 		for (;;) {
37436412d79SJohn Baldwin 			if (_obtain_lock(m, p))
37536412d79SJohn Baldwin 				break;
37636412d79SJohn Baldwin 			while (m->mtx_lock != MTX_UNOWNED) {
37736412d79SJohn Baldwin 				if (i++ < 1000000)
37836412d79SJohn Baldwin 					continue;
37936412d79SJohn Baldwin 				if (i++ < 6000000)
38036412d79SJohn Baldwin 					DELAY (1);
38136412d79SJohn Baldwin #ifdef DDB
38236412d79SJohn Baldwin 				else if (!db_active)
38336412d79SJohn Baldwin #else
38436412d79SJohn Baldwin 				else
38536412d79SJohn Baldwin #endif
38636412d79SJohn Baldwin 					panic(
38736412d79SJohn Baldwin 				"spin lock %s held by 0x%p for > 5 seconds",
38836412d79SJohn Baldwin 					    m->mtx_description,
38936412d79SJohn Baldwin 					    (void *)m->mtx_lock);
39036412d79SJohn Baldwin 			}
39136412d79SJohn Baldwin 		}
39236412d79SJohn Baldwin 
39336412d79SJohn Baldwin #ifdef MUTEX_DEBUG
39436412d79SJohn Baldwin 		if (type != MTX_SPIN)
39536412d79SJohn Baldwin 			m->mtx_saveintr = 0xbeefface;
39636412d79SJohn Baldwin 		else
39736412d79SJohn Baldwin #endif
39836412d79SJohn Baldwin 			m->mtx_saveintr = saveintr;
39936412d79SJohn Baldwin 		CTR1(KTR_LOCK, "mtx_enter: 0x%p spin done", m);
40036412d79SJohn Baldwin 		return;
40136412d79SJohn Baldwin 	    }
40236412d79SJohn Baldwin 	}
40336412d79SJohn Baldwin }
40436412d79SJohn Baldwin 
40536412d79SJohn Baldwin void
40636412d79SJohn Baldwin mtx_exit_hard(struct mtx *m, int type)
40736412d79SJohn Baldwin {
40836412d79SJohn Baldwin 	struct proc *p, *p1;
40936412d79SJohn Baldwin 	struct mtx *m1;
41036412d79SJohn Baldwin 	int pri;
41136412d79SJohn Baldwin 
41236412d79SJohn Baldwin 	p = CURPROC;
41336412d79SJohn Baldwin 	switch (type) {
41436412d79SJohn Baldwin 	case MTX_DEF:
41536412d79SJohn Baldwin 	case MTX_DEF | MTX_NOSWITCH:
41636412d79SJohn Baldwin 		if (m->mtx_recurse != 0) {
41736412d79SJohn Baldwin 			if (--(m->mtx_recurse) == 0)
41836412d79SJohn Baldwin 				atomic_clear_ptr(&m->mtx_lock, MTX_RECURSE);
41936412d79SJohn Baldwin 			CTR1(KTR_LOCK, "mtx_exit: 0x%p unrecurse", m);
42036412d79SJohn Baldwin 			return;
42136412d79SJohn Baldwin 		}
42236412d79SJohn Baldwin 		mtx_enter(&sched_lock, MTX_SPIN);
42336412d79SJohn Baldwin 		CTR1(KTR_LOCK, "mtx_exit: 0x%p contested", m);
42436412d79SJohn Baldwin 		p1 = TAILQ_FIRST(&m->mtx_blocked);
42536412d79SJohn Baldwin 		MPASS(p->p_magic == P_MAGIC);
42636412d79SJohn Baldwin 		MPASS(p1->p_magic == P_MAGIC);
42736412d79SJohn Baldwin 		TAILQ_REMOVE(&m->mtx_blocked, p1, p_procq);
42836412d79SJohn Baldwin 		if (TAILQ_EMPTY(&m->mtx_blocked)) {
42936412d79SJohn Baldwin 			LIST_REMOVE(m, mtx_contested);
43036412d79SJohn Baldwin 			_release_lock_quick(m);
43136412d79SJohn Baldwin 			CTR1(KTR_LOCK, "mtx_exit: 0x%p not held", m);
43236412d79SJohn Baldwin 		} else
43336412d79SJohn Baldwin 			m->mtx_lock = MTX_CONTESTED;
43436412d79SJohn Baldwin 		pri = MAXPRI;
43536412d79SJohn Baldwin 		LIST_FOREACH(m1, &p->p_contested, mtx_contested) {
43636412d79SJohn Baldwin 			int cp = TAILQ_FIRST(&m1->mtx_blocked)->p_priority;
43736412d79SJohn Baldwin 			if (cp < pri)
43836412d79SJohn Baldwin 				pri = cp;
43936412d79SJohn Baldwin 		}
44036412d79SJohn Baldwin 		if (pri > p->p_nativepri)
44136412d79SJohn Baldwin 			pri = p->p_nativepri;
44236412d79SJohn Baldwin 		SET_PRIO(p, pri);
44336412d79SJohn Baldwin 		CTR2(KTR_LOCK, "mtx_exit: 0x%p contested setrunqueue 0x%p",
44436412d79SJohn Baldwin 		    m, p1);
44536412d79SJohn Baldwin 		p1->p_blocked = NULL;
44636412d79SJohn Baldwin 		p1->p_stat = SRUN;
44736412d79SJohn Baldwin 		setrunqueue(p1);
44836412d79SJohn Baldwin 		if ((type & MTX_NOSWITCH) == 0 && p1->p_priority < pri) {
44936412d79SJohn Baldwin #ifdef notyet
45036412d79SJohn Baldwin 			if (p->p_flag & (P_ITHD | P_SITHD)) {
45136412d79SJohn Baldwin 				ithd_t *it = (ithd_t *)p;
45236412d79SJohn Baldwin 
45336412d79SJohn Baldwin 				if (it->it_interrupted) {
45436412d79SJohn Baldwin 					CTR2(KTR_LOCK,
45536412d79SJohn Baldwin 					    "mtx_exit: 0x%x interruped 0x%x",
45636412d79SJohn Baldwin 					    it, it->it_interrupted);
45736412d79SJohn Baldwin 					intr_thd_fixup(it);
45836412d79SJohn Baldwin 				}
45936412d79SJohn Baldwin 			}
46036412d79SJohn Baldwin #endif
46136412d79SJohn Baldwin 			setrunqueue(p);
46236412d79SJohn Baldwin 			CTR2(KTR_LOCK, "mtx_exit: 0x%p switching out lock=0x%p",
46336412d79SJohn Baldwin 			    m, m->mtx_lock);
46436412d79SJohn Baldwin 			mi_switch();
46536412d79SJohn Baldwin 			CTR2(KTR_LOCK, "mtx_exit: 0x%p resuming lock=0x%p",
46636412d79SJohn Baldwin 			    m, m->mtx_lock);
46736412d79SJohn Baldwin 		}
46836412d79SJohn Baldwin 		mtx_exit(&sched_lock, MTX_SPIN);
46936412d79SJohn Baldwin 		break;
47036412d79SJohn Baldwin 	case MTX_SPIN:
47136412d79SJohn Baldwin 	case MTX_SPIN | MTX_FIRST:
47236412d79SJohn Baldwin 		if (m->mtx_recurse != 0) {
47336412d79SJohn Baldwin 			m->mtx_recurse--;
47436412d79SJohn Baldwin 			return;
47536412d79SJohn Baldwin 		}
47636412d79SJohn Baldwin 		MPASS(mtx_owned(m));
47736412d79SJohn Baldwin 		_release_lock_quick(m);
47836412d79SJohn Baldwin 		if (type & MTX_FIRST)
47936412d79SJohn Baldwin 			enable_intr();	/* XXX is this kosher? */
48036412d79SJohn Baldwin 		else {
48136412d79SJohn Baldwin 			MPASS(m->mtx_saveintr != 0xbeefface);
48236412d79SJohn Baldwin 			restore_intr(m->mtx_saveintr);
48336412d79SJohn Baldwin 		}
48436412d79SJohn Baldwin 		break;
48536412d79SJohn Baldwin 	case MTX_SPIN | MTX_TOPHALF:
48636412d79SJohn Baldwin 		if (m->mtx_recurse != 0) {
48736412d79SJohn Baldwin 			m->mtx_recurse--;
48836412d79SJohn Baldwin 			return;
48936412d79SJohn Baldwin 		}
49036412d79SJohn Baldwin 		MPASS(mtx_owned(m));
49136412d79SJohn Baldwin 		_release_lock_quick(m);
49236412d79SJohn Baldwin 		break;
49336412d79SJohn Baldwin 	default:
49436412d79SJohn Baldwin 		panic("mtx_exit_hard: unsupported type 0x%x\n", type);
49536412d79SJohn Baldwin 	}
49636412d79SJohn Baldwin }
49736412d79SJohn Baldwin 
49836412d79SJohn Baldwin #define MV_DESTROY	0	/* validate before destory */
49936412d79SJohn Baldwin #define MV_INIT		1	/* validate before init */
50036412d79SJohn Baldwin 
50136412d79SJohn Baldwin #ifdef MUTEX_DEBUG
50236412d79SJohn Baldwin 
50336412d79SJohn Baldwin int mtx_validate __P((struct mtx *, int));
50436412d79SJohn Baldwin 
50536412d79SJohn Baldwin int
50636412d79SJohn Baldwin mtx_validate(struct mtx *m, int when)
50736412d79SJohn Baldwin {
50836412d79SJohn Baldwin 	struct mtx *mp;
50936412d79SJohn Baldwin 	int i;
51036412d79SJohn Baldwin 	int retval = 0;
51136412d79SJohn Baldwin 
51236412d79SJohn Baldwin 	if (m == &all_mtx || cold)
51336412d79SJohn Baldwin 		return 0;
51436412d79SJohn Baldwin 
51536412d79SJohn Baldwin 	mtx_enter(&all_mtx, MTX_DEF);
51636412d79SJohn Baldwin /*
51736412d79SJohn Baldwin  * XXX - When kernacc() is fixed on the alpha to handle K0_SEG memory properly
51836412d79SJohn Baldwin  * we can re-enable the kernacc() checks.
51936412d79SJohn Baldwin  */
52036412d79SJohn Baldwin #ifndef __alpha__
52136412d79SJohn Baldwin 	MPASS(kernacc((caddr_t)all_mtx.mtx_next, sizeof(uintptr_t),
52236412d79SJohn Baldwin 	    VM_PROT_READ) == 1);
52336412d79SJohn Baldwin #endif
52436412d79SJohn Baldwin 	MPASS(all_mtx.mtx_next->mtx_prev == &all_mtx);
52536412d79SJohn Baldwin 	for (i = 0, mp = all_mtx.mtx_next; mp != &all_mtx; mp = mp->mtx_next) {
52636412d79SJohn Baldwin #ifndef __alpha__
52736412d79SJohn Baldwin 		if (kernacc((caddr_t)mp->mtx_next, sizeof(uintptr_t),
52836412d79SJohn Baldwin 		    VM_PROT_READ) != 1) {
52936412d79SJohn Baldwin 			panic("mtx_validate: mp=%p mp->mtx_next=%p",
53036412d79SJohn Baldwin 			    mp, mp->mtx_next);
53136412d79SJohn Baldwin 		}
53236412d79SJohn Baldwin #endif
53336412d79SJohn Baldwin 		i++;
53436412d79SJohn Baldwin 		if (i > mtx_cur_cnt) {
53536412d79SJohn Baldwin 			panic("mtx_validate: too many in chain, known=%d\n",
53636412d79SJohn Baldwin 			    mtx_cur_cnt);
53736412d79SJohn Baldwin 		}
53836412d79SJohn Baldwin 	}
53936412d79SJohn Baldwin 	MPASS(i == mtx_cur_cnt);
54036412d79SJohn Baldwin 	switch (when) {
54136412d79SJohn Baldwin 	case MV_DESTROY:
54236412d79SJohn Baldwin 		for (mp = all_mtx.mtx_next; mp != &all_mtx; mp = mp->mtx_next)
54336412d79SJohn Baldwin 			if (mp == m)
54436412d79SJohn Baldwin 				break;
54536412d79SJohn Baldwin 		MPASS(mp == m);
54636412d79SJohn Baldwin 		break;
54736412d79SJohn Baldwin 	case MV_INIT:
54836412d79SJohn Baldwin 		for (mp = all_mtx.mtx_next; mp != &all_mtx; mp = mp->mtx_next)
54936412d79SJohn Baldwin 		if (mp == m) {
55036412d79SJohn Baldwin 			/*
55136412d79SJohn Baldwin 			 * Not good. This mutex already exists.
55236412d79SJohn Baldwin 			 */
55336412d79SJohn Baldwin 			printf("re-initing existing mutex %s\n",
55436412d79SJohn Baldwin 			    m->mtx_description);
55536412d79SJohn Baldwin 			MPASS(m->mtx_lock == MTX_UNOWNED);
55636412d79SJohn Baldwin 			retval = 1;
55736412d79SJohn Baldwin 		}
55836412d79SJohn Baldwin 	}
55936412d79SJohn Baldwin 	mtx_exit(&all_mtx, MTX_DEF);
56036412d79SJohn Baldwin 	return (retval);
56136412d79SJohn Baldwin }
56236412d79SJohn Baldwin #endif
56336412d79SJohn Baldwin 
56436412d79SJohn Baldwin void
56536412d79SJohn Baldwin mtx_init(struct mtx *m, const char *t, int flag)
56636412d79SJohn Baldwin {
56736412d79SJohn Baldwin #ifdef MUTEX_DEBUG
56836412d79SJohn Baldwin 	struct mtx_debug *debug;
56936412d79SJohn Baldwin #endif
57036412d79SJohn Baldwin 
57136412d79SJohn Baldwin 	CTR2(KTR_LOCK, "mtx_init 0x%p (%s)", m, t);
57236412d79SJohn Baldwin #ifdef MUTEX_DEBUG
57336412d79SJohn Baldwin 	if (mtx_validate(m, MV_INIT))	/* diagnostic and error correction */
57436412d79SJohn Baldwin 		return;
57536412d79SJohn Baldwin 	if (flag & MTX_COLD)
57636412d79SJohn Baldwin 		debug = m->mtx_debug;
57736412d79SJohn Baldwin 	else
57836412d79SJohn Baldwin 		debug = NULL;
57936412d79SJohn Baldwin 	if (debug == NULL) {
58036412d79SJohn Baldwin #ifdef DIAGNOSTIC
58136412d79SJohn Baldwin 		if(cold && bootverbose)
58236412d79SJohn Baldwin 			printf("malloc'ing mtx_debug while cold for %s\n", t);
58336412d79SJohn Baldwin #endif
58436412d79SJohn Baldwin 
58536412d79SJohn Baldwin 		/* XXX - should not use DEVBUF */
58636412d79SJohn Baldwin 		debug = malloc(sizeof(struct mtx_debug), M_DEVBUF, M_NOWAIT);
58736412d79SJohn Baldwin 		MPASS(debug != NULL);
58836412d79SJohn Baldwin 		bzero(debug, sizeof(struct mtx_debug));
58936412d79SJohn Baldwin 	}
59036412d79SJohn Baldwin #endif
59136412d79SJohn Baldwin 	bzero((void *)m, sizeof *m);
59236412d79SJohn Baldwin 	TAILQ_INIT(&m->mtx_blocked);
59336412d79SJohn Baldwin #ifdef MUTEX_DEBUG
59436412d79SJohn Baldwin 	m->mtx_debug = debug;
59536412d79SJohn Baldwin #endif
59636412d79SJohn Baldwin 	m->mtx_description = t;
59736412d79SJohn Baldwin 	m->mtx_lock = MTX_UNOWNED;
59836412d79SJohn Baldwin 	/* Put on all mutex queue */
59936412d79SJohn Baldwin 	mtx_enter(&all_mtx, MTX_DEF);
60036412d79SJohn Baldwin 	m->mtx_next = &all_mtx;
60136412d79SJohn Baldwin 	m->mtx_prev = all_mtx.mtx_prev;
60236412d79SJohn Baldwin 	m->mtx_prev->mtx_next = m;
60336412d79SJohn Baldwin 	all_mtx.mtx_prev = m;
60436412d79SJohn Baldwin 	if (++mtx_cur_cnt > mtx_max_cnt)
60536412d79SJohn Baldwin 		mtx_max_cnt = mtx_cur_cnt;
60636412d79SJohn Baldwin 	mtx_exit(&all_mtx, MTX_DEF);
60736412d79SJohn Baldwin 	witness_init(m, flag);
60836412d79SJohn Baldwin }
60936412d79SJohn Baldwin 
61036412d79SJohn Baldwin void
61136412d79SJohn Baldwin mtx_destroy(struct mtx *m)
61236412d79SJohn Baldwin {
61336412d79SJohn Baldwin 
61436412d79SJohn Baldwin 	CTR2(KTR_LOCK, "mtx_destroy 0x%p (%s)", m, m->mtx_description);
61536412d79SJohn Baldwin #ifdef MUTEX_DEBUG
61636412d79SJohn Baldwin 	if (m->mtx_next == NULL)
61736412d79SJohn Baldwin 		panic("mtx_destroy: %p (%s) already destroyed",
61836412d79SJohn Baldwin 		    m, m->mtx_description);
61936412d79SJohn Baldwin 
62036412d79SJohn Baldwin 	if (!mtx_owned(m)) {
62136412d79SJohn Baldwin 		MPASS(m->mtx_lock == MTX_UNOWNED);
62236412d79SJohn Baldwin 	} else {
62336412d79SJohn Baldwin 		MPASS((m->mtx_lock & (MTX_RECURSE|MTX_CONTESTED)) == 0);
62436412d79SJohn Baldwin 	}
62536412d79SJohn Baldwin 	mtx_validate(m, MV_DESTROY);		/* diagnostic */
62636412d79SJohn Baldwin #endif
62736412d79SJohn Baldwin 
62836412d79SJohn Baldwin #ifdef WITNESS
62936412d79SJohn Baldwin 	if (m->mtx_witness)
63036412d79SJohn Baldwin 		witness_destroy(m);
63136412d79SJohn Baldwin #endif /* WITNESS */
63236412d79SJohn Baldwin 
63336412d79SJohn Baldwin 	/* Remove from the all mutex queue */
63436412d79SJohn Baldwin 	mtx_enter(&all_mtx, MTX_DEF);
63536412d79SJohn Baldwin 	m->mtx_next->mtx_prev = m->mtx_prev;
63636412d79SJohn Baldwin 	m->mtx_prev->mtx_next = m->mtx_next;
63736412d79SJohn Baldwin #ifdef MUTEX_DEBUG
63836412d79SJohn Baldwin 	m->mtx_next = m->mtx_prev = NULL;
63936412d79SJohn Baldwin 	free(m->mtx_debug, M_DEVBUF);
64036412d79SJohn Baldwin 	m->mtx_debug = NULL;
64136412d79SJohn Baldwin #endif
64236412d79SJohn Baldwin 	mtx_cur_cnt--;
64336412d79SJohn Baldwin 	mtx_exit(&all_mtx, MTX_DEF);
64436412d79SJohn Baldwin }
6450384fff8SJason Evans 
6460384fff8SJason Evans /*
6470384fff8SJason Evans  * The non-inlined versions of the mtx_*() functions are always built (above),
64836412d79SJohn Baldwin  * but the witness code depends on the MUTEX_DEBUG and WITNESS kernel options
6490384fff8SJason Evans  * being specified.
6500384fff8SJason Evans  */
65136412d79SJohn Baldwin #if (defined(MUTEX_DEBUG) && defined(WITNESS))
6520384fff8SJason Evans 
6530384fff8SJason Evans #define WITNESS_COUNT 200
6540384fff8SJason Evans #define	WITNESS_NCHILDREN 2
6550384fff8SJason Evans 
6560384fff8SJason Evans #ifndef WITNESS
6570384fff8SJason Evans #define	WITNESS		0	/* default off */
6580384fff8SJason Evans #endif
6590384fff8SJason Evans 
6600384fff8SJason Evans #ifndef SMP
6610384fff8SJason Evans extern int witness_spin_check;
6620384fff8SJason Evans #endif
6630384fff8SJason Evans 
6640384fff8SJason Evans int witness_watch;
6650384fff8SJason Evans 
666606f8eb2SJohn Baldwin struct witness {
6670384fff8SJason Evans 	struct witness	*w_next;
6680384fff8SJason Evans 	char		*w_description;
66912473b76SJason Evans 	const char	*w_file;
6700384fff8SJason Evans 	int		 w_line;
6710384fff8SJason Evans 	struct witness	*w_morechildren;
6720384fff8SJason Evans 	u_char		 w_childcnt;
6730384fff8SJason Evans 	u_char		 w_Giant_squawked:1;
6740384fff8SJason Evans 	u_char		 w_other_squawked:1;
6750384fff8SJason Evans 	u_char		 w_same_squawked:1;
6760384fff8SJason Evans 	u_char		 w_sleep:1;
6770384fff8SJason Evans 	u_char		 w_spin:1;	/* this is a spin mutex */
6780384fff8SJason Evans 	u_int		 w_level;
6790384fff8SJason Evans 	struct witness	*w_children[WITNESS_NCHILDREN];
680606f8eb2SJohn Baldwin };
6810384fff8SJason Evans 
682606f8eb2SJohn Baldwin struct witness_blessed {
6830384fff8SJason Evans 	char 	*b_lock1;
6840384fff8SJason Evans 	char	*b_lock2;
685606f8eb2SJohn Baldwin };
6860384fff8SJason Evans 
6870384fff8SJason Evans #ifdef KDEBUG
6880384fff8SJason Evans /*
6890384fff8SJason Evans  * When WITNESS_KDEBUG is set to 1, it will cause the system to
6900384fff8SJason Evans  * drop into kdebug() when:
6910384fff8SJason Evans  *	- a lock heirarchy violation occurs
6920384fff8SJason Evans  *	- locks are held when going to sleep.
6930384fff8SJason Evans  */
6940384fff8SJason Evans #ifndef WITNESS_KDEBUG
6950384fff8SJason Evans #define WITNESS_KDEBUG 0
6960384fff8SJason Evans #endif
6970384fff8SJason Evans int	witness_kdebug = WITNESS_KDEBUG;
6980384fff8SJason Evans #endif /* KDEBUG */
6990384fff8SJason Evans 
7000384fff8SJason Evans #ifndef WITNESS_SKIPSPIN
7010384fff8SJason Evans #define WITNESS_SKIPSPIN 0
7020384fff8SJason Evans #endif
7030384fff8SJason Evans int	witness_skipspin = WITNESS_SKIPSPIN;
7040384fff8SJason Evans 
7050384fff8SJason Evans 
706606f8eb2SJohn Baldwin static struct mtx	 w_mtx;
707606f8eb2SJohn Baldwin static struct witness	*w_free;
708606f8eb2SJohn Baldwin static struct witness	*w_all;
7090384fff8SJason Evans static int		 w_inited;
7100384fff8SJason Evans static int		 witness_dead;	/* fatal error, probably no memory */
7110384fff8SJason Evans 
712606f8eb2SJohn Baldwin static struct witness	 w_data[WITNESS_COUNT];
7130384fff8SJason Evans 
714606f8eb2SJohn Baldwin static struct witness	 *enroll __P((char *description, int flag));
715606f8eb2SJohn Baldwin static int itismychild __P((struct witness *parent, struct witness *child));
716606f8eb2SJohn Baldwin static void removechild __P((struct witness *parent, struct witness *child));
717606f8eb2SJohn Baldwin static int isitmychild __P((struct witness *parent, struct witness *child));
718606f8eb2SJohn Baldwin static int isitmydescendant __P((struct witness *parent, struct witness *child));
719606f8eb2SJohn Baldwin static int dup_ok __P((struct witness *));
720606f8eb2SJohn Baldwin static int blessed __P((struct witness *, struct witness *));
7210384fff8SJason Evans static void witness_displaydescendants
722606f8eb2SJohn Baldwin     __P((void(*)(const char *fmt, ...), struct witness *));
723606f8eb2SJohn Baldwin static void witness_leveldescendents __P((struct witness *parent, int level));
7240384fff8SJason Evans static void witness_levelall __P((void));
725606f8eb2SJohn Baldwin static struct witness * witness_get __P((void));
726606f8eb2SJohn Baldwin static void witness_free __P((struct witness *m));
7270384fff8SJason Evans 
7280384fff8SJason Evans 
7290384fff8SJason Evans static char *ignore_list[] = {
7300384fff8SJason Evans 	"witness lock",
7310384fff8SJason Evans 	"Kdebug",		/* breaks rules and may or may not work */
7320384fff8SJason Evans 	"Page Alias",		/* sparc only, witness lock won't block intr */
7330384fff8SJason Evans 	NULL
7340384fff8SJason Evans };
7350384fff8SJason Evans 
7360384fff8SJason Evans static char *spin_order_list[] = {
7370384fff8SJason Evans 	"sched lock",
7380384fff8SJason Evans 	"log mtx",
7390384fff8SJason Evans 	"zslock",	/* sparc only above log, this one is a real hack */
7400384fff8SJason Evans 	"time lock",	/* above callout */
7410384fff8SJason Evans 	"callout mtx",	/* above wayout */
7420384fff8SJason Evans 	/*
7430384fff8SJason Evans 	 * leaf locks
7440384fff8SJason Evans 	 */
7450384fff8SJason Evans 	"wayout mtx",
7460384fff8SJason Evans 	"kernel_pmap",  /* sparc only, logically equal "pmap" below */
7470384fff8SJason Evans 	"pmap",		/* sparc only */
7480384fff8SJason Evans 	NULL
7490384fff8SJason Evans };
7500384fff8SJason Evans 
7510384fff8SJason Evans static char *order_list[] = {
7520384fff8SJason Evans 	"tcb", "inp", "so_snd", "so_rcv", "Giant lock", NULL,
7530384fff8SJason Evans 	"udb", "inp", NULL,
7540384fff8SJason Evans 	"unp head", "unp", "so_snd", NULL,
7550384fff8SJason Evans 	"de0", "Giant lock", NULL,
7560384fff8SJason Evans 	"ifnet", "Giant lock", NULL,
7570384fff8SJason Evans 	"fifo", "so_snd", NULL,
7580384fff8SJason Evans 	"hme0", "Giant lock", NULL,
7590384fff8SJason Evans 	"esp0", "Giant lock", NULL,
7600384fff8SJason Evans 	"hfa0", "Giant lock", NULL,
7610384fff8SJason Evans 	"so_rcv", "atm_global", NULL,
7620384fff8SJason Evans 	"so_snd", "atm_global", NULL,
7630384fff8SJason Evans 	"NFS", "Giant lock", NULL,
7640384fff8SJason Evans 	NULL
7650384fff8SJason Evans };
7660384fff8SJason Evans 
7670384fff8SJason Evans static char *dup_list[] = {
7680384fff8SJason Evans 	"inp",
7690384fff8SJason Evans 	"process group",
7700384fff8SJason Evans 	"session",
7710384fff8SJason Evans 	"unp",
7720384fff8SJason Evans 	"rtentry",
7730384fff8SJason Evans 	"rawcb",
7740384fff8SJason Evans 	NULL
7750384fff8SJason Evans };
7760384fff8SJason Evans 
7770384fff8SJason Evans static char *sleep_list[] = {
7780384fff8SJason Evans 	"Giant lock",
7790384fff8SJason Evans 	NULL
7800384fff8SJason Evans };
7810384fff8SJason Evans 
7820384fff8SJason Evans /*
7830384fff8SJason Evans  * Pairs of locks which have been blessed
7840384fff8SJason Evans  * Don't complain about order problems with blessed locks
7850384fff8SJason Evans  */
786606f8eb2SJohn Baldwin static struct witness_blessed blessed_list[] = {
7870384fff8SJason Evans };
788606f8eb2SJohn Baldwin static int blessed_count = sizeof(blessed_list) / sizeof(struct witness_blessed);
7890384fff8SJason Evans 
7900384fff8SJason Evans void
791606f8eb2SJohn Baldwin witness_init(struct mtx *m, int flag)
7920384fff8SJason Evans {
7930384fff8SJason Evans 	m->mtx_witness = enroll(m->mtx_description, flag);
7940384fff8SJason Evans }
7950384fff8SJason Evans 
7960384fff8SJason Evans void
797606f8eb2SJohn Baldwin witness_destroy(struct mtx *m)
7980384fff8SJason Evans {
799606f8eb2SJohn Baldwin 	struct mtx *m1;
8000384fff8SJason Evans 	struct proc *p;
8010384fff8SJason Evans 	p = CURPROC;
8020384fff8SJason Evans 	for ((m1 = LIST_FIRST(&p->p_heldmtx)); m1 != NULL;
8030384fff8SJason Evans 		m1 = LIST_NEXT(m1, mtx_held)) {
8040384fff8SJason Evans 		if (m1 == m) {
8050384fff8SJason Evans 			LIST_REMOVE(m, mtx_held);
8060384fff8SJason Evans 			break;
8070384fff8SJason Evans 		}
8080384fff8SJason Evans 	}
8090384fff8SJason Evans 	return;
8100384fff8SJason Evans 
8110384fff8SJason Evans }
8120384fff8SJason Evans 
8130384fff8SJason Evans void
814606f8eb2SJohn Baldwin witness_enter(struct mtx *m, int flags, const char *file, int line)
8150384fff8SJason Evans {
816606f8eb2SJohn Baldwin 	struct witness *w, *w1;
817606f8eb2SJohn Baldwin 	struct mtx *m1;
8180384fff8SJason Evans 	struct proc *p;
8190384fff8SJason Evans 	int i;
8200384fff8SJason Evans #ifdef KDEBUG
8210384fff8SJason Evans 	int go_into_kdebug = 0;
8220384fff8SJason Evans #endif /* KDEBUG */
8230384fff8SJason Evans 
8240384fff8SJason Evans 	w = m->mtx_witness;
8250384fff8SJason Evans 	p = CURPROC;
8260384fff8SJason Evans 
8270384fff8SJason Evans 	if (flags & MTX_SPIN) {
8280384fff8SJason Evans 		if (!w->w_spin)
8295340642aSJason Evans 			panic("mutex_enter: MTX_SPIN on MTX_DEF mutex %s @"
8305340642aSJason Evans 			    " %s:%d", m->mtx_description, file, line);
8310384fff8SJason Evans 		if (m->mtx_recurse != 0)
8320384fff8SJason Evans 			return;
8330384fff8SJason Evans 		mtx_enter(&w_mtx, MTX_SPIN);
8340384fff8SJason Evans 		i = witness_spin_check;
8350384fff8SJason Evans 		if (i != 0 && w->w_level < i) {
8360384fff8SJason Evans 			mtx_exit(&w_mtx, MTX_SPIN);
8375340642aSJason Evans 			panic("mutex_enter(%s:%x, MTX_SPIN) out of order @"
8385340642aSJason Evans 			    " %s:%d already holding %s:%x",
8390384fff8SJason Evans 			    m->mtx_description, w->w_level, file, line,
8400384fff8SJason Evans 			    spin_order_list[ffs(i)-1], i);
8410384fff8SJason Evans 		}
8420384fff8SJason Evans 		PCPU_SET(witness_spin_check, i | w->w_level);
8430384fff8SJason Evans 		mtx_exit(&w_mtx, MTX_SPIN);
8440384fff8SJason Evans 		return;
8450384fff8SJason Evans 	}
8460384fff8SJason Evans 	if (w->w_spin)
8470384fff8SJason Evans 		panic("mutex_enter: MTX_DEF on MTX_SPIN mutex %s @ %s:%d",
8480384fff8SJason Evans 		    m->mtx_description, file, line);
8490384fff8SJason Evans 
8500384fff8SJason Evans 	if (m->mtx_recurse != 0)
8510384fff8SJason Evans 		return;
8520384fff8SJason Evans 	if (witness_dead)
8530384fff8SJason Evans 		goto out;
8540384fff8SJason Evans 	if (cold)
8550384fff8SJason Evans 		goto out;
8560384fff8SJason Evans 
8570384fff8SJason Evans 	if (!mtx_legal2block())
8580384fff8SJason Evans 		panic("blockable mtx_enter() of %s when not legal @ %s:%d",
8590384fff8SJason Evans 			    m->mtx_description, file, line);
8600384fff8SJason Evans 	/*
8610384fff8SJason Evans 	 * Is this the first mutex acquired
8620384fff8SJason Evans 	 */
8630384fff8SJason Evans 	if ((m1 = LIST_FIRST(&p->p_heldmtx)) == NULL)
8640384fff8SJason Evans 		goto out;
8650384fff8SJason Evans 
8660384fff8SJason Evans 	if ((w1 = m1->mtx_witness) == w) {
8670384fff8SJason Evans 		if (w->w_same_squawked || dup_ok(w))
8680384fff8SJason Evans 			goto out;
8690384fff8SJason Evans 		w->w_same_squawked = 1;
8700384fff8SJason Evans 		printf("acquring duplicate lock of same type: \"%s\"\n",
8710384fff8SJason Evans 			m->mtx_description);
8720384fff8SJason Evans 		printf(" 1st @ %s:%d\n", w->w_file, w->w_line);
8730384fff8SJason Evans 		printf(" 2nd @ %s:%d\n", file, line);
8740384fff8SJason Evans #ifdef KDEBUG
8750384fff8SJason Evans 		go_into_kdebug = 1;
8760384fff8SJason Evans #endif /* KDEBUG */
8770384fff8SJason Evans 		goto out;
8780384fff8SJason Evans 	}
8790384fff8SJason Evans 	MPASS(!mtx_owned(&w_mtx));
8800384fff8SJason Evans 	mtx_enter(&w_mtx, MTX_SPIN);
8810384fff8SJason Evans 	/*
8820384fff8SJason Evans 	 * If we have a known higher number just say ok
8830384fff8SJason Evans 	 */
8840384fff8SJason Evans 	if (witness_watch > 1 && w->w_level > w1->w_level) {
8850384fff8SJason Evans 		mtx_exit(&w_mtx, MTX_SPIN);
8860384fff8SJason Evans 		goto out;
8870384fff8SJason Evans 	}
8880384fff8SJason Evans 	if (isitmydescendant(m1->mtx_witness, w)) {
8890384fff8SJason Evans 		mtx_exit(&w_mtx, MTX_SPIN);
8900384fff8SJason Evans 		goto out;
8910384fff8SJason Evans 	}
8920384fff8SJason Evans 	for (i = 0; m1 != NULL; m1 = LIST_NEXT(m1, mtx_held), i++) {
8930384fff8SJason Evans 
89436412d79SJohn Baldwin 		MPASS(i < 200);
8950384fff8SJason Evans 		w1 = m1->mtx_witness;
8960384fff8SJason Evans 		if (isitmydescendant(w, w1)) {
8970384fff8SJason Evans 			mtx_exit(&w_mtx, MTX_SPIN);
8980384fff8SJason Evans 			if (blessed(w, w1))
8990384fff8SJason Evans 				goto out;
9000384fff8SJason Evans 			if (m1 == &Giant) {
9010384fff8SJason Evans 				if (w1->w_Giant_squawked)
9020384fff8SJason Evans 					goto out;
9030384fff8SJason Evans 				else
9040384fff8SJason Evans 					w1->w_Giant_squawked = 1;
9050384fff8SJason Evans 			} else {
9060384fff8SJason Evans 				if (w1->w_other_squawked)
9070384fff8SJason Evans 					goto out;
9080384fff8SJason Evans 				else
9090384fff8SJason Evans 					w1->w_other_squawked = 1;
9100384fff8SJason Evans 			}
9110384fff8SJason Evans 			printf("lock order reversal\n");
9120384fff8SJason Evans 			printf(" 1st %s last acquired @ %s:%d\n",
9130384fff8SJason Evans 			    w->w_description, w->w_file, w->w_line);
9140384fff8SJason Evans 			printf(" 2nd %p %s @ %s:%d\n",
9150384fff8SJason Evans 			    m1, w1->w_description, w1->w_file, w1->w_line);
9160384fff8SJason Evans 			printf(" 3rd %p %s @ %s:%d\n",
9170384fff8SJason Evans 			    m, w->w_description, file, line);
9180384fff8SJason Evans #ifdef KDEBUG
9190384fff8SJason Evans 			go_into_kdebug = 1;
9200384fff8SJason Evans #endif /* KDEBUG */
9210384fff8SJason Evans 			goto out;
9220384fff8SJason Evans 		}
9230384fff8SJason Evans 	}
9240384fff8SJason Evans 	m1 = LIST_FIRST(&p->p_heldmtx);
9250384fff8SJason Evans 	if (!itismychild(m1->mtx_witness, w))
9260384fff8SJason Evans 		mtx_exit(&w_mtx, MTX_SPIN);
9270384fff8SJason Evans 
9280384fff8SJason Evans out:
9290384fff8SJason Evans #ifdef KDEBUG
9300384fff8SJason Evans 	if (witness_kdebug && go_into_kdebug)
9310384fff8SJason Evans 		kdebug();
9320384fff8SJason Evans #endif /* KDEBUG */
9330384fff8SJason Evans 	w->w_file = file;
9340384fff8SJason Evans 	w->w_line = line;
9350384fff8SJason Evans 	m->mtx_line = line;
9360384fff8SJason Evans 	m->mtx_file = file;
9370384fff8SJason Evans 
9380384fff8SJason Evans 	/*
9390384fff8SJason Evans 	 * If this pays off it likely means that a mutex  being witnessed
9400384fff8SJason Evans 	 * is acquired in hardclock. Put it in the ignore list. It is
9410384fff8SJason Evans 	 * likely not the mutex this assert fails on.
9420384fff8SJason Evans 	 */
94336412d79SJohn Baldwin 	MPASS(m->mtx_held.le_prev == NULL);
9440384fff8SJason Evans 	LIST_INSERT_HEAD(&p->p_heldmtx, (struct mtx*)m, mtx_held);
9450384fff8SJason Evans }
9460384fff8SJason Evans 
9470384fff8SJason Evans void
948606f8eb2SJohn Baldwin witness_exit(struct mtx *m, int flags, const char *file, int line)
9490384fff8SJason Evans {
950606f8eb2SJohn Baldwin 	struct witness *w;
9510384fff8SJason Evans 
9520384fff8SJason Evans 	w = m->mtx_witness;
9530384fff8SJason Evans 
9540384fff8SJason Evans 	if (flags & MTX_SPIN) {
9550384fff8SJason Evans 		if (!w->w_spin)
9565340642aSJason Evans 			panic("mutex_exit: MTX_SPIN on MTX_DEF mutex %s @"
9575340642aSJason Evans 			    " %s:%d", m->mtx_description, file, line);
9580384fff8SJason Evans 		if (m->mtx_recurse != 0)
9590384fff8SJason Evans 			return;
9600384fff8SJason Evans 		mtx_enter(&w_mtx, MTX_SPIN);
9610384fff8SJason Evans 		PCPU_SET(witness_spin_check, witness_spin_check & ~w->w_level);
9620384fff8SJason Evans 		mtx_exit(&w_mtx, MTX_SPIN);
9630384fff8SJason Evans 		return;
9640384fff8SJason Evans 	}
9650384fff8SJason Evans 	if (w->w_spin)
9660384fff8SJason Evans 		panic("mutex_exit: MTX_DEF on MTX_SPIN mutex %s @ %s:%d",
9670384fff8SJason Evans 		    m->mtx_description, file, line);
9680384fff8SJason Evans 
9690384fff8SJason Evans 	if (m->mtx_recurse != 0)
9700384fff8SJason Evans 		return;
9710384fff8SJason Evans 
9720384fff8SJason Evans 	if ((flags & MTX_NOSWITCH) == 0 && !mtx_legal2block() && !cold)
9730384fff8SJason Evans 		panic("switchable mtx_exit() of %s when not legal @ %s:%d",
9740384fff8SJason Evans 			    m->mtx_description, file, line);
9750384fff8SJason Evans 	LIST_REMOVE(m, mtx_held);
9760384fff8SJason Evans 	m->mtx_held.le_prev = NULL;
9770384fff8SJason Evans }
9780384fff8SJason Evans 
9790384fff8SJason Evans void
980606f8eb2SJohn Baldwin witness_try_enter(struct mtx *m, int flags, const char *file, int line)
9810384fff8SJason Evans {
9820384fff8SJason Evans 	struct proc *p;
983606f8eb2SJohn Baldwin 	struct witness *w = m->mtx_witness;
9840384fff8SJason Evans 
9850384fff8SJason Evans 	if (flags & MTX_SPIN) {
9860384fff8SJason Evans 		if (!w->w_spin)
9870384fff8SJason Evans 			panic("mutex_try_enter: "
9880384fff8SJason Evans 			    "MTX_SPIN on MTX_DEF mutex %s @ %s:%d",
9890384fff8SJason Evans 			    m->mtx_description, file, line);
9900384fff8SJason Evans 		if (m->mtx_recurse != 0)
9910384fff8SJason Evans 			return;
9920384fff8SJason Evans 		mtx_enter(&w_mtx, MTX_SPIN);
9930384fff8SJason Evans 		PCPU_SET(witness_spin_check, witness_spin_check | w->w_level);
9940384fff8SJason Evans 		mtx_exit(&w_mtx, MTX_SPIN);
9950384fff8SJason Evans 		return;
9960384fff8SJason Evans 	}
9970384fff8SJason Evans 
9980384fff8SJason Evans 	if (w->w_spin)
9990384fff8SJason Evans 		panic("mutex_try_enter: MTX_DEF on MTX_SPIN mutex %s @ %s:%d",
10000384fff8SJason Evans 		    m->mtx_description, file, line);
10010384fff8SJason Evans 
10020384fff8SJason Evans 	if (m->mtx_recurse != 0)
10030384fff8SJason Evans 		return;
10040384fff8SJason Evans 
10050384fff8SJason Evans 	w->w_file = file;
10060384fff8SJason Evans 	w->w_line = line;
10070384fff8SJason Evans 	m->mtx_line = line;
10080384fff8SJason Evans 	m->mtx_file = file;
10090384fff8SJason Evans 	p = CURPROC;
101036412d79SJohn Baldwin 	MPASS(m->mtx_held.le_prev == NULL);
10110384fff8SJason Evans 	LIST_INSERT_HEAD(&p->p_heldmtx, (struct mtx*)m, mtx_held);
10120384fff8SJason Evans }
10130384fff8SJason Evans 
10140384fff8SJason Evans void
10150384fff8SJason Evans witness_display(void(*prnt)(const char *fmt, ...))
10160384fff8SJason Evans {
1017606f8eb2SJohn Baldwin 	struct witness *w, *w1;
10180384fff8SJason Evans 
10190384fff8SJason Evans 	witness_levelall();
10200384fff8SJason Evans 
10210384fff8SJason Evans 	for (w = w_all; w; w = w->w_next) {
10220384fff8SJason Evans 		if (w->w_file == NULL)
10230384fff8SJason Evans 			continue;
10240384fff8SJason Evans 		for (w1 = w_all; w1; w1 = w1->w_next) {
10250384fff8SJason Evans 			if (isitmychild(w1, w))
10260384fff8SJason Evans 				break;
10270384fff8SJason Evans 		}
10280384fff8SJason Evans 		if (w1 != NULL)
10290384fff8SJason Evans 			continue;
10300384fff8SJason Evans 		/*
10310384fff8SJason Evans 		 * This lock has no anscestors, display its descendants.
10320384fff8SJason Evans 		 */
10330384fff8SJason Evans 		witness_displaydescendants(prnt, w);
10340384fff8SJason Evans 	}
10350384fff8SJason Evans 	prnt("\nMutex which were never acquired\n");
10360384fff8SJason Evans 	for (w = w_all; w; w = w->w_next) {
10370384fff8SJason Evans 		if (w->w_file != NULL)
10380384fff8SJason Evans 			continue;
10390384fff8SJason Evans 		prnt("%s\n", w->w_description);
10400384fff8SJason Evans 	}
10410384fff8SJason Evans }
10420384fff8SJason Evans 
10430384fff8SJason Evans int
1044606f8eb2SJohn Baldwin witness_sleep(int check_only, struct mtx *mtx, const char *file, int line)
10450384fff8SJason Evans {
1046606f8eb2SJohn Baldwin 	struct mtx *m;
10470384fff8SJason Evans 	struct proc *p;
10480384fff8SJason Evans 	char **sleep;
10490384fff8SJason Evans 	int n = 0;
10500384fff8SJason Evans 
10510384fff8SJason Evans 	p = CURPROC;
10520384fff8SJason Evans 	for ((m = LIST_FIRST(&p->p_heldmtx)); m != NULL;
10530384fff8SJason Evans 	    m = LIST_NEXT(m, mtx_held)) {
10540384fff8SJason Evans 		if (m == mtx)
10550384fff8SJason Evans 			continue;
10560384fff8SJason Evans 		for (sleep = sleep_list; *sleep!= NULL; sleep++)
10570384fff8SJason Evans 			if (strcmp(m->mtx_description, *sleep) == 0)
10580384fff8SJason Evans 				goto next;
10590384fff8SJason Evans 		printf("%s:%d: %s with \"%s\" locked from %s:%d\n",
10600384fff8SJason Evans 			file, line, check_only ? "could sleep" : "sleeping",
10610384fff8SJason Evans 			m->mtx_description,
10620384fff8SJason Evans 			m->mtx_witness->w_file, m->mtx_witness->w_line);
10630384fff8SJason Evans 		n++;
10640384fff8SJason Evans 	next:
10650384fff8SJason Evans 	}
10660384fff8SJason Evans #ifdef KDEBUG
10670384fff8SJason Evans 	if (witness_kdebug && n)
10680384fff8SJason Evans 		kdebug();
10690384fff8SJason Evans #endif /* KDEBUG */
10700384fff8SJason Evans 	return (n);
10710384fff8SJason Evans }
10720384fff8SJason Evans 
1073606f8eb2SJohn Baldwin static struct witness *
10740384fff8SJason Evans enroll(char *description, int flag)
10750384fff8SJason Evans {
10760384fff8SJason Evans 	int i;
1077606f8eb2SJohn Baldwin 	struct witness *w, *w1;
10780384fff8SJason Evans 	char **ignore;
10790384fff8SJason Evans 	char **order;
10800384fff8SJason Evans 
10810384fff8SJason Evans 	if (!witness_watch)
10820384fff8SJason Evans 		return (NULL);
10830384fff8SJason Evans 	for (ignore = ignore_list; *ignore != NULL; ignore++)
10840384fff8SJason Evans 		if (strcmp(description, *ignore) == 0)
10850384fff8SJason Evans 			return (NULL);
10860384fff8SJason Evans 
10870384fff8SJason Evans 	if (w_inited == 0) {
10880384fff8SJason Evans 		mtx_init(&w_mtx, "witness lock", MTX_DEF);
10890384fff8SJason Evans 		for (i = 0; i < WITNESS_COUNT; i++) {
10900384fff8SJason Evans 			w = &w_data[i];
10910384fff8SJason Evans 			witness_free(w);
10920384fff8SJason Evans 		}
10930384fff8SJason Evans 		w_inited = 1;
10940384fff8SJason Evans 		for (order = order_list; *order != NULL; order++) {
10950384fff8SJason Evans 			w = enroll(*order, MTX_DEF);
10960384fff8SJason Evans 			w->w_file = "order list";
10970384fff8SJason Evans 			for (order++; *order != NULL; order++) {
10980384fff8SJason Evans 				w1 = enroll(*order, MTX_DEF);
10990384fff8SJason Evans 				w1->w_file = "order list";
11000384fff8SJason Evans 				itismychild(w, w1);
11010384fff8SJason Evans 				w = w1;
11020384fff8SJason Evans     	    	    	}
11030384fff8SJason Evans 		}
11040384fff8SJason Evans 	}
11050384fff8SJason Evans 	if ((flag & MTX_SPIN) && witness_skipspin)
11060384fff8SJason Evans 		return (NULL);
11070384fff8SJason Evans 	mtx_enter(&w_mtx, MTX_SPIN);
11080384fff8SJason Evans 	for (w = w_all; w; w = w->w_next) {
11090384fff8SJason Evans 		if (strcmp(description, w->w_description) == 0) {
11100384fff8SJason Evans 			mtx_exit(&w_mtx, MTX_SPIN);
11110384fff8SJason Evans 			return (w);
11120384fff8SJason Evans 		}
11130384fff8SJason Evans 	}
11140384fff8SJason Evans 	if ((w = witness_get()) == NULL)
11150384fff8SJason Evans 		return (NULL);
11160384fff8SJason Evans 	w->w_next = w_all;
11170384fff8SJason Evans 	w_all = w;
11180384fff8SJason Evans 	w->w_description = description;
11190384fff8SJason Evans 	mtx_exit(&w_mtx, MTX_SPIN);
11200384fff8SJason Evans 	if (flag & MTX_SPIN) {
11210384fff8SJason Evans 		w->w_spin = 1;
11220384fff8SJason Evans 
11230384fff8SJason Evans 		i = 1;
11240384fff8SJason Evans 		for (order = spin_order_list; *order != NULL; order++) {
11250384fff8SJason Evans 			if (strcmp(description, *order) == 0)
11260384fff8SJason Evans 				break;
11270384fff8SJason Evans 			i <<= 1;
11280384fff8SJason Evans 		}
11290384fff8SJason Evans 		if (*order == NULL)
11300384fff8SJason Evans 			panic("spin lock %s not in order list", description);
11310384fff8SJason Evans 		w->w_level = i;
11320384fff8SJason Evans 	}
11330384fff8SJason Evans 	return (w);
11340384fff8SJason Evans }
11350384fff8SJason Evans 
11360384fff8SJason Evans static int
1137606f8eb2SJohn Baldwin itismychild(struct witness *parent, struct witness *child)
11380384fff8SJason Evans {
11390384fff8SJason Evans 	static int recursed;
11400384fff8SJason Evans 
11410384fff8SJason Evans 	/*
11420384fff8SJason Evans 	 * Insert "child" after "parent"
11430384fff8SJason Evans 	 */
11440384fff8SJason Evans 	while (parent->w_morechildren)
11450384fff8SJason Evans 		parent = parent->w_morechildren;
11460384fff8SJason Evans 
11470384fff8SJason Evans 	if (parent->w_childcnt == WITNESS_NCHILDREN) {
11480384fff8SJason Evans 		if ((parent->w_morechildren = witness_get()) == NULL)
11490384fff8SJason Evans 			return (1);
11500384fff8SJason Evans 		parent = parent->w_morechildren;
11510384fff8SJason Evans 	}
115236412d79SJohn Baldwin 	MPASS(child != NULL);
11530384fff8SJason Evans 	parent->w_children[parent->w_childcnt++] = child;
11540384fff8SJason Evans 	/*
11550384fff8SJason Evans 	 * now prune whole tree
11560384fff8SJason Evans 	 */
11570384fff8SJason Evans 	if (recursed)
11580384fff8SJason Evans 		return (0);
11590384fff8SJason Evans 	recursed = 1;
11600384fff8SJason Evans 	for (child = w_all; child != NULL; child = child->w_next) {
11610384fff8SJason Evans 		for (parent = w_all; parent != NULL;
11620384fff8SJason Evans 		    parent = parent->w_next) {
11630384fff8SJason Evans 			if (!isitmychild(parent, child))
11640384fff8SJason Evans 				continue;
11650384fff8SJason Evans 			removechild(parent, child);
11660384fff8SJason Evans 			if (isitmydescendant(parent, child))
11670384fff8SJason Evans 				continue;
11680384fff8SJason Evans 			itismychild(parent, child);
11690384fff8SJason Evans 		}
11700384fff8SJason Evans 	}
11710384fff8SJason Evans 	recursed = 0;
11720384fff8SJason Evans 	witness_levelall();
11730384fff8SJason Evans 	return (0);
11740384fff8SJason Evans }
11750384fff8SJason Evans 
11760384fff8SJason Evans static void
1177606f8eb2SJohn Baldwin removechild(struct witness *parent, struct witness *child)
11780384fff8SJason Evans {
1179606f8eb2SJohn Baldwin 	struct witness *w, *w1;
11800384fff8SJason Evans 	int i;
11810384fff8SJason Evans 
11820384fff8SJason Evans 	for (w = parent; w != NULL; w = w->w_morechildren)
11830384fff8SJason Evans 		for (i = 0; i < w->w_childcnt; i++)
11840384fff8SJason Evans 			if (w->w_children[i] == child)
11850384fff8SJason Evans 				goto found;
11860384fff8SJason Evans 	return;
11870384fff8SJason Evans found:
11880384fff8SJason Evans 	for (w1 = w; w1->w_morechildren != NULL; w1 = w1->w_morechildren)
11890384fff8SJason Evans 		continue;
11900384fff8SJason Evans 	w->w_children[i] = w1->w_children[--w1->w_childcnt];
119136412d79SJohn Baldwin 	MPASS(w->w_children[i] != NULL);
11920384fff8SJason Evans 
11930384fff8SJason Evans 	if (w1->w_childcnt != 0)
11940384fff8SJason Evans 		return;
11950384fff8SJason Evans 
11960384fff8SJason Evans 	if (w1 == parent)
11970384fff8SJason Evans 		return;
11980384fff8SJason Evans 	for (w = parent; w->w_morechildren != w1; w = w->w_morechildren)
11990384fff8SJason Evans 		continue;
12000384fff8SJason Evans 	w->w_morechildren = 0;
12010384fff8SJason Evans 	witness_free(w1);
12020384fff8SJason Evans }
12030384fff8SJason Evans 
12040384fff8SJason Evans static int
1205606f8eb2SJohn Baldwin isitmychild(struct witness *parent, struct witness *child)
12060384fff8SJason Evans {
1207606f8eb2SJohn Baldwin 	struct witness *w;
12080384fff8SJason Evans 	int i;
12090384fff8SJason Evans 
12100384fff8SJason Evans 	for (w = parent; w != NULL; w = w->w_morechildren) {
12110384fff8SJason Evans 		for (i = 0; i < w->w_childcnt; i++) {
12120384fff8SJason Evans 			if (w->w_children[i] == child)
12130384fff8SJason Evans 				return (1);
12140384fff8SJason Evans 		}
12150384fff8SJason Evans 	}
12160384fff8SJason Evans 	return (0);
12170384fff8SJason Evans }
12180384fff8SJason Evans 
12190384fff8SJason Evans static int
1220606f8eb2SJohn Baldwin isitmydescendant(struct witness *parent, struct witness *child)
12210384fff8SJason Evans {
1222606f8eb2SJohn Baldwin 	struct witness *w;
12230384fff8SJason Evans 	int i;
12240384fff8SJason Evans 	int j;
12250384fff8SJason Evans 
12260384fff8SJason Evans 	for (j = 0, w = parent; w != NULL; w = w->w_morechildren, j++) {
122736412d79SJohn Baldwin 		MPASS(j < 1000);
12280384fff8SJason Evans 		for (i = 0; i < w->w_childcnt; i++) {
12290384fff8SJason Evans 			if (w->w_children[i] == child)
12300384fff8SJason Evans 				return (1);
12310384fff8SJason Evans 		}
12320384fff8SJason Evans 		for (i = 0; i < w->w_childcnt; i++) {
12330384fff8SJason Evans 			if (isitmydescendant(w->w_children[i], child))
12340384fff8SJason Evans 				return (1);
12350384fff8SJason Evans 		}
12360384fff8SJason Evans 	}
12370384fff8SJason Evans 	return (0);
12380384fff8SJason Evans }
12390384fff8SJason Evans 
12400384fff8SJason Evans void
12410384fff8SJason Evans witness_levelall (void)
12420384fff8SJason Evans {
1243606f8eb2SJohn Baldwin 	struct witness *w, *w1;
12440384fff8SJason Evans 
12450384fff8SJason Evans 	for (w = w_all; w; w = w->w_next)
12460384fff8SJason Evans 		if (!w->w_spin)
12470384fff8SJason Evans 			w->w_level = 0;
12480384fff8SJason Evans 	for (w = w_all; w; w = w->w_next) {
12490384fff8SJason Evans 		if (w->w_spin)
12500384fff8SJason Evans 			continue;
12510384fff8SJason Evans 		for (w1 = w_all; w1; w1 = w1->w_next) {
12520384fff8SJason Evans 			if (isitmychild(w1, w))
12530384fff8SJason Evans 				break;
12540384fff8SJason Evans 		}
12550384fff8SJason Evans 		if (w1 != NULL)
12560384fff8SJason Evans 			continue;
12570384fff8SJason Evans 		witness_leveldescendents(w, 0);
12580384fff8SJason Evans 	}
12590384fff8SJason Evans }
12600384fff8SJason Evans 
12610384fff8SJason Evans static void
1262606f8eb2SJohn Baldwin witness_leveldescendents(struct witness *parent, int level)
12630384fff8SJason Evans {
12640384fff8SJason Evans 	int i;
1265606f8eb2SJohn Baldwin 	struct witness *w;
12660384fff8SJason Evans 
12670384fff8SJason Evans 	if (parent->w_level < level)
12680384fff8SJason Evans 		parent->w_level = level;
12690384fff8SJason Evans 	level++;
12700384fff8SJason Evans 	for (w = parent; w != NULL; w = w->w_morechildren)
12710384fff8SJason Evans 		for (i = 0; i < w->w_childcnt; i++)
12720384fff8SJason Evans 			witness_leveldescendents(w->w_children[i], level);
12730384fff8SJason Evans }
12740384fff8SJason Evans 
12750384fff8SJason Evans static void
1276606f8eb2SJohn Baldwin witness_displaydescendants(void(*prnt)(const char *fmt, ...),
1277606f8eb2SJohn Baldwin 			   struct witness *parent)
12780384fff8SJason Evans {
1279606f8eb2SJohn Baldwin 	struct witness *w;
12800384fff8SJason Evans 	int i;
12810384fff8SJason Evans 	int level = parent->w_level;
12820384fff8SJason Evans 
12830384fff8SJason Evans 	prnt("%d", level);
12840384fff8SJason Evans 	if (level < 10)
12850384fff8SJason Evans 		prnt(" ");
12860384fff8SJason Evans 	for (i = 0; i < level; i++)
12870384fff8SJason Evans 		prnt(" ");
12880384fff8SJason Evans 	prnt("%s", parent->w_description);
12890384fff8SJason Evans 	if (parent->w_file != NULL) {
12900384fff8SJason Evans 		prnt(" -- last acquired @ %s", parent->w_file);
12910384fff8SJason Evans #ifndef W_USE_WHERE
12920384fff8SJason Evans 		prnt(":%d", parent->w_line);
12930384fff8SJason Evans #endif
12940384fff8SJason Evans 		prnt("\n");
12950384fff8SJason Evans 	}
12960384fff8SJason Evans 
12970384fff8SJason Evans 	for (w = parent; w != NULL; w = w->w_morechildren)
12980384fff8SJason Evans 		for (i = 0; i < w->w_childcnt; i++)
12990384fff8SJason Evans 			    witness_displaydescendants(prnt, w->w_children[i]);
13000384fff8SJason Evans     }
13010384fff8SJason Evans 
13020384fff8SJason Evans static int
1303606f8eb2SJohn Baldwin dup_ok(struct witness *w)
13040384fff8SJason Evans {
13050384fff8SJason Evans 	char **dup;
13060384fff8SJason Evans 
13070384fff8SJason Evans 	for (dup = dup_list; *dup!= NULL; dup++)
13080384fff8SJason Evans 		if (strcmp(w->w_description, *dup) == 0)
13090384fff8SJason Evans 			return (1);
13100384fff8SJason Evans 	return (0);
13110384fff8SJason Evans }
13120384fff8SJason Evans 
13130384fff8SJason Evans static int
1314606f8eb2SJohn Baldwin blessed(struct witness *w1, struct witness *w2)
13150384fff8SJason Evans {
13160384fff8SJason Evans 	int i;
1317606f8eb2SJohn Baldwin 	struct witness_blessed *b;
13180384fff8SJason Evans 
13190384fff8SJason Evans 	for (i = 0; i < blessed_count; i++) {
13200384fff8SJason Evans 		b = &blessed_list[i];
13210384fff8SJason Evans 		if (strcmp(w1->w_description, b->b_lock1) == 0) {
13220384fff8SJason Evans 			if (strcmp(w2->w_description, b->b_lock2) == 0)
13230384fff8SJason Evans 				return (1);
13240384fff8SJason Evans 			continue;
13250384fff8SJason Evans 		}
13260384fff8SJason Evans 		if (strcmp(w1->w_description, b->b_lock2) == 0)
13270384fff8SJason Evans 			if (strcmp(w2->w_description, b->b_lock1) == 0)
13280384fff8SJason Evans 				return (1);
13290384fff8SJason Evans 	}
13300384fff8SJason Evans 	return (0);
13310384fff8SJason Evans }
13320384fff8SJason Evans 
1333606f8eb2SJohn Baldwin static struct witness *
13340384fff8SJason Evans witness_get()
13350384fff8SJason Evans {
1336606f8eb2SJohn Baldwin 	struct witness *w;
13370384fff8SJason Evans 
13380384fff8SJason Evans 	if ((w = w_free) == NULL) {
13390384fff8SJason Evans 		witness_dead = 1;
13400384fff8SJason Evans 		mtx_exit(&w_mtx, MTX_SPIN);
13410384fff8SJason Evans 		printf("witness exhausted\n");
13420384fff8SJason Evans 		return (NULL);
13430384fff8SJason Evans 	}
13440384fff8SJason Evans 	w_free = w->w_next;
13450384fff8SJason Evans 	bzero(w, sizeof(*w));
13460384fff8SJason Evans 	return (w);
13470384fff8SJason Evans }
13480384fff8SJason Evans 
13490384fff8SJason Evans static void
1350606f8eb2SJohn Baldwin witness_free(struct witness *w)
13510384fff8SJason Evans {
13520384fff8SJason Evans 	w->w_next = w_free;
13530384fff8SJason Evans 	w_free = w;
13540384fff8SJason Evans }
13550384fff8SJason Evans 
13560384fff8SJason Evans void
13570384fff8SJason Evans witness_list(struct proc *p)
13580384fff8SJason Evans {
1359606f8eb2SJohn Baldwin 	struct mtx *m;
13600384fff8SJason Evans 
13610384fff8SJason Evans 	for ((m = LIST_FIRST(&p->p_heldmtx)); m != NULL;
13620384fff8SJason Evans 	    m = LIST_NEXT(m, mtx_held)) {
13630384fff8SJason Evans 		printf("\t\"%s\" (%p) locked at %s:%d\n",
13640384fff8SJason Evans 		    m->mtx_description, m,
13650384fff8SJason Evans 		    m->mtx_witness->w_file, m->mtx_witness->w_line);
13660384fff8SJason Evans 	}
13670384fff8SJason Evans }
13680384fff8SJason Evans 
13690384fff8SJason Evans void
1370606f8eb2SJohn Baldwin witness_save(struct mtx *m, const char **filep, int *linep)
13710384fff8SJason Evans {
13720384fff8SJason Evans 	*filep = m->mtx_witness->w_file;
13730384fff8SJason Evans 	*linep = m->mtx_witness->w_line;
13740384fff8SJason Evans }
13750384fff8SJason Evans 
13760384fff8SJason Evans void
1377606f8eb2SJohn Baldwin witness_restore(struct mtx *m, const char *file, int line)
13780384fff8SJason Evans {
13790384fff8SJason Evans 	m->mtx_witness->w_file = file;
13800384fff8SJason Evans 	m->mtx_witness->w_line = line;
13810384fff8SJason Evans }
13820384fff8SJason Evans 
138336412d79SJohn Baldwin #endif	/* (defined(MUTEX_DEBUG) && defined(WITNESS)) */
1384