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 560931dcefSAlfred Perlstein /* 570931dcefSAlfred Perlstein * Cause non-inlined mtx_*() to be compiled. 580931dcefSAlfred Perlstein * Must be defined early because other system headers may include mutex.h. 590931dcefSAlfred Perlstein */ 600931dcefSAlfred Perlstein #define _KERN_MUTEX_C_ 610931dcefSAlfred Perlstein 620384fff8SJason Evans #include <sys/param.h> 6336412d79SJohn Baldwin #include <sys/bus.h> 6436412d79SJohn Baldwin #include <sys/kernel.h> 6536412d79SJohn Baldwin #include <sys/malloc.h> 660384fff8SJason Evans #include <sys/proc.h> 67a5a96a19SJohn Baldwin #include <sys/sysctl.h> 680384fff8SJason Evans #include <sys/systm.h> 6936412d79SJohn Baldwin #include <sys/vmmeter.h> 700384fff8SJason Evans #include <sys/ktr.h> 710384fff8SJason Evans 7236412d79SJohn Baldwin #include <machine/atomic.h> 7336412d79SJohn Baldwin #include <machine/bus.h> 7436412d79SJohn Baldwin #include <machine/clock.h> 750384fff8SJason Evans #include <machine/cpu.h> 7636412d79SJohn Baldwin 779c36c934SJohn Baldwin #include <ddb/ddb.h> 789c36c934SJohn Baldwin 7936412d79SJohn Baldwin #include <vm/vm.h> 8036412d79SJohn Baldwin #include <vm/vm_extern.h> 8136412d79SJohn Baldwin 8236412d79SJohn Baldwin #include <sys/mutex.h> 8336412d79SJohn Baldwin 8436412d79SJohn Baldwin /* 8536412d79SJohn Baldwin * Machine independent bits of the mutex implementation 8636412d79SJohn Baldwin */ 8736412d79SJohn Baldwin /* All mutexes in system (used for debug/panic) */ 886936206eSJohn Baldwin #ifdef WITNESS 8936412d79SJohn Baldwin static struct mtx_debug all_mtx_debug = { NULL, {NULL, NULL}, NULL, 0, 9036412d79SJohn Baldwin "All mutexes queue head" }; 9136412d79SJohn Baldwin static struct mtx all_mtx = { MTX_UNOWNED, 0, 0, &all_mtx_debug, 9236412d79SJohn Baldwin TAILQ_HEAD_INITIALIZER(all_mtx.mtx_blocked), 9336412d79SJohn Baldwin { NULL, NULL }, &all_mtx, &all_mtx }; 946936206eSJohn Baldwin #else /* WITNESS */ 9536412d79SJohn Baldwin static struct mtx all_mtx = { MTX_UNOWNED, 0, 0, "All mutexes queue head", 9636412d79SJohn Baldwin TAILQ_HEAD_INITIALIZER(all_mtx.mtx_blocked), 9736412d79SJohn Baldwin { NULL, NULL }, &all_mtx, &all_mtx }; 986936206eSJohn Baldwin #endif /* WITNESS */ 9936412d79SJohn Baldwin 10036412d79SJohn Baldwin static int mtx_cur_cnt; 10136412d79SJohn Baldwin static int mtx_max_cnt; 10236412d79SJohn Baldwin 10336412d79SJohn Baldwin void _mtx_enter_giant_def(void); 10436412d79SJohn Baldwin void _mtx_exit_giant_def(void); 1051bd0eefbSJohn Baldwin static void propagate_priority(struct proc *); 10636412d79SJohn Baldwin 10736412d79SJohn Baldwin #define mtx_unowned(m) ((m)->mtx_lock == MTX_UNOWNED) 10836412d79SJohn Baldwin #define mtx_owner(m) (mtx_unowned(m) ? NULL \ 10936412d79SJohn Baldwin : (struct proc *)((m)->mtx_lock & MTX_FLAGMASK)) 11036412d79SJohn Baldwin 11136412d79SJohn Baldwin #define RETIP(x) *(((uintptr_t *)(&x)) - 1) 11236412d79SJohn Baldwin #define SET_PRIO(p, pri) (p)->p_priority = (pri) 11336412d79SJohn Baldwin 11436412d79SJohn Baldwin /* 11536412d79SJohn Baldwin * XXX Temporary, for use from assembly language 11636412d79SJohn Baldwin */ 11736412d79SJohn Baldwin 11836412d79SJohn Baldwin void 11936412d79SJohn Baldwin _mtx_enter_giant_def(void) 12036412d79SJohn Baldwin { 12136412d79SJohn Baldwin 12236412d79SJohn Baldwin mtx_enter(&Giant, MTX_DEF); 12336412d79SJohn Baldwin } 12436412d79SJohn Baldwin 12536412d79SJohn Baldwin void 12636412d79SJohn Baldwin _mtx_exit_giant_def(void) 12736412d79SJohn Baldwin { 12836412d79SJohn Baldwin 12936412d79SJohn Baldwin mtx_exit(&Giant, MTX_DEF); 13036412d79SJohn Baldwin } 13136412d79SJohn Baldwin 13236412d79SJohn Baldwin static void 13336412d79SJohn Baldwin propagate_priority(struct proc *p) 13436412d79SJohn Baldwin { 13536412d79SJohn Baldwin int pri = p->p_priority; 13636412d79SJohn Baldwin struct mtx *m = p->p_blocked; 13736412d79SJohn Baldwin 1381bd0eefbSJohn Baldwin mtx_assert(&sched_lock, MA_OWNED); 13936412d79SJohn Baldwin for (;;) { 14036412d79SJohn Baldwin struct proc *p1; 14136412d79SJohn Baldwin 14236412d79SJohn Baldwin p = mtx_owner(m); 14336412d79SJohn Baldwin 14436412d79SJohn Baldwin if (p == NULL) { 14536412d79SJohn Baldwin /* 14636412d79SJohn Baldwin * This really isn't quite right. Really 14736412d79SJohn Baldwin * ought to bump priority of process that 14836412d79SJohn Baldwin * next acquires the mutex. 14936412d79SJohn Baldwin */ 15036412d79SJohn Baldwin MPASS(m->mtx_lock == MTX_CONTESTED); 15136412d79SJohn Baldwin return; 15236412d79SJohn Baldwin } 15336412d79SJohn Baldwin MPASS(p->p_magic == P_MAGIC); 1541bd0eefbSJohn Baldwin KASSERT(p->p_stat != SSLEEP, ("sleeping process owns a mutex")); 15536412d79SJohn Baldwin if (p->p_priority <= pri) 15636412d79SJohn Baldwin return; 1571bd0eefbSJohn Baldwin 1581bd0eefbSJohn Baldwin /* 1591bd0eefbSJohn Baldwin * Bump this process' priority. 1601bd0eefbSJohn Baldwin */ 1611bd0eefbSJohn Baldwin SET_PRIO(p, pri); 1621bd0eefbSJohn Baldwin 16336412d79SJohn Baldwin /* 16436412d79SJohn Baldwin * If lock holder is actually running, just bump priority. 16536412d79SJohn Baldwin */ 1661bd0eefbSJohn Baldwin #ifdef SMP 1671bd0eefbSJohn Baldwin /* 1681bd0eefbSJohn Baldwin * For SMP, we can check the p_oncpu field to see if we are 1691bd0eefbSJohn Baldwin * running. 1701bd0eefbSJohn Baldwin */ 1711bd0eefbSJohn Baldwin if (p->p_oncpu != 0xff) { 17236412d79SJohn Baldwin MPASS(p->p_stat == SRUN || p->p_stat == SZOMB); 17336412d79SJohn Baldwin return; 17436412d79SJohn Baldwin } 1751bd0eefbSJohn Baldwin #else 1761bd0eefbSJohn Baldwin /* 1771bd0eefbSJohn Baldwin * For UP, we check to see if p is curproc (this shouldn't 1781bd0eefbSJohn Baldwin * ever happen however as it would mean we are in a deadlock.) 1791bd0eefbSJohn Baldwin */ 1801bd0eefbSJohn Baldwin if (p == curproc) { 1811bd0eefbSJohn Baldwin panic("Deadlock detected"); 1821bd0eefbSJohn Baldwin return; 1831bd0eefbSJohn Baldwin } 1841bd0eefbSJohn Baldwin #endif 18536412d79SJohn Baldwin /* 18636412d79SJohn Baldwin * If on run queue move to new run queue, and 18736412d79SJohn Baldwin * quit. 18836412d79SJohn Baldwin */ 18936412d79SJohn Baldwin if (p->p_stat == SRUN) { 1901bd0eefbSJohn Baldwin printf("XXX: moving process %d(%s) to a new run queue\n", 1911bd0eefbSJohn Baldwin p->p_pid, p->p_comm); 19236412d79SJohn Baldwin MPASS(p->p_blocked == NULL); 19336412d79SJohn Baldwin remrunqueue(p); 19436412d79SJohn Baldwin setrunqueue(p); 19536412d79SJohn Baldwin return; 19636412d79SJohn Baldwin } 19736412d79SJohn Baldwin 19836412d79SJohn Baldwin /* 1991bd0eefbSJohn Baldwin * If we aren't blocked on a mutex, we should be. 20036412d79SJohn Baldwin */ 2011bd0eefbSJohn Baldwin KASSERT(p->p_stat == SMTX, ( 2021bd0eefbSJohn Baldwin "process %d(%s):%d holds %s but isn't blocked on a mutex\n", 2031bd0eefbSJohn Baldwin p->p_pid, p->p_comm, p->p_stat, 2041bd0eefbSJohn Baldwin m->mtx_description)); 20536412d79SJohn Baldwin 20636412d79SJohn Baldwin /* 20736412d79SJohn Baldwin * Pick up the mutex that p is blocked on. 20836412d79SJohn Baldwin */ 20936412d79SJohn Baldwin m = p->p_blocked; 21036412d79SJohn Baldwin MPASS(m != NULL); 21136412d79SJohn Baldwin 21236412d79SJohn Baldwin printf("XXX: process %d(%s) is blocked on %s\n", p->p_pid, 21336412d79SJohn Baldwin p->p_comm, m->mtx_description); 21436412d79SJohn Baldwin /* 21536412d79SJohn Baldwin * Check if the proc needs to be moved up on 21636412d79SJohn Baldwin * the blocked chain 21736412d79SJohn Baldwin */ 2181bd0eefbSJohn Baldwin if (p == TAILQ_FIRST(&m->mtx_blocked)) { 2191bd0eefbSJohn Baldwin printf("XXX: process at head of run queue\n"); 2201bd0eefbSJohn Baldwin continue; 2211bd0eefbSJohn Baldwin } 2221bd0eefbSJohn Baldwin p1 = TAILQ_PREV(p, rq, p_procq); 2231bd0eefbSJohn Baldwin if (p1->p_priority <= pri) { 22436412d79SJohn Baldwin printf( 22536412d79SJohn Baldwin "XXX: previous process %d(%s) has higher priority\n", 22636412d79SJohn Baldwin p->p_pid, p->p_comm); 22736412d79SJohn Baldwin continue; 22836412d79SJohn Baldwin } 22936412d79SJohn Baldwin 23036412d79SJohn Baldwin /* 2311bd0eefbSJohn Baldwin * Remove proc from blocked chain and determine where 2321bd0eefbSJohn Baldwin * it should be moved up to. Since we know that p1 has 2331bd0eefbSJohn Baldwin * a lower priority than p, we know that at least one 2341bd0eefbSJohn Baldwin * process in the chain has a lower priority and that 2351bd0eefbSJohn Baldwin * p1 will thus not be NULL after the loop. 23636412d79SJohn Baldwin */ 23736412d79SJohn Baldwin TAILQ_REMOVE(&m->mtx_blocked, p, p_procq); 23836412d79SJohn Baldwin TAILQ_FOREACH(p1, &m->mtx_blocked, p_procq) { 23936412d79SJohn Baldwin MPASS(p1->p_magic == P_MAGIC); 24036412d79SJohn Baldwin if (p1->p_priority > pri) 24136412d79SJohn Baldwin break; 24236412d79SJohn Baldwin } 2431bd0eefbSJohn Baldwin MPASS(p1 != NULL); 24436412d79SJohn Baldwin TAILQ_INSERT_BEFORE(p1, p, p_procq); 24536412d79SJohn Baldwin CTR4(KTR_LOCK, 2461bd0eefbSJohn Baldwin "propagate_priority: p 0x%p moved before 0x%p on [0x%p] %s", 24736412d79SJohn Baldwin p, p1, m, m->mtx_description); 24836412d79SJohn Baldwin } 24936412d79SJohn Baldwin } 25036412d79SJohn Baldwin 25136412d79SJohn Baldwin void 25236412d79SJohn Baldwin mtx_enter_hard(struct mtx *m, int type, int saveintr) 25336412d79SJohn Baldwin { 25436412d79SJohn Baldwin struct proc *p = CURPROC; 25536412d79SJohn Baldwin 25636412d79SJohn Baldwin KASSERT(p != NULL, ("curproc is NULL in mutex")); 25736412d79SJohn Baldwin 25836412d79SJohn Baldwin switch (type) { 25936412d79SJohn Baldwin case MTX_DEF: 26036412d79SJohn Baldwin if ((m->mtx_lock & MTX_FLAGMASK) == (uintptr_t)p) { 26136412d79SJohn Baldwin m->mtx_recurse++; 26208812b39SBosko Milekic atomic_set_ptr(&m->mtx_lock, MTX_RECURSED); 263562e4ffeSJohn Baldwin if ((type & MTX_QUIET) == 0) 26436412d79SJohn Baldwin CTR1(KTR_LOCK, "mtx_enter: 0x%p recurse", m); 26536412d79SJohn Baldwin return; 26636412d79SJohn Baldwin } 267562e4ffeSJohn Baldwin if ((type & MTX_QUIET) == 0) 268562e4ffeSJohn Baldwin CTR3(KTR_LOCK, 269562e4ffeSJohn Baldwin "mtx_enter: 0x%p contested (lock=%p) [0x%p]", 27031271627SJohn Baldwin m, (void *)m->mtx_lock, (void *)RETIP(m)); 2711bd0eefbSJohn Baldwin 2721bd0eefbSJohn Baldwin /* 2731bd0eefbSJohn Baldwin * Save our priority. Even though p_nativepri is protected 2741bd0eefbSJohn Baldwin * by sched_lock, we don't obtain it here as it can be 2751bd0eefbSJohn Baldwin * expensive. Since this is the only place p_nativepri is 2761bd0eefbSJohn Baldwin * set, and since two CPUs will not be executing the same 2771bd0eefbSJohn Baldwin * process concurrently, we know that no other CPU is going 2781bd0eefbSJohn Baldwin * to be messing with this. Also, p_nativepri is only read 2791bd0eefbSJohn Baldwin * when we are blocked on a mutex, so that can't be happening 2801bd0eefbSJohn Baldwin * right now either. 2811bd0eefbSJohn Baldwin */ 2821bd0eefbSJohn Baldwin p->p_nativepri = p->p_priority; 28336412d79SJohn Baldwin while (!_obtain_lock(m, p)) { 284f5271ebcSJohn Baldwin uintptr_t v; 28536412d79SJohn Baldwin struct proc *p1; 28636412d79SJohn Baldwin 28736412d79SJohn Baldwin mtx_enter(&sched_lock, MTX_SPIN | MTX_RLIKELY); 28836412d79SJohn Baldwin /* 28936412d79SJohn Baldwin * check if the lock has been released while 29036412d79SJohn Baldwin * waiting for the schedlock. 29136412d79SJohn Baldwin */ 29236412d79SJohn Baldwin if ((v = m->mtx_lock) == MTX_UNOWNED) { 29336412d79SJohn Baldwin mtx_exit(&sched_lock, MTX_SPIN); 29436412d79SJohn Baldwin continue; 29536412d79SJohn Baldwin } 29636412d79SJohn Baldwin /* 29736412d79SJohn Baldwin * The mutex was marked contested on release. This 29836412d79SJohn Baldwin * means that there are processes blocked on it. 29936412d79SJohn Baldwin */ 30036412d79SJohn Baldwin if (v == MTX_CONTESTED) { 30136412d79SJohn Baldwin p1 = TAILQ_FIRST(&m->mtx_blocked); 30236412d79SJohn Baldwin KASSERT(p1 != NULL, ("contested mutex has no contesters")); 30336412d79SJohn Baldwin KASSERT(p != NULL, ("curproc is NULL for contested mutex")); 30436412d79SJohn Baldwin m->mtx_lock = (uintptr_t)p | MTX_CONTESTED; 30536412d79SJohn Baldwin if (p1->p_priority < p->p_priority) { 30636412d79SJohn Baldwin SET_PRIO(p, p1->p_priority); 30736412d79SJohn Baldwin } 30836412d79SJohn Baldwin mtx_exit(&sched_lock, MTX_SPIN); 30936412d79SJohn Baldwin return; 31036412d79SJohn Baldwin } 31136412d79SJohn Baldwin /* 31236412d79SJohn Baldwin * If the mutex isn't already contested and 31336412d79SJohn Baldwin * a failure occurs setting the contested bit the 31436412d79SJohn Baldwin * mutex was either release or the 31536412d79SJohn Baldwin * state of the RECURSION bit changed. 31636412d79SJohn Baldwin */ 31736412d79SJohn Baldwin if ((v & MTX_CONTESTED) == 0 && 31836412d79SJohn Baldwin !atomic_cmpset_ptr(&m->mtx_lock, (void *)v, 31936412d79SJohn Baldwin (void *)(v | MTX_CONTESTED))) { 32036412d79SJohn Baldwin mtx_exit(&sched_lock, MTX_SPIN); 32136412d79SJohn Baldwin continue; 32236412d79SJohn Baldwin } 32336412d79SJohn Baldwin 32436412d79SJohn Baldwin /* We definitely have to sleep for this lock */ 32536412d79SJohn Baldwin mtx_assert(m, MA_NOTOWNED); 32636412d79SJohn Baldwin 32736412d79SJohn Baldwin #ifdef notyet 32836412d79SJohn Baldwin /* 32936412d79SJohn Baldwin * If we're borrowing an interrupted thread's VM 33036412d79SJohn Baldwin * context must clean up before going to sleep. 33136412d79SJohn Baldwin */ 33236412d79SJohn Baldwin if (p->p_flag & (P_ITHD | P_SITHD)) { 33336412d79SJohn Baldwin ithd_t *it = (ithd_t *)p; 33436412d79SJohn Baldwin 33536412d79SJohn Baldwin if (it->it_interrupted) { 336562e4ffeSJohn Baldwin if ((type & MTX_QUIET) == 0) 33736412d79SJohn Baldwin CTR2(KTR_LOCK, 33836412d79SJohn Baldwin "mtx_enter: 0x%x interrupted 0x%x", 33936412d79SJohn Baldwin it, it->it_interrupted); 34036412d79SJohn Baldwin intr_thd_fixup(it); 34136412d79SJohn Baldwin } 34236412d79SJohn Baldwin } 34336412d79SJohn Baldwin #endif 34436412d79SJohn Baldwin 34536412d79SJohn Baldwin /* Put us on the list of procs blocked on this mutex */ 34636412d79SJohn Baldwin if (TAILQ_EMPTY(&m->mtx_blocked)) { 34736412d79SJohn Baldwin p1 = (struct proc *)(m->mtx_lock & 34836412d79SJohn Baldwin MTX_FLAGMASK); 34936412d79SJohn Baldwin LIST_INSERT_HEAD(&p1->p_contested, m, 35036412d79SJohn Baldwin mtx_contested); 35136412d79SJohn Baldwin TAILQ_INSERT_TAIL(&m->mtx_blocked, p, p_procq); 35236412d79SJohn Baldwin } else { 35336412d79SJohn Baldwin TAILQ_FOREACH(p1, &m->mtx_blocked, p_procq) 35436412d79SJohn Baldwin if (p1->p_priority > p->p_priority) 35536412d79SJohn Baldwin break; 35636412d79SJohn Baldwin if (p1) 35736412d79SJohn Baldwin TAILQ_INSERT_BEFORE(p1, p, p_procq); 35836412d79SJohn Baldwin else 35936412d79SJohn Baldwin TAILQ_INSERT_TAIL(&m->mtx_blocked, p, 36036412d79SJohn Baldwin p_procq); 36136412d79SJohn Baldwin } 36236412d79SJohn Baldwin 36336412d79SJohn Baldwin p->p_blocked = m; /* Who we're blocked on */ 36486327ad8SJohn Baldwin p->p_mtxname = m->mtx_description; 36536412d79SJohn Baldwin p->p_stat = SMTX; 36636412d79SJohn Baldwin #if 0 36736412d79SJohn Baldwin propagate_priority(p); 36836412d79SJohn Baldwin #endif 369562e4ffeSJohn Baldwin if ((type & MTX_QUIET) == 0) 370562e4ffeSJohn Baldwin CTR3(KTR_LOCK, 371562e4ffeSJohn Baldwin "mtx_enter: p 0x%p blocked on [0x%p] %s", 37236412d79SJohn Baldwin p, m, m->mtx_description); 37320cdcc5bSJohn Baldwin mi_switch(); 374562e4ffeSJohn Baldwin if ((type & MTX_QUIET) == 0) 37536412d79SJohn Baldwin CTR3(KTR_LOCK, 37636412d79SJohn Baldwin "mtx_enter: p 0x%p free from blocked on [0x%p] %s", 37736412d79SJohn Baldwin p, m, m->mtx_description); 37836412d79SJohn Baldwin mtx_exit(&sched_lock, MTX_SPIN); 37936412d79SJohn Baldwin } 38036412d79SJohn Baldwin return; 38136412d79SJohn Baldwin case MTX_SPIN: 38236412d79SJohn Baldwin case MTX_SPIN | MTX_FIRST: 38336412d79SJohn Baldwin case MTX_SPIN | MTX_TOPHALF: 38436412d79SJohn Baldwin { 38536412d79SJohn Baldwin int i = 0; 38636412d79SJohn Baldwin 38736412d79SJohn Baldwin if (m->mtx_lock == (uintptr_t)p) { 38836412d79SJohn Baldwin m->mtx_recurse++; 38936412d79SJohn Baldwin return; 39036412d79SJohn Baldwin } 391562e4ffeSJohn Baldwin if ((type & MTX_QUIET) == 0) 39236412d79SJohn Baldwin CTR1(KTR_LOCK, "mtx_enter: %p spinning", m); 39336412d79SJohn Baldwin for (;;) { 39436412d79SJohn Baldwin if (_obtain_lock(m, p)) 39536412d79SJohn Baldwin break; 39636412d79SJohn Baldwin while (m->mtx_lock != MTX_UNOWNED) { 39736412d79SJohn Baldwin if (i++ < 1000000) 39836412d79SJohn Baldwin continue; 39936412d79SJohn Baldwin if (i++ < 6000000) 40036412d79SJohn Baldwin DELAY (1); 40136412d79SJohn Baldwin #ifdef DDB 40236412d79SJohn Baldwin else if (!db_active) 40336412d79SJohn Baldwin #else 40436412d79SJohn Baldwin else 40536412d79SJohn Baldwin #endif 40636412d79SJohn Baldwin panic( 40736412d79SJohn Baldwin "spin lock %s held by 0x%p for > 5 seconds", 40836412d79SJohn Baldwin m->mtx_description, 40936412d79SJohn Baldwin (void *)m->mtx_lock); 41036412d79SJohn Baldwin } 41136412d79SJohn Baldwin } 41236412d79SJohn Baldwin 41336412d79SJohn Baldwin #ifdef MUTEX_DEBUG 41436412d79SJohn Baldwin if (type != MTX_SPIN) 41536412d79SJohn Baldwin m->mtx_saveintr = 0xbeefface; 41636412d79SJohn Baldwin else 41736412d79SJohn Baldwin #endif 41836412d79SJohn Baldwin m->mtx_saveintr = saveintr; 419562e4ffeSJohn Baldwin if ((type & MTX_QUIET) == 0) 42036412d79SJohn Baldwin CTR1(KTR_LOCK, "mtx_enter: 0x%p spin done", m); 42136412d79SJohn Baldwin return; 42236412d79SJohn Baldwin } 42336412d79SJohn Baldwin } 42436412d79SJohn Baldwin } 42536412d79SJohn Baldwin 42636412d79SJohn Baldwin void 42736412d79SJohn Baldwin mtx_exit_hard(struct mtx *m, int type) 42836412d79SJohn Baldwin { 42936412d79SJohn Baldwin struct proc *p, *p1; 43036412d79SJohn Baldwin struct mtx *m1; 43136412d79SJohn Baldwin int pri; 43236412d79SJohn Baldwin 43336412d79SJohn Baldwin p = CURPROC; 43436412d79SJohn Baldwin switch (type) { 43536412d79SJohn Baldwin case MTX_DEF: 43636412d79SJohn Baldwin case MTX_DEF | MTX_NOSWITCH: 43708812b39SBosko Milekic if (mtx_recursed(m)) { 43836412d79SJohn Baldwin if (--(m->mtx_recurse) == 0) 43908812b39SBosko Milekic atomic_clear_ptr(&m->mtx_lock, MTX_RECURSED); 440562e4ffeSJohn Baldwin if ((type & MTX_QUIET) == 0) 44136412d79SJohn Baldwin CTR1(KTR_LOCK, "mtx_exit: 0x%p unrecurse", m); 44236412d79SJohn Baldwin return; 44336412d79SJohn Baldwin } 44436412d79SJohn Baldwin mtx_enter(&sched_lock, MTX_SPIN); 445562e4ffeSJohn Baldwin if ((type & MTX_QUIET) == 0) 44636412d79SJohn Baldwin CTR1(KTR_LOCK, "mtx_exit: 0x%p contested", m); 44736412d79SJohn Baldwin p1 = TAILQ_FIRST(&m->mtx_blocked); 44836412d79SJohn Baldwin MPASS(p->p_magic == P_MAGIC); 44936412d79SJohn Baldwin MPASS(p1->p_magic == P_MAGIC); 45036412d79SJohn Baldwin TAILQ_REMOVE(&m->mtx_blocked, p1, p_procq); 45136412d79SJohn Baldwin if (TAILQ_EMPTY(&m->mtx_blocked)) { 45236412d79SJohn Baldwin LIST_REMOVE(m, mtx_contested); 45336412d79SJohn Baldwin _release_lock_quick(m); 454562e4ffeSJohn Baldwin if ((type & MTX_QUIET) == 0) 45536412d79SJohn Baldwin CTR1(KTR_LOCK, "mtx_exit: 0x%p not held", m); 45636412d79SJohn Baldwin } else 457f404050eSJohn Baldwin atomic_store_rel_ptr(&m->mtx_lock, 458f404050eSJohn Baldwin (void *)MTX_CONTESTED); 45936412d79SJohn Baldwin pri = MAXPRI; 46036412d79SJohn Baldwin LIST_FOREACH(m1, &p->p_contested, mtx_contested) { 46136412d79SJohn Baldwin int cp = TAILQ_FIRST(&m1->mtx_blocked)->p_priority; 46236412d79SJohn Baldwin if (cp < pri) 46336412d79SJohn Baldwin pri = cp; 46436412d79SJohn Baldwin } 46536412d79SJohn Baldwin if (pri > p->p_nativepri) 46636412d79SJohn Baldwin pri = p->p_nativepri; 46736412d79SJohn Baldwin SET_PRIO(p, pri); 468562e4ffeSJohn Baldwin if ((type & MTX_QUIET) == 0) 469562e4ffeSJohn Baldwin CTR2(KTR_LOCK, 470562e4ffeSJohn Baldwin "mtx_exit: 0x%p contested setrunqueue 0x%p", m, p1); 47136412d79SJohn Baldwin p1->p_blocked = NULL; 47286327ad8SJohn Baldwin p1->p_mtxname = NULL; 47336412d79SJohn Baldwin p1->p_stat = SRUN; 47436412d79SJohn Baldwin setrunqueue(p1); 47536412d79SJohn Baldwin if ((type & MTX_NOSWITCH) == 0 && p1->p_priority < pri) { 47636412d79SJohn Baldwin #ifdef notyet 47736412d79SJohn Baldwin if (p->p_flag & (P_ITHD | P_SITHD)) { 47836412d79SJohn Baldwin ithd_t *it = (ithd_t *)p; 47936412d79SJohn Baldwin 48036412d79SJohn Baldwin if (it->it_interrupted) { 481562e4ffeSJohn Baldwin if ((type & MTX_QUIET) == 0) 48236412d79SJohn Baldwin CTR2(KTR_LOCK, 48336412d79SJohn Baldwin "mtx_exit: 0x%x interruped 0x%x", 48436412d79SJohn Baldwin it, it->it_interrupted); 48536412d79SJohn Baldwin intr_thd_fixup(it); 48636412d79SJohn Baldwin } 48736412d79SJohn Baldwin } 48836412d79SJohn Baldwin #endif 48936412d79SJohn Baldwin setrunqueue(p); 490562e4ffeSJohn Baldwin if ((type & MTX_QUIET) == 0) 491562e4ffeSJohn Baldwin CTR2(KTR_LOCK, 492562e4ffeSJohn Baldwin "mtx_exit: 0x%p switching out lock=0x%p", 49331271627SJohn Baldwin m, (void *)m->mtx_lock); 49436412d79SJohn Baldwin mi_switch(); 495562e4ffeSJohn Baldwin if ((type & MTX_QUIET) == 0) 496562e4ffeSJohn Baldwin CTR2(KTR_LOCK, 497562e4ffeSJohn Baldwin "mtx_exit: 0x%p resuming lock=0x%p", 49831271627SJohn Baldwin m, (void *)m->mtx_lock); 49936412d79SJohn Baldwin } 50036412d79SJohn Baldwin mtx_exit(&sched_lock, MTX_SPIN); 50136412d79SJohn Baldwin break; 50236412d79SJohn Baldwin case MTX_SPIN: 50336412d79SJohn Baldwin case MTX_SPIN | MTX_FIRST: 50408812b39SBosko Milekic if (mtx_recursed(m)) { 50536412d79SJohn Baldwin m->mtx_recurse--; 50636412d79SJohn Baldwin return; 50736412d79SJohn Baldwin } 50836412d79SJohn Baldwin MPASS(mtx_owned(m)); 50936412d79SJohn Baldwin _release_lock_quick(m); 51036412d79SJohn Baldwin if (type & MTX_FIRST) 51136412d79SJohn Baldwin enable_intr(); /* XXX is this kosher? */ 51236412d79SJohn Baldwin else { 51336412d79SJohn Baldwin MPASS(m->mtx_saveintr != 0xbeefface); 51436412d79SJohn Baldwin restore_intr(m->mtx_saveintr); 51536412d79SJohn Baldwin } 51636412d79SJohn Baldwin break; 51736412d79SJohn Baldwin case MTX_SPIN | MTX_TOPHALF: 51808812b39SBosko Milekic if (mtx_recursed(m)) { 51936412d79SJohn Baldwin m->mtx_recurse--; 52036412d79SJohn Baldwin return; 52136412d79SJohn Baldwin } 52236412d79SJohn Baldwin MPASS(mtx_owned(m)); 52336412d79SJohn Baldwin _release_lock_quick(m); 52436412d79SJohn Baldwin break; 52536412d79SJohn Baldwin default: 52636412d79SJohn Baldwin panic("mtx_exit_hard: unsupported type 0x%x\n", type); 52736412d79SJohn Baldwin } 52836412d79SJohn Baldwin } 52936412d79SJohn Baldwin 53036412d79SJohn Baldwin #define MV_DESTROY 0 /* validate before destory */ 53136412d79SJohn Baldwin #define MV_INIT 1 /* validate before init */ 53236412d79SJohn Baldwin 53336412d79SJohn Baldwin #ifdef MUTEX_DEBUG 53436412d79SJohn Baldwin 53536412d79SJohn Baldwin int mtx_validate __P((struct mtx *, int)); 53636412d79SJohn Baldwin 53736412d79SJohn Baldwin int 53836412d79SJohn Baldwin mtx_validate(struct mtx *m, int when) 53936412d79SJohn Baldwin { 54036412d79SJohn Baldwin struct mtx *mp; 54136412d79SJohn Baldwin int i; 54236412d79SJohn Baldwin int retval = 0; 54336412d79SJohn Baldwin 54436412d79SJohn Baldwin if (m == &all_mtx || cold) 54536412d79SJohn Baldwin return 0; 54636412d79SJohn Baldwin 54736412d79SJohn Baldwin mtx_enter(&all_mtx, MTX_DEF); 54836412d79SJohn Baldwin /* 54936412d79SJohn Baldwin * XXX - When kernacc() is fixed on the alpha to handle K0_SEG memory properly 55036412d79SJohn Baldwin * we can re-enable the kernacc() checks. 55136412d79SJohn Baldwin */ 55236412d79SJohn Baldwin #ifndef __alpha__ 55336412d79SJohn Baldwin MPASS(kernacc((caddr_t)all_mtx.mtx_next, sizeof(uintptr_t), 55436412d79SJohn Baldwin VM_PROT_READ) == 1); 55536412d79SJohn Baldwin #endif 55636412d79SJohn Baldwin MPASS(all_mtx.mtx_next->mtx_prev == &all_mtx); 55736412d79SJohn Baldwin for (i = 0, mp = all_mtx.mtx_next; mp != &all_mtx; mp = mp->mtx_next) { 55836412d79SJohn Baldwin #ifndef __alpha__ 55936412d79SJohn Baldwin if (kernacc((caddr_t)mp->mtx_next, sizeof(uintptr_t), 56036412d79SJohn Baldwin VM_PROT_READ) != 1) { 56136412d79SJohn Baldwin panic("mtx_validate: mp=%p mp->mtx_next=%p", 56236412d79SJohn Baldwin mp, mp->mtx_next); 56336412d79SJohn Baldwin } 56436412d79SJohn Baldwin #endif 56536412d79SJohn Baldwin i++; 56636412d79SJohn Baldwin if (i > mtx_cur_cnt) { 56736412d79SJohn Baldwin panic("mtx_validate: too many in chain, known=%d\n", 56836412d79SJohn Baldwin mtx_cur_cnt); 56936412d79SJohn Baldwin } 57036412d79SJohn Baldwin } 57136412d79SJohn Baldwin MPASS(i == mtx_cur_cnt); 57236412d79SJohn Baldwin switch (when) { 57336412d79SJohn Baldwin case MV_DESTROY: 57436412d79SJohn Baldwin for (mp = all_mtx.mtx_next; mp != &all_mtx; mp = mp->mtx_next) 57536412d79SJohn Baldwin if (mp == m) 57636412d79SJohn Baldwin break; 57736412d79SJohn Baldwin MPASS(mp == m); 57836412d79SJohn Baldwin break; 57936412d79SJohn Baldwin case MV_INIT: 58036412d79SJohn Baldwin for (mp = all_mtx.mtx_next; mp != &all_mtx; mp = mp->mtx_next) 58136412d79SJohn Baldwin if (mp == m) { 58236412d79SJohn Baldwin /* 58336412d79SJohn Baldwin * Not good. This mutex already exists. 58436412d79SJohn Baldwin */ 58536412d79SJohn Baldwin printf("re-initing existing mutex %s\n", 58636412d79SJohn Baldwin m->mtx_description); 58736412d79SJohn Baldwin MPASS(m->mtx_lock == MTX_UNOWNED); 58836412d79SJohn Baldwin retval = 1; 58936412d79SJohn Baldwin } 59036412d79SJohn Baldwin } 59136412d79SJohn Baldwin mtx_exit(&all_mtx, MTX_DEF); 59236412d79SJohn Baldwin return (retval); 59336412d79SJohn Baldwin } 59436412d79SJohn Baldwin #endif 59536412d79SJohn Baldwin 59636412d79SJohn Baldwin void 59736412d79SJohn Baldwin mtx_init(struct mtx *m, const char *t, int flag) 59836412d79SJohn Baldwin { 5996936206eSJohn Baldwin #ifdef WITNESS 60036412d79SJohn Baldwin struct mtx_debug *debug; 60136412d79SJohn Baldwin #endif 60236412d79SJohn Baldwin 603562e4ffeSJohn Baldwin if ((flag & MTX_QUIET) == 0) 60436412d79SJohn Baldwin CTR2(KTR_LOCK, "mtx_init 0x%p (%s)", m, t); 60536412d79SJohn Baldwin #ifdef MUTEX_DEBUG 60636412d79SJohn Baldwin if (mtx_validate(m, MV_INIT)) /* diagnostic and error correction */ 60736412d79SJohn Baldwin return; 6086936206eSJohn Baldwin #endif 6096936206eSJohn Baldwin #ifdef WITNESS 61036412d79SJohn Baldwin if (flag & MTX_COLD) 61136412d79SJohn Baldwin debug = m->mtx_debug; 61236412d79SJohn Baldwin else 61336412d79SJohn Baldwin debug = NULL; 61436412d79SJohn Baldwin if (debug == NULL) { 61536412d79SJohn Baldwin #ifdef DIAGNOSTIC 61636412d79SJohn Baldwin if(cold && bootverbose) 61736412d79SJohn Baldwin printf("malloc'ing mtx_debug while cold for %s\n", t); 61836412d79SJohn Baldwin #endif 61936412d79SJohn Baldwin 62036412d79SJohn Baldwin /* XXX - should not use DEVBUF */ 6217cc0979fSDavid Malone debug = malloc(sizeof(struct mtx_debug), M_DEVBUF, 6227cc0979fSDavid Malone M_NOWAIT | M_ZERO); 62336412d79SJohn Baldwin MPASS(debug != NULL); 62436412d79SJohn Baldwin } 62536412d79SJohn Baldwin #endif 62636412d79SJohn Baldwin bzero((void *)m, sizeof *m); 62736412d79SJohn Baldwin TAILQ_INIT(&m->mtx_blocked); 6286936206eSJohn Baldwin #ifdef WITNESS 62936412d79SJohn Baldwin m->mtx_debug = debug; 63036412d79SJohn Baldwin #endif 63136412d79SJohn Baldwin m->mtx_description = t; 63236412d79SJohn Baldwin m->mtx_lock = MTX_UNOWNED; 63336412d79SJohn Baldwin /* Put on all mutex queue */ 63436412d79SJohn Baldwin mtx_enter(&all_mtx, MTX_DEF); 63536412d79SJohn Baldwin m->mtx_next = &all_mtx; 63636412d79SJohn Baldwin m->mtx_prev = all_mtx.mtx_prev; 63736412d79SJohn Baldwin m->mtx_prev->mtx_next = m; 63836412d79SJohn Baldwin all_mtx.mtx_prev = m; 63936412d79SJohn Baldwin if (++mtx_cur_cnt > mtx_max_cnt) 64036412d79SJohn Baldwin mtx_max_cnt = mtx_cur_cnt; 64136412d79SJohn Baldwin mtx_exit(&all_mtx, MTX_DEF); 64236412d79SJohn Baldwin witness_init(m, flag); 64336412d79SJohn Baldwin } 64436412d79SJohn Baldwin 64536412d79SJohn Baldwin void 64636412d79SJohn Baldwin mtx_destroy(struct mtx *m) 64736412d79SJohn Baldwin { 64836412d79SJohn Baldwin 64936412d79SJohn Baldwin CTR2(KTR_LOCK, "mtx_destroy 0x%p (%s)", m, m->mtx_description); 65036412d79SJohn Baldwin #ifdef MUTEX_DEBUG 65136412d79SJohn Baldwin if (m->mtx_next == NULL) 65236412d79SJohn Baldwin panic("mtx_destroy: %p (%s) already destroyed", 65336412d79SJohn Baldwin m, m->mtx_description); 65436412d79SJohn Baldwin 65536412d79SJohn Baldwin if (!mtx_owned(m)) { 65636412d79SJohn Baldwin MPASS(m->mtx_lock == MTX_UNOWNED); 65736412d79SJohn Baldwin } else { 65808812b39SBosko Milekic MPASS((m->mtx_lock & (MTX_RECURSED|MTX_CONTESTED)) == 0); 65936412d79SJohn Baldwin } 66036412d79SJohn Baldwin mtx_validate(m, MV_DESTROY); /* diagnostic */ 66136412d79SJohn Baldwin #endif 66236412d79SJohn Baldwin 66336412d79SJohn Baldwin #ifdef WITNESS 66436412d79SJohn Baldwin if (m->mtx_witness) 66536412d79SJohn Baldwin witness_destroy(m); 66636412d79SJohn Baldwin #endif /* WITNESS */ 66736412d79SJohn Baldwin 66836412d79SJohn Baldwin /* Remove from the all mutex queue */ 66936412d79SJohn Baldwin mtx_enter(&all_mtx, MTX_DEF); 67036412d79SJohn Baldwin m->mtx_next->mtx_prev = m->mtx_prev; 67136412d79SJohn Baldwin m->mtx_prev->mtx_next = m->mtx_next; 67236412d79SJohn Baldwin #ifdef MUTEX_DEBUG 67336412d79SJohn Baldwin m->mtx_next = m->mtx_prev = NULL; 6746936206eSJohn Baldwin #endif 6756936206eSJohn Baldwin #ifdef WITNESS 67636412d79SJohn Baldwin free(m->mtx_debug, M_DEVBUF); 67736412d79SJohn Baldwin m->mtx_debug = NULL; 67836412d79SJohn Baldwin #endif 67936412d79SJohn Baldwin mtx_cur_cnt--; 68036412d79SJohn Baldwin mtx_exit(&all_mtx, MTX_DEF); 68136412d79SJohn Baldwin } 6820384fff8SJason Evans 6830384fff8SJason Evans /* 6840384fff8SJason Evans * The non-inlined versions of the mtx_*() functions are always built (above), 6856936206eSJohn Baldwin * but the witness code depends on the WITNESS kernel option being specified. 6860384fff8SJason Evans */ 6876936206eSJohn Baldwin #ifdef WITNESS 6880384fff8SJason Evans 6890384fff8SJason Evans #define WITNESS_COUNT 200 6900384fff8SJason Evans #define WITNESS_NCHILDREN 2 6910384fff8SJason Evans 69278f0da03SJohn Baldwin int witness_watch = 1; 6930384fff8SJason Evans 694606f8eb2SJohn Baldwin struct witness { 6950384fff8SJason Evans struct witness *w_next; 696b67a3e6eSJohn Baldwin const char *w_description; 69712473b76SJason Evans const char *w_file; 6980384fff8SJason Evans int w_line; 6990384fff8SJason Evans struct witness *w_morechildren; 7000384fff8SJason Evans u_char w_childcnt; 7010384fff8SJason Evans u_char w_Giant_squawked:1; 7020384fff8SJason Evans u_char w_other_squawked:1; 7030384fff8SJason Evans u_char w_same_squawked:1; 70408812b39SBosko Milekic u_char w_sleep:1; /* MTX_DEF type mutex. */ 70508812b39SBosko Milekic u_char w_spin:1; /* MTX_SPIN type mutex. */ 70608812b39SBosko Milekic u_char w_recurse:1; /* MTX_RECURSE mutex option. */ 7070384fff8SJason Evans u_int w_level; 7080384fff8SJason Evans struct witness *w_children[WITNESS_NCHILDREN]; 709606f8eb2SJohn Baldwin }; 7100384fff8SJason Evans 711606f8eb2SJohn Baldwin struct witness_blessed { 7120384fff8SJason Evans char *b_lock1; 7130384fff8SJason Evans char *b_lock2; 714606f8eb2SJohn Baldwin }; 7150384fff8SJason Evans 716a5a96a19SJohn Baldwin #ifdef DDB 7170384fff8SJason Evans /* 718a5a96a19SJohn Baldwin * When DDB is enabled and witness_ddb is set to 1, it will cause the system to 7190384fff8SJason Evans * drop into kdebug() when: 7200384fff8SJason Evans * - a lock heirarchy violation occurs 7210384fff8SJason Evans * - locks are held when going to sleep. 7220384fff8SJason Evans */ 723a5a96a19SJohn Baldwin #ifdef WITNESS_DDB 724a5a96a19SJohn Baldwin int witness_ddb = 1; 725a5a96a19SJohn Baldwin #else 726a5a96a19SJohn Baldwin int witness_ddb = 0; 7270384fff8SJason Evans #endif 728a5a96a19SJohn Baldwin SYSCTL_INT(_debug, OID_AUTO, witness_ddb, CTLFLAG_RW, &witness_ddb, 0, ""); 729a5a96a19SJohn Baldwin #endif /* DDB */ 7300384fff8SJason Evans 731a5a96a19SJohn Baldwin #ifdef WITNESS_SKIPSPIN 732a5a96a19SJohn Baldwin int witness_skipspin = 1; 733a5a96a19SJohn Baldwin #else 734a5a96a19SJohn Baldwin int witness_skipspin = 0; 7350384fff8SJason Evans #endif 736a5a96a19SJohn Baldwin SYSCTL_INT(_debug, OID_AUTO, witness_skipspin, CTLFLAG_RD, &witness_skipspin, 0, 737a5a96a19SJohn Baldwin ""); 7380384fff8SJason Evans 739a5a96a19SJohn Baldwin MUTEX_DECLARE(static,w_mtx); 740606f8eb2SJohn Baldwin static struct witness *w_free; 741606f8eb2SJohn Baldwin static struct witness *w_all; 7420384fff8SJason Evans static int w_inited; 7430384fff8SJason Evans static int witness_dead; /* fatal error, probably no memory */ 7440384fff8SJason Evans 745606f8eb2SJohn Baldwin static struct witness w_data[WITNESS_COUNT]; 7460384fff8SJason Evans 747b67a3e6eSJohn Baldwin static struct witness *enroll __P((const char *description, int flag)); 748606f8eb2SJohn Baldwin static int itismychild __P((struct witness *parent, struct witness *child)); 749606f8eb2SJohn Baldwin static void removechild __P((struct witness *parent, struct witness *child)); 750606f8eb2SJohn Baldwin static int isitmychild __P((struct witness *parent, struct witness *child)); 751606f8eb2SJohn Baldwin static int isitmydescendant __P((struct witness *parent, struct witness *child)); 752606f8eb2SJohn Baldwin static int dup_ok __P((struct witness *)); 753606f8eb2SJohn Baldwin static int blessed __P((struct witness *, struct witness *)); 7540384fff8SJason Evans static void witness_displaydescendants 755606f8eb2SJohn Baldwin __P((void(*)(const char *fmt, ...), struct witness *)); 756606f8eb2SJohn Baldwin static void witness_leveldescendents __P((struct witness *parent, int level)); 7570384fff8SJason Evans static void witness_levelall __P((void)); 758606f8eb2SJohn Baldwin static struct witness * witness_get __P((void)); 759606f8eb2SJohn Baldwin static void witness_free __P((struct witness *m)); 7600384fff8SJason Evans 7610384fff8SJason Evans 7620384fff8SJason Evans static char *ignore_list[] = { 7630384fff8SJason Evans "witness lock", 7640384fff8SJason Evans NULL 7650384fff8SJason Evans }; 7660384fff8SJason Evans 7670384fff8SJason Evans static char *spin_order_list[] = { 768a5a96a19SJohn Baldwin "sio", 7698f838cb5SJohn Baldwin "sched lock", 77020cdcc5bSJohn Baldwin #ifdef __i386__ 77120cdcc5bSJohn Baldwin "clk", 77220cdcc5bSJohn Baldwin #endif 773fa2fbc3dSJake Burkholder "callout", 7740384fff8SJason Evans /* 7750384fff8SJason Evans * leaf locks 7760384fff8SJason Evans */ 7770384fff8SJason Evans NULL 7780384fff8SJason Evans }; 7790384fff8SJason Evans 7800384fff8SJason Evans static char *order_list[] = { 781a5d5c61cSJake Burkholder "uidinfo hash", "uidinfo struct", NULL, 7820384fff8SJason Evans NULL 7830384fff8SJason Evans }; 7840384fff8SJason Evans 7850384fff8SJason Evans static char *dup_list[] = { 7860384fff8SJason Evans NULL 7870384fff8SJason Evans }; 7880384fff8SJason Evans 7890384fff8SJason Evans static char *sleep_list[] = { 7907da6f977SJake Burkholder "Giant", 7910384fff8SJason Evans NULL 7920384fff8SJason Evans }; 7930384fff8SJason Evans 7940384fff8SJason Evans /* 7950384fff8SJason Evans * Pairs of locks which have been blessed 7960384fff8SJason Evans * Don't complain about order problems with blessed locks 7970384fff8SJason Evans */ 798606f8eb2SJohn Baldwin static struct witness_blessed blessed_list[] = { 7990384fff8SJason Evans }; 800606f8eb2SJohn Baldwin static int blessed_count = sizeof(blessed_list) / sizeof(struct witness_blessed); 8010384fff8SJason Evans 8020384fff8SJason Evans void 803606f8eb2SJohn Baldwin witness_init(struct mtx *m, int flag) 8040384fff8SJason Evans { 8050384fff8SJason Evans m->mtx_witness = enroll(m->mtx_description, flag); 8060384fff8SJason Evans } 8070384fff8SJason Evans 8080384fff8SJason Evans void 809606f8eb2SJohn Baldwin witness_destroy(struct mtx *m) 8100384fff8SJason Evans { 811606f8eb2SJohn Baldwin struct mtx *m1; 8120384fff8SJason Evans struct proc *p; 8130384fff8SJason Evans p = CURPROC; 8140384fff8SJason Evans for ((m1 = LIST_FIRST(&p->p_heldmtx)); m1 != NULL; 8150384fff8SJason Evans m1 = LIST_NEXT(m1, mtx_held)) { 8160384fff8SJason Evans if (m1 == m) { 8170384fff8SJason Evans LIST_REMOVE(m, mtx_held); 8180384fff8SJason Evans break; 8190384fff8SJason Evans } 8200384fff8SJason Evans } 8210384fff8SJason Evans return; 8220384fff8SJason Evans 8230384fff8SJason Evans } 8240384fff8SJason Evans 8250384fff8SJason Evans void 826606f8eb2SJohn Baldwin witness_enter(struct mtx *m, int flags, const char *file, int line) 8270384fff8SJason Evans { 828606f8eb2SJohn Baldwin struct witness *w, *w1; 829606f8eb2SJohn Baldwin struct mtx *m1; 8300384fff8SJason Evans struct proc *p; 8310384fff8SJason Evans int i; 832a5a96a19SJohn Baldwin #ifdef DDB 833a5a96a19SJohn Baldwin int go_into_ddb = 0; 834a5a96a19SJohn Baldwin #endif /* DDB */ 8350384fff8SJason Evans 836562e4ffeSJohn Baldwin if (panicstr) 837562e4ffeSJohn Baldwin return; 8380384fff8SJason Evans w = m->mtx_witness; 8390384fff8SJason Evans p = CURPROC; 8400384fff8SJason Evans 8410384fff8SJason Evans if (flags & MTX_SPIN) { 84208812b39SBosko Milekic if (!(w->w_spin)) 8435340642aSJason Evans panic("mutex_enter: MTX_SPIN on MTX_DEF mutex %s @" 8445340642aSJason Evans " %s:%d", m->mtx_description, file, line); 84508812b39SBosko Milekic if (mtx_recursed(m)) { 84608812b39SBosko Milekic if (!(w->w_recurse)) 84708812b39SBosko Milekic panic("mutex_enter: recursion on non-recursive" 84808812b39SBosko Milekic " mutex %s @ %s:%d", m->mtx_description, 84908812b39SBosko Milekic file, line); 8500384fff8SJason Evans return; 85108812b39SBosko Milekic } 852562e4ffeSJohn Baldwin mtx_enter(&w_mtx, MTX_SPIN | MTX_QUIET); 853ef73ae4bSJake Burkholder i = PCPU_GET(witness_spin_check); 8540384fff8SJason Evans if (i != 0 && w->w_level < i) { 855562e4ffeSJohn Baldwin mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET); 8565340642aSJason Evans panic("mutex_enter(%s:%x, MTX_SPIN) out of order @" 8575340642aSJason Evans " %s:%d already holding %s:%x", 8580384fff8SJason Evans m->mtx_description, w->w_level, file, line, 8590384fff8SJason Evans spin_order_list[ffs(i)-1], i); 8600384fff8SJason Evans } 8610384fff8SJason Evans PCPU_SET(witness_spin_check, i | w->w_level); 862562e4ffeSJohn Baldwin mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET); 863bbc7a98aSJohn Baldwin w->w_file = file; 864bbc7a98aSJohn Baldwin w->w_line = line; 865bbc7a98aSJohn Baldwin m->mtx_line = line; 866bbc7a98aSJohn Baldwin m->mtx_file = file; 8670384fff8SJason Evans return; 8680384fff8SJason Evans } 8690384fff8SJason Evans if (w->w_spin) 8700384fff8SJason Evans panic("mutex_enter: MTX_DEF on MTX_SPIN mutex %s @ %s:%d", 8710384fff8SJason Evans m->mtx_description, file, line); 8720384fff8SJason Evans 87308812b39SBosko Milekic if (mtx_recursed(m)) { 87408812b39SBosko Milekic if (!(w->w_recurse)) 87508812b39SBosko Milekic panic("mutex_enter: recursion on non-recursive" 87608812b39SBosko Milekic " mutex %s @ %s:%d", m->mtx_description, 87708812b39SBosko Milekic file, line); 8780384fff8SJason Evans return; 87908812b39SBosko Milekic } 8800384fff8SJason Evans if (witness_dead) 8810384fff8SJason Evans goto out; 882562e4ffeSJohn Baldwin if (cold) 8830384fff8SJason Evans goto out; 8840384fff8SJason Evans 8850384fff8SJason Evans if (!mtx_legal2block()) 8860384fff8SJason Evans panic("blockable mtx_enter() of %s when not legal @ %s:%d", 8870384fff8SJason Evans m->mtx_description, file, line); 8880384fff8SJason Evans /* 8890384fff8SJason Evans * Is this the first mutex acquired 8900384fff8SJason Evans */ 8910384fff8SJason Evans if ((m1 = LIST_FIRST(&p->p_heldmtx)) == NULL) 8920384fff8SJason Evans goto out; 8930384fff8SJason Evans 8940384fff8SJason Evans if ((w1 = m1->mtx_witness) == w) { 8950384fff8SJason Evans if (w->w_same_squawked || dup_ok(w)) 8960384fff8SJason Evans goto out; 8970384fff8SJason Evans w->w_same_squawked = 1; 8980384fff8SJason Evans printf("acquring duplicate lock of same type: \"%s\"\n", 8990384fff8SJason Evans m->mtx_description); 9000384fff8SJason Evans printf(" 1st @ %s:%d\n", w->w_file, w->w_line); 9010384fff8SJason Evans printf(" 2nd @ %s:%d\n", file, line); 902a5a96a19SJohn Baldwin #ifdef DDB 903a5a96a19SJohn Baldwin go_into_ddb = 1; 904a5a96a19SJohn Baldwin #endif /* DDB */ 9050384fff8SJason Evans goto out; 9060384fff8SJason Evans } 9070384fff8SJason Evans MPASS(!mtx_owned(&w_mtx)); 908562e4ffeSJohn Baldwin mtx_enter(&w_mtx, MTX_SPIN | MTX_QUIET); 9090384fff8SJason Evans /* 9100384fff8SJason Evans * If we have a known higher number just say ok 9110384fff8SJason Evans */ 9120384fff8SJason Evans if (witness_watch > 1 && w->w_level > w1->w_level) { 913562e4ffeSJohn Baldwin mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET); 9140384fff8SJason Evans goto out; 9150384fff8SJason Evans } 9160384fff8SJason Evans if (isitmydescendant(m1->mtx_witness, w)) { 917562e4ffeSJohn Baldwin mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET); 9180384fff8SJason Evans goto out; 9190384fff8SJason Evans } 9200384fff8SJason Evans for (i = 0; m1 != NULL; m1 = LIST_NEXT(m1, mtx_held), i++) { 9210384fff8SJason Evans 92236412d79SJohn Baldwin MPASS(i < 200); 9230384fff8SJason Evans w1 = m1->mtx_witness; 9240384fff8SJason Evans if (isitmydescendant(w, w1)) { 925562e4ffeSJohn Baldwin mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET); 9260384fff8SJason Evans if (blessed(w, w1)) 9270384fff8SJason Evans goto out; 9280384fff8SJason Evans if (m1 == &Giant) { 9290384fff8SJason Evans if (w1->w_Giant_squawked) 9300384fff8SJason Evans goto out; 9310384fff8SJason Evans else 9320384fff8SJason Evans w1->w_Giant_squawked = 1; 9330384fff8SJason Evans } else { 9340384fff8SJason Evans if (w1->w_other_squawked) 9350384fff8SJason Evans goto out; 9360384fff8SJason Evans else 9370384fff8SJason Evans w1->w_other_squawked = 1; 9380384fff8SJason Evans } 9390384fff8SJason Evans printf("lock order reversal\n"); 9400384fff8SJason Evans printf(" 1st %s last acquired @ %s:%d\n", 9410384fff8SJason Evans w->w_description, w->w_file, w->w_line); 9420384fff8SJason Evans printf(" 2nd %p %s @ %s:%d\n", 9430384fff8SJason Evans m1, w1->w_description, w1->w_file, w1->w_line); 9440384fff8SJason Evans printf(" 3rd %p %s @ %s:%d\n", 9450384fff8SJason Evans m, w->w_description, file, line); 946a5a96a19SJohn Baldwin #ifdef DDB 947a5a96a19SJohn Baldwin go_into_ddb = 1; 948a5a96a19SJohn Baldwin #endif /* DDB */ 9490384fff8SJason Evans goto out; 9500384fff8SJason Evans } 9510384fff8SJason Evans } 9520384fff8SJason Evans m1 = LIST_FIRST(&p->p_heldmtx); 9530384fff8SJason Evans if (!itismychild(m1->mtx_witness, w)) 954562e4ffeSJohn Baldwin mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET); 9550384fff8SJason Evans 9560384fff8SJason Evans out: 957a5a96a19SJohn Baldwin #ifdef DDB 958a5a96a19SJohn Baldwin if (witness_ddb && go_into_ddb) 959a5a96a19SJohn Baldwin Debugger("witness_enter"); 960a5a96a19SJohn Baldwin #endif /* DDB */ 9610384fff8SJason Evans w->w_file = file; 9620384fff8SJason Evans w->w_line = line; 9630384fff8SJason Evans m->mtx_line = line; 9640384fff8SJason Evans m->mtx_file = file; 9650384fff8SJason Evans 9660384fff8SJason Evans /* 9670384fff8SJason Evans * If this pays off it likely means that a mutex being witnessed 9680384fff8SJason Evans * is acquired in hardclock. Put it in the ignore list. It is 9690384fff8SJason Evans * likely not the mutex this assert fails on. 9700384fff8SJason Evans */ 97136412d79SJohn Baldwin MPASS(m->mtx_held.le_prev == NULL); 9720384fff8SJason Evans LIST_INSERT_HEAD(&p->p_heldmtx, (struct mtx*)m, mtx_held); 9730384fff8SJason Evans } 9740384fff8SJason Evans 9750384fff8SJason Evans void 976606f8eb2SJohn Baldwin witness_exit(struct mtx *m, int flags, const char *file, int line) 9770384fff8SJason Evans { 978606f8eb2SJohn Baldwin struct witness *w; 9790384fff8SJason Evans 980562e4ffeSJohn Baldwin if (panicstr) 981562e4ffeSJohn Baldwin return; 9820384fff8SJason Evans w = m->mtx_witness; 9830384fff8SJason Evans 9840384fff8SJason Evans if (flags & MTX_SPIN) { 98508812b39SBosko Milekic if (!(w->w_spin)) 9865340642aSJason Evans panic("mutex_exit: MTX_SPIN on MTX_DEF mutex %s @" 9875340642aSJason Evans " %s:%d", m->mtx_description, file, line); 98808812b39SBosko Milekic if (mtx_recursed(m)) { 98908812b39SBosko Milekic if (!(w->w_recurse)) 99008812b39SBosko Milekic panic("mutex_exit: recursion on non-recursive" 99108812b39SBosko Milekic " mutex %s @ %s:%d", m->mtx_description, 99208812b39SBosko Milekic file, line); 9930384fff8SJason Evans return; 99408812b39SBosko Milekic } 995562e4ffeSJohn Baldwin mtx_enter(&w_mtx, MTX_SPIN | MTX_QUIET); 996ef73ae4bSJake Burkholder PCPU_SET(witness_spin_check, 997ef73ae4bSJake Burkholder PCPU_GET(witness_spin_check) & ~w->w_level); 998562e4ffeSJohn Baldwin mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET); 9990384fff8SJason Evans return; 10000384fff8SJason Evans } 10010384fff8SJason Evans if (w->w_spin) 10020384fff8SJason Evans panic("mutex_exit: MTX_DEF on MTX_SPIN mutex %s @ %s:%d", 10030384fff8SJason Evans m->mtx_description, file, line); 10040384fff8SJason Evans 100508812b39SBosko Milekic if (mtx_recursed(m)) { 100608812b39SBosko Milekic if (!(w->w_recurse)) 100708812b39SBosko Milekic panic("mutex_exit: recursion on non-recursive" 100808812b39SBosko Milekic " mutex %s @ %s:%d", m->mtx_description, 100908812b39SBosko Milekic file, line); 10100384fff8SJason Evans return; 101108812b39SBosko Milekic } 10120384fff8SJason Evans 10130384fff8SJason Evans if ((flags & MTX_NOSWITCH) == 0 && !mtx_legal2block() && !cold) 10140384fff8SJason Evans panic("switchable mtx_exit() of %s when not legal @ %s:%d", 10150384fff8SJason Evans m->mtx_description, file, line); 10160384fff8SJason Evans LIST_REMOVE(m, mtx_held); 10170384fff8SJason Evans m->mtx_held.le_prev = NULL; 10180384fff8SJason Evans } 10190384fff8SJason Evans 10200384fff8SJason Evans void 1021606f8eb2SJohn Baldwin witness_try_enter(struct mtx *m, int flags, const char *file, int line) 10220384fff8SJason Evans { 10230384fff8SJason Evans struct proc *p; 1024606f8eb2SJohn Baldwin struct witness *w = m->mtx_witness; 10250384fff8SJason Evans 1026562e4ffeSJohn Baldwin if (panicstr) 1027562e4ffeSJohn Baldwin return; 10280384fff8SJason Evans if (flags & MTX_SPIN) { 102908812b39SBosko Milekic if (!(w->w_spin)) 10300384fff8SJason Evans panic("mutex_try_enter: " 10310384fff8SJason Evans "MTX_SPIN on MTX_DEF mutex %s @ %s:%d", 10320384fff8SJason Evans m->mtx_description, file, line); 103308812b39SBosko Milekic if (mtx_recursed(m)) { 103408812b39SBosko Milekic if (!(w->w_recurse)) 103508812b39SBosko Milekic panic("mutex_try_enter: recursion on" 103608812b39SBosko Milekic " non-recursive mutex %s @ %s:%d", 103708812b39SBosko Milekic m->mtx_description, file, line); 10380384fff8SJason Evans return; 103908812b39SBosko Milekic } 1040562e4ffeSJohn Baldwin mtx_enter(&w_mtx, MTX_SPIN | MTX_QUIET); 1041ef73ae4bSJake Burkholder PCPU_SET(witness_spin_check, 1042ef73ae4bSJake Burkholder PCPU_GET(witness_spin_check) | w->w_level); 1043562e4ffeSJohn Baldwin mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET); 1044bbc7a98aSJohn Baldwin w->w_file = file; 1045bbc7a98aSJohn Baldwin w->w_line = line; 1046bbc7a98aSJohn Baldwin m->mtx_line = line; 1047bbc7a98aSJohn Baldwin m->mtx_file = file; 10480384fff8SJason Evans return; 10490384fff8SJason Evans } 10500384fff8SJason Evans 10510384fff8SJason Evans if (w->w_spin) 10520384fff8SJason Evans panic("mutex_try_enter: MTX_DEF on MTX_SPIN mutex %s @ %s:%d", 10530384fff8SJason Evans m->mtx_description, file, line); 10540384fff8SJason Evans 105508812b39SBosko Milekic if (mtx_recursed(m)) { 105608812b39SBosko Milekic if (!(w->w_recurse)) 105708812b39SBosko Milekic panic("mutex_try_enter: recursion on non-recursive" 105808812b39SBosko Milekic " mutex %s @ %s:%d", m->mtx_description, file, 105908812b39SBosko Milekic line); 10600384fff8SJason Evans return; 106108812b39SBosko Milekic } 10620384fff8SJason Evans w->w_file = file; 10630384fff8SJason Evans w->w_line = line; 10640384fff8SJason Evans m->mtx_line = line; 10650384fff8SJason Evans m->mtx_file = file; 10660384fff8SJason Evans p = CURPROC; 106736412d79SJohn Baldwin MPASS(m->mtx_held.le_prev == NULL); 10680384fff8SJason Evans LIST_INSERT_HEAD(&p->p_heldmtx, (struct mtx*)m, mtx_held); 10690384fff8SJason Evans } 10700384fff8SJason Evans 10710384fff8SJason Evans void 10720384fff8SJason Evans witness_display(void(*prnt)(const char *fmt, ...)) 10730384fff8SJason Evans { 1074606f8eb2SJohn Baldwin struct witness *w, *w1; 10750384fff8SJason Evans 10760384fff8SJason Evans witness_levelall(); 10770384fff8SJason Evans 10780384fff8SJason Evans for (w = w_all; w; w = w->w_next) { 10790384fff8SJason Evans if (w->w_file == NULL) 10800384fff8SJason Evans continue; 10810384fff8SJason Evans for (w1 = w_all; w1; w1 = w1->w_next) { 10820384fff8SJason Evans if (isitmychild(w1, w)) 10830384fff8SJason Evans break; 10840384fff8SJason Evans } 10850384fff8SJason Evans if (w1 != NULL) 10860384fff8SJason Evans continue; 10870384fff8SJason Evans /* 10880384fff8SJason Evans * This lock has no anscestors, display its descendants. 10890384fff8SJason Evans */ 10900384fff8SJason Evans witness_displaydescendants(prnt, w); 10910384fff8SJason Evans } 10920384fff8SJason Evans prnt("\nMutex which were never acquired\n"); 10930384fff8SJason Evans for (w = w_all; w; w = w->w_next) { 10940384fff8SJason Evans if (w->w_file != NULL) 10950384fff8SJason Evans continue; 10960384fff8SJason Evans prnt("%s\n", w->w_description); 10970384fff8SJason Evans } 10980384fff8SJason Evans } 10990384fff8SJason Evans 11000384fff8SJason Evans int 1101606f8eb2SJohn Baldwin witness_sleep(int check_only, struct mtx *mtx, const char *file, int line) 11020384fff8SJason Evans { 1103606f8eb2SJohn Baldwin struct mtx *m; 11040384fff8SJason Evans struct proc *p; 11050384fff8SJason Evans char **sleep; 11060384fff8SJason Evans int n = 0; 11070384fff8SJason Evans 11080384fff8SJason Evans p = CURPROC; 11090384fff8SJason Evans for ((m = LIST_FIRST(&p->p_heldmtx)); m != NULL; 11100384fff8SJason Evans m = LIST_NEXT(m, mtx_held)) { 11110384fff8SJason Evans if (m == mtx) 11120384fff8SJason Evans continue; 11130384fff8SJason Evans for (sleep = sleep_list; *sleep!= NULL; sleep++) 11140384fff8SJason Evans if (strcmp(m->mtx_description, *sleep) == 0) 11150384fff8SJason Evans goto next; 11160384fff8SJason Evans printf("%s:%d: %s with \"%s\" locked from %s:%d\n", 11170384fff8SJason Evans file, line, check_only ? "could sleep" : "sleeping", 11180384fff8SJason Evans m->mtx_description, 11190384fff8SJason Evans m->mtx_witness->w_file, m->mtx_witness->w_line); 11200384fff8SJason Evans n++; 11210384fff8SJason Evans next: 11220384fff8SJason Evans } 1123a5a96a19SJohn Baldwin #ifdef DDB 1124a5a96a19SJohn Baldwin if (witness_ddb && n) 1125a5a96a19SJohn Baldwin Debugger("witness_sleep"); 1126a5a96a19SJohn Baldwin #endif /* DDB */ 11270384fff8SJason Evans return (n); 11280384fff8SJason Evans } 11290384fff8SJason Evans 1130606f8eb2SJohn Baldwin static struct witness * 1131b67a3e6eSJohn Baldwin enroll(const char *description, int flag) 11320384fff8SJason Evans { 11330384fff8SJason Evans int i; 1134606f8eb2SJohn Baldwin struct witness *w, *w1; 11350384fff8SJason Evans char **ignore; 11360384fff8SJason Evans char **order; 11370384fff8SJason Evans 11380384fff8SJason Evans if (!witness_watch) 11390384fff8SJason Evans return (NULL); 11400384fff8SJason Evans for (ignore = ignore_list; *ignore != NULL; ignore++) 11410384fff8SJason Evans if (strcmp(description, *ignore) == 0) 11420384fff8SJason Evans return (NULL); 11430384fff8SJason Evans 11440384fff8SJason Evans if (w_inited == 0) { 1145428b4b55SJohn Baldwin mtx_init(&w_mtx, "witness lock", MTX_COLD | MTX_SPIN); 11460384fff8SJason Evans for (i = 0; i < WITNESS_COUNT; i++) { 11470384fff8SJason Evans w = &w_data[i]; 11480384fff8SJason Evans witness_free(w); 11490384fff8SJason Evans } 11500384fff8SJason Evans w_inited = 1; 11510384fff8SJason Evans for (order = order_list; *order != NULL; order++) { 11520384fff8SJason Evans w = enroll(*order, MTX_DEF); 11530384fff8SJason Evans w->w_file = "order list"; 11540384fff8SJason Evans for (order++; *order != NULL; order++) { 11550384fff8SJason Evans w1 = enroll(*order, MTX_DEF); 11560384fff8SJason Evans w1->w_file = "order list"; 11570384fff8SJason Evans itismychild(w, w1); 11580384fff8SJason Evans w = w1; 11590384fff8SJason Evans } 11600384fff8SJason Evans } 11610384fff8SJason Evans } 11620384fff8SJason Evans if ((flag & MTX_SPIN) && witness_skipspin) 11630384fff8SJason Evans return (NULL); 1164562e4ffeSJohn Baldwin mtx_enter(&w_mtx, MTX_SPIN | MTX_QUIET); 11650384fff8SJason Evans for (w = w_all; w; w = w->w_next) { 11660384fff8SJason Evans if (strcmp(description, w->w_description) == 0) { 1167562e4ffeSJohn Baldwin mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET); 11680384fff8SJason Evans return (w); 11690384fff8SJason Evans } 11700384fff8SJason Evans } 11710384fff8SJason Evans if ((w = witness_get()) == NULL) 11720384fff8SJason Evans return (NULL); 11730384fff8SJason Evans w->w_next = w_all; 11740384fff8SJason Evans w_all = w; 11750384fff8SJason Evans w->w_description = description; 1176562e4ffeSJohn Baldwin mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET); 11770384fff8SJason Evans if (flag & MTX_SPIN) { 11780384fff8SJason Evans w->w_spin = 1; 11790384fff8SJason Evans 11800384fff8SJason Evans i = 1; 11810384fff8SJason Evans for (order = spin_order_list; *order != NULL; order++) { 11820384fff8SJason Evans if (strcmp(description, *order) == 0) 11830384fff8SJason Evans break; 11840384fff8SJason Evans i <<= 1; 11850384fff8SJason Evans } 11860384fff8SJason Evans if (*order == NULL) 11870384fff8SJason Evans panic("spin lock %s not in order list", description); 11880384fff8SJason Evans w->w_level = i; 118908812b39SBosko Milekic } else 119008812b39SBosko Milekic w->w_sleep = 1; 119108812b39SBosko Milekic 119208812b39SBosko Milekic if (flag & MTX_RECURSE) 119308812b39SBosko Milekic w->w_recurse = 1; 119408812b39SBosko Milekic 11950384fff8SJason Evans return (w); 11960384fff8SJason Evans } 11970384fff8SJason Evans 11980384fff8SJason Evans static int 1199606f8eb2SJohn Baldwin itismychild(struct witness *parent, struct witness *child) 12000384fff8SJason Evans { 12010384fff8SJason Evans static int recursed; 12020384fff8SJason Evans 12030384fff8SJason Evans /* 12040384fff8SJason Evans * Insert "child" after "parent" 12050384fff8SJason Evans */ 12060384fff8SJason Evans while (parent->w_morechildren) 12070384fff8SJason Evans parent = parent->w_morechildren; 12080384fff8SJason Evans 12090384fff8SJason Evans if (parent->w_childcnt == WITNESS_NCHILDREN) { 12100384fff8SJason Evans if ((parent->w_morechildren = witness_get()) == NULL) 12110384fff8SJason Evans return (1); 12120384fff8SJason Evans parent = parent->w_morechildren; 12130384fff8SJason Evans } 121436412d79SJohn Baldwin MPASS(child != NULL); 12150384fff8SJason Evans parent->w_children[parent->w_childcnt++] = child; 12160384fff8SJason Evans /* 12170384fff8SJason Evans * now prune whole tree 12180384fff8SJason Evans */ 12190384fff8SJason Evans if (recursed) 12200384fff8SJason Evans return (0); 12210384fff8SJason Evans recursed = 1; 12220384fff8SJason Evans for (child = w_all; child != NULL; child = child->w_next) { 12230384fff8SJason Evans for (parent = w_all; parent != NULL; 12240384fff8SJason Evans parent = parent->w_next) { 12250384fff8SJason Evans if (!isitmychild(parent, child)) 12260384fff8SJason Evans continue; 12270384fff8SJason Evans removechild(parent, child); 12280384fff8SJason Evans if (isitmydescendant(parent, child)) 12290384fff8SJason Evans continue; 12300384fff8SJason Evans itismychild(parent, child); 12310384fff8SJason Evans } 12320384fff8SJason Evans } 12330384fff8SJason Evans recursed = 0; 12340384fff8SJason Evans witness_levelall(); 12350384fff8SJason Evans return (0); 12360384fff8SJason Evans } 12370384fff8SJason Evans 12380384fff8SJason Evans static void 1239606f8eb2SJohn Baldwin removechild(struct witness *parent, struct witness *child) 12400384fff8SJason Evans { 1241606f8eb2SJohn Baldwin struct witness *w, *w1; 12420384fff8SJason Evans int i; 12430384fff8SJason Evans 12440384fff8SJason Evans for (w = parent; w != NULL; w = w->w_morechildren) 12450384fff8SJason Evans for (i = 0; i < w->w_childcnt; i++) 12460384fff8SJason Evans if (w->w_children[i] == child) 12470384fff8SJason Evans goto found; 12480384fff8SJason Evans return; 12490384fff8SJason Evans found: 12500384fff8SJason Evans for (w1 = w; w1->w_morechildren != NULL; w1 = w1->w_morechildren) 12510384fff8SJason Evans continue; 12520384fff8SJason Evans w->w_children[i] = w1->w_children[--w1->w_childcnt]; 125336412d79SJohn Baldwin MPASS(w->w_children[i] != NULL); 12540384fff8SJason Evans 12550384fff8SJason Evans if (w1->w_childcnt != 0) 12560384fff8SJason Evans return; 12570384fff8SJason Evans 12580384fff8SJason Evans if (w1 == parent) 12590384fff8SJason Evans return; 12600384fff8SJason Evans for (w = parent; w->w_morechildren != w1; w = w->w_morechildren) 12610384fff8SJason Evans continue; 12620384fff8SJason Evans w->w_morechildren = 0; 12630384fff8SJason Evans witness_free(w1); 12640384fff8SJason Evans } 12650384fff8SJason Evans 12660384fff8SJason Evans static int 1267606f8eb2SJohn Baldwin isitmychild(struct witness *parent, struct witness *child) 12680384fff8SJason Evans { 1269606f8eb2SJohn Baldwin struct witness *w; 12700384fff8SJason Evans int i; 12710384fff8SJason Evans 12720384fff8SJason Evans for (w = parent; w != NULL; w = w->w_morechildren) { 12730384fff8SJason Evans for (i = 0; i < w->w_childcnt; i++) { 12740384fff8SJason Evans if (w->w_children[i] == child) 12750384fff8SJason Evans return (1); 12760384fff8SJason Evans } 12770384fff8SJason Evans } 12780384fff8SJason Evans return (0); 12790384fff8SJason Evans } 12800384fff8SJason Evans 12810384fff8SJason Evans static int 1282606f8eb2SJohn Baldwin isitmydescendant(struct witness *parent, struct witness *child) 12830384fff8SJason Evans { 1284606f8eb2SJohn Baldwin struct witness *w; 12850384fff8SJason Evans int i; 12860384fff8SJason Evans int j; 12870384fff8SJason Evans 12880384fff8SJason Evans for (j = 0, w = parent; w != NULL; w = w->w_morechildren, j++) { 128936412d79SJohn Baldwin MPASS(j < 1000); 12900384fff8SJason Evans for (i = 0; i < w->w_childcnt; i++) { 12910384fff8SJason Evans if (w->w_children[i] == child) 12920384fff8SJason Evans return (1); 12930384fff8SJason Evans } 12940384fff8SJason Evans for (i = 0; i < w->w_childcnt; i++) { 12950384fff8SJason Evans if (isitmydescendant(w->w_children[i], child)) 12960384fff8SJason Evans return (1); 12970384fff8SJason Evans } 12980384fff8SJason Evans } 12990384fff8SJason Evans return (0); 13000384fff8SJason Evans } 13010384fff8SJason Evans 13020384fff8SJason Evans void 13030384fff8SJason Evans witness_levelall (void) 13040384fff8SJason Evans { 1305606f8eb2SJohn Baldwin struct witness *w, *w1; 13060384fff8SJason Evans 13070384fff8SJason Evans for (w = w_all; w; w = w->w_next) 130808812b39SBosko Milekic if (!(w->w_spin)) 13090384fff8SJason Evans w->w_level = 0; 13100384fff8SJason Evans for (w = w_all; w; w = w->w_next) { 13110384fff8SJason Evans if (w->w_spin) 13120384fff8SJason Evans continue; 13130384fff8SJason Evans for (w1 = w_all; w1; w1 = w1->w_next) { 13140384fff8SJason Evans if (isitmychild(w1, w)) 13150384fff8SJason Evans break; 13160384fff8SJason Evans } 13170384fff8SJason Evans if (w1 != NULL) 13180384fff8SJason Evans continue; 13190384fff8SJason Evans witness_leveldescendents(w, 0); 13200384fff8SJason Evans } 13210384fff8SJason Evans } 13220384fff8SJason Evans 13230384fff8SJason Evans static void 1324606f8eb2SJohn Baldwin witness_leveldescendents(struct witness *parent, int level) 13250384fff8SJason Evans { 13260384fff8SJason Evans int i; 1327606f8eb2SJohn Baldwin struct witness *w; 13280384fff8SJason Evans 13290384fff8SJason Evans if (parent->w_level < level) 13300384fff8SJason Evans parent->w_level = level; 13310384fff8SJason Evans level++; 13320384fff8SJason Evans for (w = parent; w != NULL; w = w->w_morechildren) 13330384fff8SJason Evans for (i = 0; i < w->w_childcnt; i++) 13340384fff8SJason Evans witness_leveldescendents(w->w_children[i], level); 13350384fff8SJason Evans } 13360384fff8SJason Evans 13370384fff8SJason Evans static void 1338606f8eb2SJohn Baldwin witness_displaydescendants(void(*prnt)(const char *fmt, ...), 1339606f8eb2SJohn Baldwin struct witness *parent) 13400384fff8SJason Evans { 1341606f8eb2SJohn Baldwin struct witness *w; 13420384fff8SJason Evans int i; 13430384fff8SJason Evans int level = parent->w_level; 13440384fff8SJason Evans 13450384fff8SJason Evans prnt("%d", level); 13460384fff8SJason Evans if (level < 10) 13470384fff8SJason Evans prnt(" "); 13480384fff8SJason Evans for (i = 0; i < level; i++) 13490384fff8SJason Evans prnt(" "); 13500384fff8SJason Evans prnt("%s", parent->w_description); 13510384fff8SJason Evans if (parent->w_file != NULL) { 13520384fff8SJason Evans prnt(" -- last acquired @ %s", parent->w_file); 13530384fff8SJason Evans #ifndef W_USE_WHERE 13540384fff8SJason Evans prnt(":%d", parent->w_line); 13550384fff8SJason Evans #endif 13560384fff8SJason Evans prnt("\n"); 13570384fff8SJason Evans } 13580384fff8SJason Evans 13590384fff8SJason Evans for (w = parent; w != NULL; w = w->w_morechildren) 13600384fff8SJason Evans for (i = 0; i < w->w_childcnt; i++) 13610384fff8SJason Evans witness_displaydescendants(prnt, w->w_children[i]); 13620384fff8SJason Evans } 13630384fff8SJason Evans 13640384fff8SJason Evans static int 1365606f8eb2SJohn Baldwin dup_ok(struct witness *w) 13660384fff8SJason Evans { 13670384fff8SJason Evans char **dup; 13680384fff8SJason Evans 13690384fff8SJason Evans for (dup = dup_list; *dup!= NULL; dup++) 13700384fff8SJason Evans if (strcmp(w->w_description, *dup) == 0) 13710384fff8SJason Evans return (1); 13720384fff8SJason Evans return (0); 13730384fff8SJason Evans } 13740384fff8SJason Evans 13750384fff8SJason Evans static int 1376606f8eb2SJohn Baldwin blessed(struct witness *w1, struct witness *w2) 13770384fff8SJason Evans { 13780384fff8SJason Evans int i; 1379606f8eb2SJohn Baldwin struct witness_blessed *b; 13800384fff8SJason Evans 13810384fff8SJason Evans for (i = 0; i < blessed_count; i++) { 13820384fff8SJason Evans b = &blessed_list[i]; 13830384fff8SJason Evans if (strcmp(w1->w_description, b->b_lock1) == 0) { 13840384fff8SJason Evans if (strcmp(w2->w_description, b->b_lock2) == 0) 13850384fff8SJason Evans return (1); 13860384fff8SJason Evans continue; 13870384fff8SJason Evans } 13880384fff8SJason Evans if (strcmp(w1->w_description, b->b_lock2) == 0) 13890384fff8SJason Evans if (strcmp(w2->w_description, b->b_lock1) == 0) 13900384fff8SJason Evans return (1); 13910384fff8SJason Evans } 13920384fff8SJason Evans return (0); 13930384fff8SJason Evans } 13940384fff8SJason Evans 1395606f8eb2SJohn Baldwin static struct witness * 13960384fff8SJason Evans witness_get() 13970384fff8SJason Evans { 1398606f8eb2SJohn Baldwin struct witness *w; 13990384fff8SJason Evans 14000384fff8SJason Evans if ((w = w_free) == NULL) { 14010384fff8SJason Evans witness_dead = 1; 1402562e4ffeSJohn Baldwin mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET); 14030384fff8SJason Evans printf("witness exhausted\n"); 14040384fff8SJason Evans return (NULL); 14050384fff8SJason Evans } 14060384fff8SJason Evans w_free = w->w_next; 14070384fff8SJason Evans bzero(w, sizeof(*w)); 14080384fff8SJason Evans return (w); 14090384fff8SJason Evans } 14100384fff8SJason Evans 14110384fff8SJason Evans static void 1412606f8eb2SJohn Baldwin witness_free(struct witness *w) 14130384fff8SJason Evans { 14140384fff8SJason Evans w->w_next = w_free; 14150384fff8SJason Evans w_free = w; 14160384fff8SJason Evans } 14170384fff8SJason Evans 141892cf772dSJake Burkholder int 14190384fff8SJason Evans witness_list(struct proc *p) 14200384fff8SJason Evans { 1421606f8eb2SJohn Baldwin struct mtx *m; 142292cf772dSJake Burkholder int nheld; 14230384fff8SJason Evans 142492cf772dSJake Burkholder nheld = 0; 14250384fff8SJason Evans for ((m = LIST_FIRST(&p->p_heldmtx)); m != NULL; 14260384fff8SJason Evans m = LIST_NEXT(m, mtx_held)) { 14270384fff8SJason Evans printf("\t\"%s\" (%p) locked at %s:%d\n", 14280384fff8SJason Evans m->mtx_description, m, 14290384fff8SJason Evans m->mtx_witness->w_file, m->mtx_witness->w_line); 143092cf772dSJake Burkholder nheld++; 14310384fff8SJason Evans } 143292cf772dSJake Burkholder 143392cf772dSJake Burkholder return (nheld); 14340384fff8SJason Evans } 14350384fff8SJason Evans 14360384fff8SJason Evans void 1437606f8eb2SJohn Baldwin witness_save(struct mtx *m, const char **filep, int *linep) 14380384fff8SJason Evans { 14390384fff8SJason Evans *filep = m->mtx_witness->w_file; 14400384fff8SJason Evans *linep = m->mtx_witness->w_line; 14410384fff8SJason Evans } 14420384fff8SJason Evans 14430384fff8SJason Evans void 1444606f8eb2SJohn Baldwin witness_restore(struct mtx *m, const char *file, int line) 14450384fff8SJason Evans { 14460384fff8SJason Evans m->mtx_witness->w_file = file; 14470384fff8SJason Evans m->mtx_witness->w_line = line; 14480384fff8SJason Evans } 14490384fff8SJason Evans 14506936206eSJohn Baldwin #endif /* WITNESS */ 1451