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