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