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 */ 870cde2e34SJason Evans 886936206eSJohn Baldwin #ifdef WITNESS 890cde2e34SJason Evans struct mtx_debug { 900cde2e34SJason Evans struct witness *mtxd_witness; 910cde2e34SJason Evans LIST_ENTRY(mtx) mtxd_held; 920cde2e34SJason Evans const char *mtxd_file; 930cde2e34SJason Evans int mtxd_line; 940cde2e34SJason Evans const char *mtxd_description; 950cde2e34SJason Evans }; 960cde2e34SJason Evans 970cde2e34SJason Evans #define mtx_description mtx_union.mtxu_debug->mtxd_description 980cde2e34SJason Evans #define mtx_held mtx_union.mtxu_debug->mtxd_held 990cde2e34SJason Evans #define mtx_file mtx_union.mtxu_debug->mtxd_file 1000cde2e34SJason Evans #define mtx_line mtx_union.mtxu_debug->mtxd_line 1010cde2e34SJason Evans #define mtx_witness mtx_union.mtxu_debug->mtxd_witness 1020cde2e34SJason Evans #else /* WITNESS */ 1030cde2e34SJason Evans #define mtx_description mtx_union.mtxu_description 1040cde2e34SJason Evans #endif /* WITNESS */ 1050cde2e34SJason Evans 1060cde2e34SJason Evans /* 1070cde2e34SJason Evans * Assembly macros 1080cde2e34SJason Evans *------------------------------------------------------------------------------ 1090cde2e34SJason Evans */ 1100cde2e34SJason Evans 1110cde2e34SJason Evans #define _V(x) __STRING(x) 1120cde2e34SJason Evans 1130cde2e34SJason Evans /* 1140cde2e34SJason Evans * Default, unoptimized mutex micro-operations 1150cde2e34SJason Evans */ 1160cde2e34SJason Evans 1170cde2e34SJason Evans #ifndef _obtain_lock 1180cde2e34SJason Evans /* Actually obtain mtx_lock */ 1190cde2e34SJason Evans #define _obtain_lock(mp, tid) \ 1200cde2e34SJason Evans atomic_cmpset_acq_ptr(&(mp)->mtx_lock, (void *)MTX_UNOWNED, (tid)) 1210cde2e34SJason Evans #endif 1220cde2e34SJason Evans 1230cde2e34SJason Evans #ifndef _release_lock 1240cde2e34SJason Evans /* Actually release mtx_lock */ 1250cde2e34SJason Evans #define _release_lock(mp, tid) \ 1260cde2e34SJason Evans atomic_cmpset_rel_ptr(&(mp)->mtx_lock, (tid), (void *)MTX_UNOWNED) 1270cde2e34SJason Evans #endif 1280cde2e34SJason Evans 1290cde2e34SJason Evans #ifndef _release_lock_quick 1300cde2e34SJason Evans /* Actually release mtx_lock quickly assuming that we own it */ 1310cde2e34SJason Evans #define _release_lock_quick(mp) \ 1320cde2e34SJason Evans atomic_store_rel_ptr(&(mp)->mtx_lock, (void *)MTX_UNOWNED) 1330cde2e34SJason Evans #endif 1340cde2e34SJason Evans 1350cde2e34SJason Evans #ifndef _getlock_sleep 1360cde2e34SJason Evans /* Get a sleep lock, deal with recursion inline. */ 1370cde2e34SJason Evans #define _getlock_sleep(mp, tid, type) do { \ 1380cde2e34SJason Evans if (!_obtain_lock(mp, tid)) { \ 1390cde2e34SJason Evans if (((mp)->mtx_lock & MTX_FLAGMASK) != ((uintptr_t)(tid)))\ 1400cde2e34SJason Evans mtx_enter_hard(mp, (type) & MTX_HARDOPTS, 0); \ 1410cde2e34SJason Evans else { \ 1420cde2e34SJason Evans atomic_set_ptr(&(mp)->mtx_lock, MTX_RECURSED); \ 1430cde2e34SJason Evans (mp)->mtx_recurse++; \ 1440cde2e34SJason Evans } \ 1450cde2e34SJason Evans } \ 1460cde2e34SJason Evans } while (0) 1470cde2e34SJason Evans #endif 1480cde2e34SJason Evans 1490cde2e34SJason Evans #ifndef _getlock_spin_block 1500cde2e34SJason Evans /* Get a spin lock, handle recursion inline (as the less common case) */ 1510cde2e34SJason Evans #define _getlock_spin_block(mp, tid, type) do { \ 1520cde2e34SJason Evans u_int _mtx_intr = save_intr(); \ 1530cde2e34SJason Evans disable_intr(); \ 1540cde2e34SJason Evans if (!_obtain_lock(mp, tid)) \ 1550cde2e34SJason Evans mtx_enter_hard(mp, (type) & MTX_HARDOPTS, _mtx_intr); \ 1560cde2e34SJason Evans else \ 1570cde2e34SJason Evans (mp)->mtx_saveintr = _mtx_intr; \ 1580cde2e34SJason Evans } while (0) 1590cde2e34SJason Evans #endif 1600cde2e34SJason Evans 1610cde2e34SJason Evans #ifndef _getlock_norecurse 1620cde2e34SJason Evans /* 1630cde2e34SJason Evans * Get a lock without any recursion handling. Calls the hard enter function if 1640cde2e34SJason Evans * we can't get it inline. 1650cde2e34SJason Evans */ 1660cde2e34SJason Evans #define _getlock_norecurse(mp, tid, type) do { \ 1670cde2e34SJason Evans if (!_obtain_lock(mp, tid)) \ 1680cde2e34SJason Evans mtx_enter_hard((mp), (type) & MTX_HARDOPTS, 0); \ 1690cde2e34SJason Evans } while (0) 1700cde2e34SJason Evans #endif 1710cde2e34SJason Evans 1720cde2e34SJason Evans #ifndef _exitlock_norecurse 1730cde2e34SJason Evans /* 1740cde2e34SJason Evans * Release a sleep lock assuming we haven't recursed on it, recursion is handled 1750cde2e34SJason Evans * in the hard function. 1760cde2e34SJason Evans */ 1770cde2e34SJason Evans #define _exitlock_norecurse(mp, tid, type) do { \ 1780cde2e34SJason Evans if (!_release_lock(mp, tid)) \ 1790cde2e34SJason Evans mtx_exit_hard((mp), (type) & MTX_HARDOPTS); \ 1800cde2e34SJason Evans } while (0) 1810cde2e34SJason Evans #endif 1820cde2e34SJason Evans 1830cde2e34SJason Evans #ifndef _exitlock 1840cde2e34SJason Evans /* 1850cde2e34SJason Evans * Release a sleep lock when its likely we recursed (the code to 1860cde2e34SJason Evans * deal with simple recursion is inline). 1870cde2e34SJason Evans */ 1880cde2e34SJason Evans #define _exitlock(mp, tid, type) do { \ 1890cde2e34SJason Evans if (!_release_lock(mp, tid)) { \ 1900cde2e34SJason Evans if ((mp)->mtx_lock & MTX_RECURSED) { \ 1910cde2e34SJason Evans if (--((mp)->mtx_recurse) == 0) \ 1920cde2e34SJason Evans atomic_clear_ptr(&(mp)->mtx_lock, \ 1930cde2e34SJason Evans MTX_RECURSED); \ 1940cde2e34SJason Evans } else { \ 1950cde2e34SJason Evans mtx_exit_hard((mp), (type) & MTX_HARDOPTS); \ 1960cde2e34SJason Evans } \ 1970cde2e34SJason Evans } \ 1980cde2e34SJason Evans } while (0) 1990cde2e34SJason Evans #endif 2000cde2e34SJason Evans 2010cde2e34SJason Evans #ifndef _exitlock_spin 2020cde2e34SJason Evans /* Release a spin lock (with possible recursion). */ 2030cde2e34SJason Evans #define _exitlock_spin(mp) do { \ 2040cde2e34SJason Evans if (!mtx_recursed((mp))) { \ 2050cde2e34SJason Evans int _mtx_intr = (mp)->mtx_saveintr; \ 2060cde2e34SJason Evans \ 2070cde2e34SJason Evans _release_lock_quick(mp); \ 2080cde2e34SJason Evans restore_intr(_mtx_intr); \ 2090cde2e34SJason Evans } else { \ 2100cde2e34SJason Evans (mp)->mtx_recurse--; \ 2110cde2e34SJason Evans } \ 2120cde2e34SJason Evans } while (0) 2130cde2e34SJason Evans #endif 2140cde2e34SJason Evans 2150cde2e34SJason Evans #ifdef WITNESS 2160cde2e34SJason Evans static void witness_init(struct mtx *, int flag); 2170cde2e34SJason Evans static void witness_destroy(struct mtx *); 2180cde2e34SJason Evans static void witness_display(void(*)(const char *fmt, ...)); 2190cde2e34SJason Evans 2200cde2e34SJason Evans /* All mutexes in system (used for debug/panic) */ 22136412d79SJohn Baldwin static struct mtx_debug all_mtx_debug = { NULL, {NULL, NULL}, NULL, 0, 22236412d79SJohn Baldwin "All mutexes queue head" }; 223527c2fd2SJason Evans static struct mtx all_mtx = { MTX_UNOWNED, 0, 0, 0, {&all_mtx_debug}, 22436412d79SJohn Baldwin TAILQ_HEAD_INITIALIZER(all_mtx.mtx_blocked), 22536412d79SJohn Baldwin { NULL, NULL }, &all_mtx, &all_mtx }; 226d1c1b841SJason Evans /* 227d1c1b841SJason Evans * Set to 0 once mutexes have been fully initialized so that witness code can be 228d1c1b841SJason Evans * safely executed. 229d1c1b841SJason Evans */ 230d1c1b841SJason Evans static int witness_cold = 1; 2316936206eSJohn Baldwin #else /* WITNESS */ 2320cde2e34SJason Evans /* All mutexes in system (used for debug/panic) */ 233527c2fd2SJason Evans static struct mtx all_mtx = { MTX_UNOWNED, 0, 0, 0, {"All mutexes queue head"}, 23436412d79SJohn Baldwin TAILQ_HEAD_INITIALIZER(all_mtx.mtx_blocked), 23536412d79SJohn Baldwin { NULL, NULL }, &all_mtx, &all_mtx }; 2360cde2e34SJason Evans 2370cde2e34SJason Evans /* 2380cde2e34SJason Evans * flag++ is slezoid way of shutting up unused parameter warning 2390cde2e34SJason Evans * in mtx_init() 2400cde2e34SJason Evans */ 2410cde2e34SJason Evans #define witness_init(m, flag) flag++ 2420cde2e34SJason Evans #define witness_destroy(m) 2430cde2e34SJason Evans #define witness_try_enter(m, t, f, l) 2446936206eSJohn Baldwin #endif /* WITNESS */ 24536412d79SJohn Baldwin 24636412d79SJohn Baldwin static int mtx_cur_cnt; 24736412d79SJohn Baldwin static int mtx_max_cnt; 24836412d79SJohn Baldwin 2491bd0eefbSJohn Baldwin static void propagate_priority(struct proc *); 2500cde2e34SJason Evans static void mtx_enter_hard(struct mtx *, int type, int saveintr); 2510cde2e34SJason Evans static void mtx_exit_hard(struct mtx *, int type); 25236412d79SJohn Baldwin 25336412d79SJohn Baldwin #define mtx_unowned(m) ((m)->mtx_lock == MTX_UNOWNED) 25436412d79SJohn Baldwin #define mtx_owner(m) (mtx_unowned(m) ? NULL \ 25536412d79SJohn Baldwin : (struct proc *)((m)->mtx_lock & MTX_FLAGMASK)) 25636412d79SJohn Baldwin 25736412d79SJohn Baldwin #define RETIP(x) *(((uintptr_t *)(&x)) - 1) 25836412d79SJohn Baldwin #define SET_PRIO(p, pri) (p)->p_priority = (pri) 25936412d79SJohn Baldwin 26036412d79SJohn Baldwin static void 26136412d79SJohn Baldwin propagate_priority(struct proc *p) 26236412d79SJohn Baldwin { 26336412d79SJohn Baldwin int pri = p->p_priority; 26436412d79SJohn Baldwin struct mtx *m = p->p_blocked; 26536412d79SJohn Baldwin 2661bd0eefbSJohn Baldwin mtx_assert(&sched_lock, MA_OWNED); 26736412d79SJohn Baldwin for (;;) { 26836412d79SJohn Baldwin struct proc *p1; 26936412d79SJohn Baldwin 27036412d79SJohn Baldwin p = mtx_owner(m); 27136412d79SJohn Baldwin 27236412d79SJohn Baldwin if (p == NULL) { 27336412d79SJohn Baldwin /* 27436412d79SJohn Baldwin * This really isn't quite right. Really 27536412d79SJohn Baldwin * ought to bump priority of process that 27636412d79SJohn Baldwin * next acquires the mutex. 27736412d79SJohn Baldwin */ 27836412d79SJohn Baldwin MPASS(m->mtx_lock == MTX_CONTESTED); 27936412d79SJohn Baldwin return; 28036412d79SJohn Baldwin } 28136412d79SJohn Baldwin MPASS(p->p_magic == P_MAGIC); 2821bd0eefbSJohn Baldwin KASSERT(p->p_stat != SSLEEP, ("sleeping process owns a mutex")); 28336412d79SJohn Baldwin if (p->p_priority <= pri) 28436412d79SJohn Baldwin return; 2851bd0eefbSJohn Baldwin 2861bd0eefbSJohn Baldwin /* 2871bd0eefbSJohn Baldwin * Bump this process' priority. 2881bd0eefbSJohn Baldwin */ 2891bd0eefbSJohn Baldwin SET_PRIO(p, pri); 2901bd0eefbSJohn Baldwin 29136412d79SJohn Baldwin /* 29236412d79SJohn Baldwin * If lock holder is actually running, just bump priority. 29336412d79SJohn Baldwin */ 2941bd0eefbSJohn Baldwin #ifdef SMP 2951bd0eefbSJohn Baldwin /* 2961bd0eefbSJohn Baldwin * For SMP, we can check the p_oncpu field to see if we are 2971bd0eefbSJohn Baldwin * running. 2981bd0eefbSJohn Baldwin */ 2991bd0eefbSJohn Baldwin if (p->p_oncpu != 0xff) { 30036412d79SJohn Baldwin MPASS(p->p_stat == SRUN || p->p_stat == SZOMB); 30136412d79SJohn Baldwin return; 30236412d79SJohn Baldwin } 3031bd0eefbSJohn Baldwin #else 3041bd0eefbSJohn Baldwin /* 3051bd0eefbSJohn Baldwin * For UP, we check to see if p is curproc (this shouldn't 3061bd0eefbSJohn Baldwin * ever happen however as it would mean we are in a deadlock.) 3071bd0eefbSJohn Baldwin */ 3081bd0eefbSJohn Baldwin if (p == curproc) { 3091bd0eefbSJohn Baldwin panic("Deadlock detected"); 3101bd0eefbSJohn Baldwin return; 3111bd0eefbSJohn Baldwin } 3121bd0eefbSJohn Baldwin #endif 31336412d79SJohn Baldwin /* 31436412d79SJohn Baldwin * If on run queue move to new run queue, and 31536412d79SJohn Baldwin * quit. 31636412d79SJohn Baldwin */ 31736412d79SJohn Baldwin if (p->p_stat == SRUN) { 3181bd0eefbSJohn Baldwin printf("XXX: moving process %d(%s) to a new run queue\n", 3191bd0eefbSJohn Baldwin p->p_pid, p->p_comm); 32036412d79SJohn Baldwin MPASS(p->p_blocked == NULL); 32136412d79SJohn Baldwin remrunqueue(p); 32236412d79SJohn Baldwin setrunqueue(p); 32336412d79SJohn Baldwin return; 32436412d79SJohn Baldwin } 32536412d79SJohn Baldwin 32636412d79SJohn Baldwin /* 3271bd0eefbSJohn Baldwin * If we aren't blocked on a mutex, we should be. 32836412d79SJohn Baldwin */ 3291bd0eefbSJohn Baldwin KASSERT(p->p_stat == SMTX, ( 3301bd0eefbSJohn Baldwin "process %d(%s):%d holds %s but isn't blocked on a mutex\n", 3311bd0eefbSJohn Baldwin p->p_pid, p->p_comm, p->p_stat, 3321bd0eefbSJohn Baldwin m->mtx_description)); 33336412d79SJohn Baldwin 33436412d79SJohn Baldwin /* 33536412d79SJohn Baldwin * Pick up the mutex that p is blocked on. 33636412d79SJohn Baldwin */ 33736412d79SJohn Baldwin m = p->p_blocked; 33836412d79SJohn Baldwin MPASS(m != NULL); 33936412d79SJohn Baldwin 34036412d79SJohn Baldwin printf("XXX: process %d(%s) is blocked on %s\n", p->p_pid, 34136412d79SJohn Baldwin p->p_comm, m->mtx_description); 34236412d79SJohn Baldwin /* 34336412d79SJohn Baldwin * Check if the proc needs to be moved up on 34436412d79SJohn Baldwin * the blocked chain 34536412d79SJohn Baldwin */ 3461bd0eefbSJohn Baldwin if (p == TAILQ_FIRST(&m->mtx_blocked)) { 3471bd0eefbSJohn Baldwin printf("XXX: process at head of run queue\n"); 3481bd0eefbSJohn Baldwin continue; 3491bd0eefbSJohn Baldwin } 3501bd0eefbSJohn Baldwin p1 = TAILQ_PREV(p, rq, p_procq); 3511bd0eefbSJohn Baldwin if (p1->p_priority <= pri) { 35236412d79SJohn Baldwin printf( 35336412d79SJohn Baldwin "XXX: previous process %d(%s) has higher priority\n", 35436412d79SJohn Baldwin p->p_pid, p->p_comm); 35536412d79SJohn Baldwin continue; 35636412d79SJohn Baldwin } 35736412d79SJohn Baldwin 35836412d79SJohn Baldwin /* 3591bd0eefbSJohn Baldwin * Remove proc from blocked chain and determine where 3601bd0eefbSJohn Baldwin * it should be moved up to. Since we know that p1 has 3611bd0eefbSJohn Baldwin * a lower priority than p, we know that at least one 3621bd0eefbSJohn Baldwin * process in the chain has a lower priority and that 3631bd0eefbSJohn Baldwin * p1 will thus not be NULL after the loop. 36436412d79SJohn Baldwin */ 36536412d79SJohn Baldwin TAILQ_REMOVE(&m->mtx_blocked, p, p_procq); 36636412d79SJohn Baldwin TAILQ_FOREACH(p1, &m->mtx_blocked, p_procq) { 36736412d79SJohn Baldwin MPASS(p1->p_magic == P_MAGIC); 36836412d79SJohn Baldwin if (p1->p_priority > pri) 36936412d79SJohn Baldwin break; 37036412d79SJohn Baldwin } 3711bd0eefbSJohn Baldwin MPASS(p1 != NULL); 37236412d79SJohn Baldwin TAILQ_INSERT_BEFORE(p1, p, p_procq); 37336412d79SJohn Baldwin CTR4(KTR_LOCK, 3741bd0eefbSJohn Baldwin "propagate_priority: p 0x%p moved before 0x%p on [0x%p] %s", 37536412d79SJohn Baldwin p, p1, m, m->mtx_description); 37636412d79SJohn Baldwin } 37736412d79SJohn Baldwin } 37836412d79SJohn Baldwin 3790cde2e34SJason Evans /* 3800cde2e34SJason Evans * Get lock 'm', the macro handles the easy (and most common cases) and leaves 3810cde2e34SJason Evans * the slow stuff to the mtx_enter_hard() function. 3820cde2e34SJason Evans * 3830cde2e34SJason Evans * Note: since type is usually a constant much of this code is optimized out. 3840cde2e34SJason Evans */ 3850cde2e34SJason Evans void 3860cde2e34SJason Evans _mtx_enter(struct mtx *mtxp, int type, const char *file, int line) 3870cde2e34SJason Evans { 3880cde2e34SJason Evans struct mtx *mpp = mtxp; 3890cde2e34SJason Evans 3900cde2e34SJason Evans /* bits only valid on mtx_exit() */ 3910cde2e34SJason Evans MPASS4(((type) & (MTX_NORECURSE | MTX_NOSWITCH)) == 0, 3920cde2e34SJason Evans STR_mtx_bad_type, file, line); 3930cde2e34SJason Evans 3940cde2e34SJason Evans if ((type) & MTX_SPIN) { 3950cde2e34SJason Evans /* 3960cde2e34SJason Evans * Easy cases of spin locks: 3970cde2e34SJason Evans * 3980cde2e34SJason Evans * 1) We already own the lock and will simply recurse on it (if 3990cde2e34SJason Evans * RLIKELY) 4000cde2e34SJason Evans * 4010cde2e34SJason Evans * 2) The lock is free, we just get it 4020cde2e34SJason Evans */ 4030cde2e34SJason Evans if ((type) & MTX_RLIKELY) { 4040cde2e34SJason Evans /* 4050cde2e34SJason Evans * Check for recursion, if we already have this 4060cde2e34SJason Evans * lock we just bump the recursion count. 4070cde2e34SJason Evans */ 4080cde2e34SJason Evans if (mpp->mtx_lock == (uintptr_t)CURTHD) { 4090cde2e34SJason Evans mpp->mtx_recurse++; 4100cde2e34SJason Evans goto done; 4110cde2e34SJason Evans } 4120cde2e34SJason Evans } 4130cde2e34SJason Evans 4140cde2e34SJason Evans if (((type) & MTX_TOPHALF) == 0) { 4150cde2e34SJason Evans /* 4160cde2e34SJason Evans * If an interrupt thread uses this we must block 4170cde2e34SJason Evans * interrupts here. 4180cde2e34SJason Evans */ 4190cde2e34SJason Evans if ((type) & MTX_FIRST) { 4200cde2e34SJason Evans ASS_IEN; 4210cde2e34SJason Evans disable_intr(); 4220cde2e34SJason Evans _getlock_norecurse(mpp, CURTHD, 4230cde2e34SJason Evans (type) & MTX_HARDOPTS); 4240cde2e34SJason Evans } else { 4250cde2e34SJason Evans _getlock_spin_block(mpp, CURTHD, 4260cde2e34SJason Evans (type) & MTX_HARDOPTS); 4270cde2e34SJason Evans } 4280cde2e34SJason Evans } else 4290cde2e34SJason Evans _getlock_norecurse(mpp, CURTHD, (type) & MTX_HARDOPTS); 4300cde2e34SJason Evans } else { 4310cde2e34SJason Evans /* Sleep locks */ 4320cde2e34SJason Evans if ((type) & MTX_RLIKELY) 4330cde2e34SJason Evans _getlock_sleep(mpp, CURTHD, (type) & MTX_HARDOPTS); 4340cde2e34SJason Evans else 4350cde2e34SJason Evans _getlock_norecurse(mpp, CURTHD, (type) & MTX_HARDOPTS); 4360cde2e34SJason Evans } 4370cde2e34SJason Evans done: 4380cde2e34SJason Evans WITNESS_ENTER(mpp, type, file, line); 4390cde2e34SJason Evans if (((type) & MTX_QUIET) == 0) 4400cde2e34SJason Evans CTR5(KTR_LOCK, STR_mtx_enter_fmt, 4410cde2e34SJason Evans mpp->mtx_description, mpp, mpp->mtx_recurse, file, line); 4420cde2e34SJason Evans 4430cde2e34SJason Evans } 4440cde2e34SJason Evans 4450cde2e34SJason Evans /* 4460cde2e34SJason Evans * Attempt to get MTX_DEF lock, return non-zero if lock acquired. 4470cde2e34SJason Evans * 4480cde2e34SJason Evans * XXX DOES NOT HANDLE RECURSION 4490cde2e34SJason Evans */ 4500cde2e34SJason Evans int 4510cde2e34SJason Evans _mtx_try_enter(struct mtx *mtxp, int type, const char *file, int line) 4520cde2e34SJason Evans { 4530cde2e34SJason Evans struct mtx *const mpp = mtxp; 4540cde2e34SJason Evans int rval; 4550cde2e34SJason Evans 4560cde2e34SJason Evans rval = _obtain_lock(mpp, CURTHD); 4570cde2e34SJason Evans #ifdef WITNESS 4580cde2e34SJason Evans if (rval && mpp->mtx_witness != NULL) { 4590cde2e34SJason Evans MPASS(mpp->mtx_recurse == 0); 4600cde2e34SJason Evans witness_try_enter(mpp, type, file, line); 4610cde2e34SJason Evans } 4620cde2e34SJason Evans #endif /* WITNESS */ 4630cde2e34SJason Evans if (((type) & MTX_QUIET) == 0) 4640cde2e34SJason Evans CTR5(KTR_LOCK, STR_mtx_try_enter_fmt, 4650cde2e34SJason Evans mpp->mtx_description, mpp, rval, file, line); 4660cde2e34SJason Evans 4670cde2e34SJason Evans return rval; 4680cde2e34SJason Evans } 4690cde2e34SJason Evans 4700cde2e34SJason Evans /* 4710cde2e34SJason Evans * Release lock m. 4720cde2e34SJason Evans */ 4730cde2e34SJason Evans void 4740cde2e34SJason Evans _mtx_exit(struct mtx *mtxp, int type, const char *file, int line) 4750cde2e34SJason Evans { 4760cde2e34SJason Evans struct mtx *const mpp = mtxp; 4770cde2e34SJason Evans 4780cde2e34SJason Evans MPASS4(mtx_owned(mpp), STR_mtx_owned, file, line); 4790cde2e34SJason Evans WITNESS_EXIT(mpp, type, file, line); 4800cde2e34SJason Evans if (((type) & MTX_QUIET) == 0) 4810cde2e34SJason Evans CTR5(KTR_LOCK, STR_mtx_exit_fmt, 4820cde2e34SJason Evans mpp->mtx_description, mpp, mpp->mtx_recurse, file, line); 4830cde2e34SJason Evans if ((type) & MTX_SPIN) { 4840cde2e34SJason Evans if ((type) & MTX_NORECURSE) { 4850cde2e34SJason Evans int mtx_intr = mpp->mtx_saveintr; 4860cde2e34SJason Evans 4870cde2e34SJason Evans MPASS4(mpp->mtx_recurse == 0, STR_mtx_recurse, 4880cde2e34SJason Evans file, line); 4890cde2e34SJason Evans _release_lock_quick(mpp); 4900cde2e34SJason Evans if (((type) & MTX_TOPHALF) == 0) { 4910cde2e34SJason Evans if ((type) & MTX_FIRST) { 4920cde2e34SJason Evans ASS_IDIS; 4930cde2e34SJason Evans enable_intr(); 4940cde2e34SJason Evans } else 4950cde2e34SJason Evans restore_intr(mtx_intr); 4960cde2e34SJason Evans } 4970cde2e34SJason Evans } else { 4980cde2e34SJason Evans if (((type & MTX_TOPHALF) == 0) && 4990cde2e34SJason Evans (type & MTX_FIRST)) { 5000cde2e34SJason Evans ASS_IDIS; 5010cde2e34SJason Evans ASS_SIEN(mpp); 5020cde2e34SJason Evans } 5030cde2e34SJason Evans _exitlock_spin(mpp); 5040cde2e34SJason Evans } 5050cde2e34SJason Evans } else { 5060cde2e34SJason Evans /* Handle sleep locks */ 5070cde2e34SJason Evans if ((type) & MTX_RLIKELY) 5080cde2e34SJason Evans _exitlock(mpp, CURTHD, (type) & MTX_HARDOPTS); 5090cde2e34SJason Evans else { 5100cde2e34SJason Evans _exitlock_norecurse(mpp, CURTHD, 5110cde2e34SJason Evans (type) & MTX_HARDOPTS); 5120cde2e34SJason Evans } 5130cde2e34SJason Evans } 5140cde2e34SJason Evans } 5150cde2e34SJason Evans 51636412d79SJohn Baldwin void 51736412d79SJohn Baldwin mtx_enter_hard(struct mtx *m, int type, int saveintr) 51836412d79SJohn Baldwin { 51936412d79SJohn Baldwin struct proc *p = CURPROC; 52036412d79SJohn Baldwin 52136412d79SJohn Baldwin KASSERT(p != NULL, ("curproc is NULL in mutex")); 52236412d79SJohn Baldwin 52336412d79SJohn Baldwin switch (type) { 52436412d79SJohn Baldwin case MTX_DEF: 52536412d79SJohn Baldwin if ((m->mtx_lock & MTX_FLAGMASK) == (uintptr_t)p) { 52636412d79SJohn Baldwin m->mtx_recurse++; 52708812b39SBosko Milekic atomic_set_ptr(&m->mtx_lock, MTX_RECURSED); 528562e4ffeSJohn Baldwin if ((type & MTX_QUIET) == 0) 52936412d79SJohn Baldwin CTR1(KTR_LOCK, "mtx_enter: 0x%p recurse", m); 53036412d79SJohn Baldwin return; 53136412d79SJohn Baldwin } 532562e4ffeSJohn Baldwin if ((type & MTX_QUIET) == 0) 533562e4ffeSJohn Baldwin CTR3(KTR_LOCK, 534562e4ffeSJohn Baldwin "mtx_enter: 0x%p contested (lock=%p) [0x%p]", 53531271627SJohn Baldwin m, (void *)m->mtx_lock, (void *)RETIP(m)); 5361bd0eefbSJohn Baldwin 5371bd0eefbSJohn Baldwin /* 5381bd0eefbSJohn Baldwin * Save our priority. Even though p_nativepri is protected 5391bd0eefbSJohn Baldwin * by sched_lock, we don't obtain it here as it can be 5401bd0eefbSJohn Baldwin * expensive. Since this is the only place p_nativepri is 5411bd0eefbSJohn Baldwin * set, and since two CPUs will not be executing the same 5421bd0eefbSJohn Baldwin * process concurrently, we know that no other CPU is going 5431bd0eefbSJohn Baldwin * to be messing with this. Also, p_nativepri is only read 5441bd0eefbSJohn Baldwin * when we are blocked on a mutex, so that can't be happening 5451bd0eefbSJohn Baldwin * right now either. 5461bd0eefbSJohn Baldwin */ 5471bd0eefbSJohn Baldwin p->p_nativepri = p->p_priority; 54836412d79SJohn Baldwin while (!_obtain_lock(m, p)) { 549f5271ebcSJohn Baldwin uintptr_t v; 55036412d79SJohn Baldwin struct proc *p1; 55136412d79SJohn Baldwin 55236412d79SJohn Baldwin mtx_enter(&sched_lock, MTX_SPIN | MTX_RLIKELY); 55336412d79SJohn Baldwin /* 55436412d79SJohn Baldwin * check if the lock has been released while 55536412d79SJohn Baldwin * waiting for the schedlock. 55636412d79SJohn Baldwin */ 55736412d79SJohn Baldwin if ((v = m->mtx_lock) == MTX_UNOWNED) { 55836412d79SJohn Baldwin mtx_exit(&sched_lock, MTX_SPIN); 55936412d79SJohn Baldwin continue; 56036412d79SJohn Baldwin } 56136412d79SJohn Baldwin /* 56236412d79SJohn Baldwin * The mutex was marked contested on release. This 56336412d79SJohn Baldwin * means that there are processes blocked on it. 56436412d79SJohn Baldwin */ 56536412d79SJohn Baldwin if (v == MTX_CONTESTED) { 56636412d79SJohn Baldwin p1 = TAILQ_FIRST(&m->mtx_blocked); 56736412d79SJohn Baldwin KASSERT(p1 != NULL, ("contested mutex has no contesters")); 56836412d79SJohn Baldwin KASSERT(p != NULL, ("curproc is NULL for contested mutex")); 56936412d79SJohn Baldwin m->mtx_lock = (uintptr_t)p | MTX_CONTESTED; 57036412d79SJohn Baldwin if (p1->p_priority < p->p_priority) { 57136412d79SJohn Baldwin SET_PRIO(p, p1->p_priority); 57236412d79SJohn Baldwin } 57336412d79SJohn Baldwin mtx_exit(&sched_lock, MTX_SPIN); 57436412d79SJohn Baldwin return; 57536412d79SJohn Baldwin } 57636412d79SJohn Baldwin /* 57736412d79SJohn Baldwin * If the mutex isn't already contested and 57836412d79SJohn Baldwin * a failure occurs setting the contested bit the 57936412d79SJohn Baldwin * mutex was either release or the 58036412d79SJohn Baldwin * state of the RECURSION bit changed. 58136412d79SJohn Baldwin */ 58236412d79SJohn Baldwin if ((v & MTX_CONTESTED) == 0 && 58336412d79SJohn Baldwin !atomic_cmpset_ptr(&m->mtx_lock, (void *)v, 58436412d79SJohn Baldwin (void *)(v | MTX_CONTESTED))) { 58536412d79SJohn Baldwin mtx_exit(&sched_lock, MTX_SPIN); 58636412d79SJohn Baldwin continue; 58736412d79SJohn Baldwin } 58836412d79SJohn Baldwin 58936412d79SJohn Baldwin /* We definitely have to sleep for this lock */ 59036412d79SJohn Baldwin mtx_assert(m, MA_NOTOWNED); 59136412d79SJohn Baldwin 59236412d79SJohn Baldwin #ifdef notyet 59336412d79SJohn Baldwin /* 59436412d79SJohn Baldwin * If we're borrowing an interrupted thread's VM 59536412d79SJohn Baldwin * context must clean up before going to sleep. 59636412d79SJohn Baldwin */ 59736412d79SJohn Baldwin if (p->p_flag & (P_ITHD | P_SITHD)) { 59836412d79SJohn Baldwin ithd_t *it = (ithd_t *)p; 59936412d79SJohn Baldwin 60036412d79SJohn Baldwin if (it->it_interrupted) { 601562e4ffeSJohn Baldwin if ((type & MTX_QUIET) == 0) 60236412d79SJohn Baldwin CTR2(KTR_LOCK, 60336412d79SJohn Baldwin "mtx_enter: 0x%x interrupted 0x%x", 60436412d79SJohn Baldwin it, it->it_interrupted); 60536412d79SJohn Baldwin intr_thd_fixup(it); 60636412d79SJohn Baldwin } 60736412d79SJohn Baldwin } 60836412d79SJohn Baldwin #endif 60936412d79SJohn Baldwin 61036412d79SJohn Baldwin /* Put us on the list of procs blocked on this mutex */ 61136412d79SJohn Baldwin if (TAILQ_EMPTY(&m->mtx_blocked)) { 61236412d79SJohn Baldwin p1 = (struct proc *)(m->mtx_lock & 61336412d79SJohn Baldwin MTX_FLAGMASK); 61436412d79SJohn Baldwin LIST_INSERT_HEAD(&p1->p_contested, m, 61536412d79SJohn Baldwin mtx_contested); 61636412d79SJohn Baldwin TAILQ_INSERT_TAIL(&m->mtx_blocked, p, p_procq); 61736412d79SJohn Baldwin } else { 61836412d79SJohn Baldwin TAILQ_FOREACH(p1, &m->mtx_blocked, p_procq) 61936412d79SJohn Baldwin if (p1->p_priority > p->p_priority) 62036412d79SJohn Baldwin break; 62136412d79SJohn Baldwin if (p1) 62236412d79SJohn Baldwin TAILQ_INSERT_BEFORE(p1, p, p_procq); 62336412d79SJohn Baldwin else 62436412d79SJohn Baldwin TAILQ_INSERT_TAIL(&m->mtx_blocked, p, 62536412d79SJohn Baldwin p_procq); 62636412d79SJohn Baldwin } 62736412d79SJohn Baldwin 62836412d79SJohn Baldwin p->p_blocked = m; /* Who we're blocked on */ 62986327ad8SJohn Baldwin p->p_mtxname = m->mtx_description; 63036412d79SJohn Baldwin p->p_stat = SMTX; 63136412d79SJohn Baldwin #if 0 63236412d79SJohn Baldwin propagate_priority(p); 63336412d79SJohn Baldwin #endif 634562e4ffeSJohn Baldwin if ((type & MTX_QUIET) == 0) 635562e4ffeSJohn Baldwin CTR3(KTR_LOCK, 636562e4ffeSJohn Baldwin "mtx_enter: p 0x%p blocked on [0x%p] %s", 63736412d79SJohn Baldwin p, m, m->mtx_description); 63820cdcc5bSJohn Baldwin mi_switch(); 639562e4ffeSJohn Baldwin if ((type & MTX_QUIET) == 0) 64036412d79SJohn Baldwin CTR3(KTR_LOCK, 64136412d79SJohn Baldwin "mtx_enter: p 0x%p free from blocked on [0x%p] %s", 64236412d79SJohn Baldwin p, m, m->mtx_description); 64336412d79SJohn Baldwin mtx_exit(&sched_lock, MTX_SPIN); 64436412d79SJohn Baldwin } 64536412d79SJohn Baldwin return; 64636412d79SJohn Baldwin case MTX_SPIN: 64736412d79SJohn Baldwin case MTX_SPIN | MTX_FIRST: 64836412d79SJohn Baldwin case MTX_SPIN | MTX_TOPHALF: 64936412d79SJohn Baldwin { 65036412d79SJohn Baldwin int i = 0; 65136412d79SJohn Baldwin 65236412d79SJohn Baldwin if (m->mtx_lock == (uintptr_t)p) { 65336412d79SJohn Baldwin m->mtx_recurse++; 65436412d79SJohn Baldwin return; 65536412d79SJohn Baldwin } 656562e4ffeSJohn Baldwin if ((type & MTX_QUIET) == 0) 65736412d79SJohn Baldwin CTR1(KTR_LOCK, "mtx_enter: %p spinning", m); 65836412d79SJohn Baldwin for (;;) { 65936412d79SJohn Baldwin if (_obtain_lock(m, p)) 66036412d79SJohn Baldwin break; 66136412d79SJohn Baldwin while (m->mtx_lock != MTX_UNOWNED) { 66236412d79SJohn Baldwin if (i++ < 1000000) 66336412d79SJohn Baldwin continue; 66436412d79SJohn Baldwin if (i++ < 6000000) 66536412d79SJohn Baldwin DELAY (1); 66636412d79SJohn Baldwin #ifdef DDB 66736412d79SJohn Baldwin else if (!db_active) 66836412d79SJohn Baldwin #else 66936412d79SJohn Baldwin else 67036412d79SJohn Baldwin #endif 67136412d79SJohn Baldwin panic( 67236412d79SJohn Baldwin "spin lock %s held by 0x%p for > 5 seconds", 67336412d79SJohn Baldwin m->mtx_description, 67436412d79SJohn Baldwin (void *)m->mtx_lock); 67536412d79SJohn Baldwin } 67636412d79SJohn Baldwin } 67736412d79SJohn Baldwin 67836412d79SJohn Baldwin #ifdef MUTEX_DEBUG 67936412d79SJohn Baldwin if (type != MTX_SPIN) 68036412d79SJohn Baldwin m->mtx_saveintr = 0xbeefface; 68136412d79SJohn Baldwin else 68236412d79SJohn Baldwin #endif 68336412d79SJohn Baldwin m->mtx_saveintr = saveintr; 684562e4ffeSJohn Baldwin if ((type & MTX_QUIET) == 0) 68536412d79SJohn Baldwin CTR1(KTR_LOCK, "mtx_enter: 0x%p spin done", m); 68636412d79SJohn Baldwin return; 68736412d79SJohn Baldwin } 68836412d79SJohn Baldwin } 68936412d79SJohn Baldwin } 69036412d79SJohn Baldwin 69136412d79SJohn Baldwin void 69236412d79SJohn Baldwin mtx_exit_hard(struct mtx *m, int type) 69336412d79SJohn Baldwin { 69436412d79SJohn Baldwin struct proc *p, *p1; 69536412d79SJohn Baldwin struct mtx *m1; 69636412d79SJohn Baldwin int pri; 69736412d79SJohn Baldwin 69836412d79SJohn Baldwin p = CURPROC; 69936412d79SJohn Baldwin switch (type) { 70036412d79SJohn Baldwin case MTX_DEF: 70136412d79SJohn Baldwin case MTX_DEF | MTX_NOSWITCH: 70208812b39SBosko Milekic if (mtx_recursed(m)) { 70336412d79SJohn Baldwin if (--(m->mtx_recurse) == 0) 70408812b39SBosko Milekic atomic_clear_ptr(&m->mtx_lock, MTX_RECURSED); 705562e4ffeSJohn Baldwin if ((type & MTX_QUIET) == 0) 70636412d79SJohn Baldwin CTR1(KTR_LOCK, "mtx_exit: 0x%p unrecurse", m); 70736412d79SJohn Baldwin return; 70836412d79SJohn Baldwin } 70936412d79SJohn Baldwin mtx_enter(&sched_lock, MTX_SPIN); 710562e4ffeSJohn Baldwin if ((type & MTX_QUIET) == 0) 71136412d79SJohn Baldwin CTR1(KTR_LOCK, "mtx_exit: 0x%p contested", m); 71236412d79SJohn Baldwin p1 = TAILQ_FIRST(&m->mtx_blocked); 71336412d79SJohn Baldwin MPASS(p->p_magic == P_MAGIC); 71436412d79SJohn Baldwin MPASS(p1->p_magic == P_MAGIC); 71536412d79SJohn Baldwin TAILQ_REMOVE(&m->mtx_blocked, p1, p_procq); 71636412d79SJohn Baldwin if (TAILQ_EMPTY(&m->mtx_blocked)) { 71736412d79SJohn Baldwin LIST_REMOVE(m, mtx_contested); 71836412d79SJohn Baldwin _release_lock_quick(m); 719562e4ffeSJohn Baldwin if ((type & MTX_QUIET) == 0) 72036412d79SJohn Baldwin CTR1(KTR_LOCK, "mtx_exit: 0x%p not held", m); 72136412d79SJohn Baldwin } else 722f404050eSJohn Baldwin atomic_store_rel_ptr(&m->mtx_lock, 723f404050eSJohn Baldwin (void *)MTX_CONTESTED); 72436412d79SJohn Baldwin pri = MAXPRI; 72536412d79SJohn Baldwin LIST_FOREACH(m1, &p->p_contested, mtx_contested) { 72636412d79SJohn Baldwin int cp = TAILQ_FIRST(&m1->mtx_blocked)->p_priority; 72736412d79SJohn Baldwin if (cp < pri) 72836412d79SJohn Baldwin pri = cp; 72936412d79SJohn Baldwin } 73036412d79SJohn Baldwin if (pri > p->p_nativepri) 73136412d79SJohn Baldwin pri = p->p_nativepri; 73236412d79SJohn Baldwin SET_PRIO(p, pri); 733562e4ffeSJohn Baldwin if ((type & MTX_QUIET) == 0) 734562e4ffeSJohn Baldwin CTR2(KTR_LOCK, 735562e4ffeSJohn Baldwin "mtx_exit: 0x%p contested setrunqueue 0x%p", m, p1); 73636412d79SJohn Baldwin p1->p_blocked = NULL; 73786327ad8SJohn Baldwin p1->p_mtxname = NULL; 73836412d79SJohn Baldwin p1->p_stat = SRUN; 73936412d79SJohn Baldwin setrunqueue(p1); 74036412d79SJohn Baldwin if ((type & MTX_NOSWITCH) == 0 && p1->p_priority < pri) { 74136412d79SJohn Baldwin #ifdef notyet 74236412d79SJohn Baldwin if (p->p_flag & (P_ITHD | P_SITHD)) { 74336412d79SJohn Baldwin ithd_t *it = (ithd_t *)p; 74436412d79SJohn Baldwin 74536412d79SJohn Baldwin if (it->it_interrupted) { 746562e4ffeSJohn Baldwin if ((type & MTX_QUIET) == 0) 74736412d79SJohn Baldwin CTR2(KTR_LOCK, 74836412d79SJohn Baldwin "mtx_exit: 0x%x interruped 0x%x", 74936412d79SJohn Baldwin it, it->it_interrupted); 75036412d79SJohn Baldwin intr_thd_fixup(it); 75136412d79SJohn Baldwin } 75236412d79SJohn Baldwin } 75336412d79SJohn Baldwin #endif 75436412d79SJohn Baldwin setrunqueue(p); 755562e4ffeSJohn Baldwin if ((type & MTX_QUIET) == 0) 756562e4ffeSJohn Baldwin CTR2(KTR_LOCK, 757562e4ffeSJohn Baldwin "mtx_exit: 0x%p switching out lock=0x%p", 75831271627SJohn Baldwin m, (void *)m->mtx_lock); 75936412d79SJohn Baldwin mi_switch(); 760562e4ffeSJohn Baldwin if ((type & MTX_QUIET) == 0) 761562e4ffeSJohn Baldwin CTR2(KTR_LOCK, 762562e4ffeSJohn Baldwin "mtx_exit: 0x%p resuming lock=0x%p", 76331271627SJohn Baldwin m, (void *)m->mtx_lock); 76436412d79SJohn Baldwin } 76536412d79SJohn Baldwin mtx_exit(&sched_lock, MTX_SPIN); 76636412d79SJohn Baldwin break; 76736412d79SJohn Baldwin case MTX_SPIN: 76836412d79SJohn Baldwin case MTX_SPIN | MTX_FIRST: 76908812b39SBosko Milekic if (mtx_recursed(m)) { 77036412d79SJohn Baldwin m->mtx_recurse--; 77136412d79SJohn Baldwin return; 77236412d79SJohn Baldwin } 77336412d79SJohn Baldwin MPASS(mtx_owned(m)); 77436412d79SJohn Baldwin _release_lock_quick(m); 77536412d79SJohn Baldwin if (type & MTX_FIRST) 77636412d79SJohn Baldwin enable_intr(); /* XXX is this kosher? */ 77736412d79SJohn Baldwin else { 77836412d79SJohn Baldwin MPASS(m->mtx_saveintr != 0xbeefface); 77936412d79SJohn Baldwin restore_intr(m->mtx_saveintr); 78036412d79SJohn Baldwin } 78136412d79SJohn Baldwin break; 78236412d79SJohn Baldwin case MTX_SPIN | MTX_TOPHALF: 78308812b39SBosko Milekic if (mtx_recursed(m)) { 78436412d79SJohn Baldwin m->mtx_recurse--; 78536412d79SJohn Baldwin return; 78636412d79SJohn Baldwin } 78736412d79SJohn Baldwin MPASS(mtx_owned(m)); 78836412d79SJohn Baldwin _release_lock_quick(m); 78936412d79SJohn Baldwin break; 79036412d79SJohn Baldwin default: 79136412d79SJohn Baldwin panic("mtx_exit_hard: unsupported type 0x%x\n", type); 79236412d79SJohn Baldwin } 79336412d79SJohn Baldwin } 79436412d79SJohn Baldwin 7950cde2e34SJason Evans #ifdef INVARIANTS 7960cde2e34SJason Evans void 79756771ca7SJason Evans _mtx_assert(struct mtx *m, int what, const char *file, int line) 7980cde2e34SJason Evans { 7990cde2e34SJason Evans switch ((what)) { 8000cde2e34SJason Evans case MA_OWNED: 8010cde2e34SJason Evans case MA_OWNED | MA_RECURSED: 8020cde2e34SJason Evans case MA_OWNED | MA_NOTRECURSED: 8030cde2e34SJason Evans if (!mtx_owned((m))) 8040cde2e34SJason Evans panic("mutex %s not owned at %s:%d", 80556771ca7SJason Evans (m)->mtx_description, file, line); 8060cde2e34SJason Evans if (mtx_recursed((m))) { 8070cde2e34SJason Evans if (((what) & MA_NOTRECURSED) != 0) 8080cde2e34SJason Evans panic("mutex %s recursed at %s:%d", 80956771ca7SJason Evans (m)->mtx_description, file, line); 8100cde2e34SJason Evans } else if (((what) & MA_RECURSED) != 0) { 8110cde2e34SJason Evans panic("mutex %s unrecursed at %s:%d", 81256771ca7SJason Evans (m)->mtx_description, file, line); 8130cde2e34SJason Evans } 8140cde2e34SJason Evans break; 8150cde2e34SJason Evans case MA_NOTOWNED: 8160cde2e34SJason Evans if (mtx_owned((m))) 8170cde2e34SJason Evans panic("mutex %s owned at %s:%d", 81856771ca7SJason Evans (m)->mtx_description, file, line); 8190cde2e34SJason Evans break; 8200cde2e34SJason Evans default: 82156771ca7SJason Evans panic("unknown mtx_assert at %s:%d", file, line); 8220cde2e34SJason Evans } 8230cde2e34SJason Evans } 8240cde2e34SJason Evans #endif 8250cde2e34SJason Evans 82636412d79SJohn Baldwin #define MV_DESTROY 0 /* validate before destory */ 82736412d79SJohn Baldwin #define MV_INIT 1 /* validate before init */ 82836412d79SJohn Baldwin 82936412d79SJohn Baldwin #ifdef MUTEX_DEBUG 83036412d79SJohn Baldwin 83136412d79SJohn Baldwin int mtx_validate __P((struct mtx *, int)); 83236412d79SJohn Baldwin 83336412d79SJohn Baldwin int 83436412d79SJohn Baldwin mtx_validate(struct mtx *m, int when) 83536412d79SJohn Baldwin { 83636412d79SJohn Baldwin struct mtx *mp; 83736412d79SJohn Baldwin int i; 83836412d79SJohn Baldwin int retval = 0; 83936412d79SJohn Baldwin 840d1c1b841SJason Evans #ifdef WITNESS 841d1c1b841SJason Evans if (witness_cold) 842d1c1b841SJason Evans return 0; 843d1c1b841SJason Evans #endif 84436412d79SJohn Baldwin if (m == &all_mtx || cold) 84536412d79SJohn Baldwin return 0; 84636412d79SJohn Baldwin 84736412d79SJohn Baldwin mtx_enter(&all_mtx, MTX_DEF); 84836412d79SJohn Baldwin /* 84936412d79SJohn Baldwin * XXX - When kernacc() is fixed on the alpha to handle K0_SEG memory properly 85036412d79SJohn Baldwin * we can re-enable the kernacc() checks. 85136412d79SJohn Baldwin */ 85236412d79SJohn Baldwin #ifndef __alpha__ 85336412d79SJohn Baldwin MPASS(kernacc((caddr_t)all_mtx.mtx_next, sizeof(uintptr_t), 85436412d79SJohn Baldwin VM_PROT_READ) == 1); 85536412d79SJohn Baldwin #endif 85636412d79SJohn Baldwin MPASS(all_mtx.mtx_next->mtx_prev == &all_mtx); 85736412d79SJohn Baldwin for (i = 0, mp = all_mtx.mtx_next; mp != &all_mtx; mp = mp->mtx_next) { 85836412d79SJohn Baldwin #ifndef __alpha__ 85936412d79SJohn Baldwin if (kernacc((caddr_t)mp->mtx_next, sizeof(uintptr_t), 86036412d79SJohn Baldwin VM_PROT_READ) != 1) { 86136412d79SJohn Baldwin panic("mtx_validate: mp=%p mp->mtx_next=%p", 86236412d79SJohn Baldwin mp, mp->mtx_next); 86336412d79SJohn Baldwin } 86436412d79SJohn Baldwin #endif 86536412d79SJohn Baldwin i++; 86636412d79SJohn Baldwin if (i > mtx_cur_cnt) { 86736412d79SJohn Baldwin panic("mtx_validate: too many in chain, known=%d\n", 86836412d79SJohn Baldwin mtx_cur_cnt); 86936412d79SJohn Baldwin } 87036412d79SJohn Baldwin } 87136412d79SJohn Baldwin MPASS(i == mtx_cur_cnt); 87236412d79SJohn Baldwin switch (when) { 87336412d79SJohn Baldwin case MV_DESTROY: 87436412d79SJohn Baldwin for (mp = all_mtx.mtx_next; mp != &all_mtx; mp = mp->mtx_next) 87536412d79SJohn Baldwin if (mp == m) 87636412d79SJohn Baldwin break; 87736412d79SJohn Baldwin MPASS(mp == m); 87836412d79SJohn Baldwin break; 87936412d79SJohn Baldwin case MV_INIT: 88036412d79SJohn Baldwin for (mp = all_mtx.mtx_next; mp != &all_mtx; mp = mp->mtx_next) 88136412d79SJohn Baldwin if (mp == m) { 88236412d79SJohn Baldwin /* 88336412d79SJohn Baldwin * Not good. This mutex already exists. 88436412d79SJohn Baldwin */ 88536412d79SJohn Baldwin printf("re-initing existing mutex %s\n", 88636412d79SJohn Baldwin m->mtx_description); 88736412d79SJohn Baldwin MPASS(m->mtx_lock == MTX_UNOWNED); 88836412d79SJohn Baldwin retval = 1; 88936412d79SJohn Baldwin } 89036412d79SJohn Baldwin } 89136412d79SJohn Baldwin mtx_exit(&all_mtx, MTX_DEF); 89236412d79SJohn Baldwin return (retval); 89336412d79SJohn Baldwin } 89436412d79SJohn Baldwin #endif 89536412d79SJohn Baldwin 89636412d79SJohn Baldwin void 89736412d79SJohn Baldwin mtx_init(struct mtx *m, const char *t, int flag) 89836412d79SJohn Baldwin { 899562e4ffeSJohn Baldwin if ((flag & MTX_QUIET) == 0) 90036412d79SJohn Baldwin CTR2(KTR_LOCK, "mtx_init 0x%p (%s)", m, t); 90136412d79SJohn Baldwin #ifdef MUTEX_DEBUG 90236412d79SJohn Baldwin if (mtx_validate(m, MV_INIT)) /* diagnostic and error correction */ 90336412d79SJohn Baldwin return; 9046936206eSJohn Baldwin #endif 90536412d79SJohn Baldwin 90636412d79SJohn Baldwin bzero((void *)m, sizeof *m); 90736412d79SJohn Baldwin TAILQ_INIT(&m->mtx_blocked); 9086936206eSJohn Baldwin #ifdef WITNESS 909d1c1b841SJason Evans if (!witness_cold) { 910d1c1b841SJason Evans /* XXX - should not use DEVBUF */ 911d1c1b841SJason Evans m->mtx_union.mtxu_debug = malloc(sizeof(struct mtx_debug), 912d1c1b841SJason Evans M_DEVBUF, M_NOWAIT | M_ZERO); 913d1c1b841SJason Evans MPASS(m->mtx_union.mtxu_debug != NULL); 914d1c1b841SJason Evans 91536412d79SJohn Baldwin m->mtx_description = t; 916d1c1b841SJason Evans } else { 917d1c1b841SJason Evans /* 918d1c1b841SJason Evans * Save a pointer to the description so that witness_fixup() 919d1c1b841SJason Evans * can properly initialize this mutex later on. 920d1c1b841SJason Evans */ 921d1c1b841SJason Evans m->mtx_union.mtxu_description = t; 922d1c1b841SJason Evans } 923d1c1b841SJason Evans #else 924d1c1b841SJason Evans m->mtx_description = t; 925d1c1b841SJason Evans #endif 926d1c1b841SJason Evans 927d1c1b841SJason Evans m->mtx_flags = flag; 92836412d79SJohn Baldwin m->mtx_lock = MTX_UNOWNED; 92936412d79SJohn Baldwin /* Put on all mutex queue */ 93036412d79SJohn Baldwin mtx_enter(&all_mtx, MTX_DEF); 93136412d79SJohn Baldwin m->mtx_next = &all_mtx; 93236412d79SJohn Baldwin m->mtx_prev = all_mtx.mtx_prev; 93336412d79SJohn Baldwin m->mtx_prev->mtx_next = m; 93436412d79SJohn Baldwin all_mtx.mtx_prev = m; 93536412d79SJohn Baldwin if (++mtx_cur_cnt > mtx_max_cnt) 93636412d79SJohn Baldwin mtx_max_cnt = mtx_cur_cnt; 93736412d79SJohn Baldwin mtx_exit(&all_mtx, MTX_DEF); 938d1c1b841SJason Evans #ifdef WITNESS 939d1c1b841SJason Evans if (!witness_cold) 94036412d79SJohn Baldwin witness_init(m, flag); 941d1c1b841SJason Evans #endif 94236412d79SJohn Baldwin } 94336412d79SJohn Baldwin 94436412d79SJohn Baldwin void 94536412d79SJohn Baldwin mtx_destroy(struct mtx *m) 94636412d79SJohn Baldwin { 94736412d79SJohn Baldwin 948d1c1b841SJason Evans #ifdef WITNESS 949d1c1b841SJason Evans KASSERT(!witness_cold, ("%s: Cannot destroy while still cold\n", 950d1c1b841SJason Evans __FUNCTION__)); 951d1c1b841SJason Evans #endif 95236412d79SJohn Baldwin CTR2(KTR_LOCK, "mtx_destroy 0x%p (%s)", m, m->mtx_description); 95336412d79SJohn Baldwin #ifdef MUTEX_DEBUG 95436412d79SJohn Baldwin if (m->mtx_next == NULL) 95536412d79SJohn Baldwin panic("mtx_destroy: %p (%s) already destroyed", 95636412d79SJohn Baldwin m, m->mtx_description); 95736412d79SJohn Baldwin 95836412d79SJohn Baldwin if (!mtx_owned(m)) { 95936412d79SJohn Baldwin MPASS(m->mtx_lock == MTX_UNOWNED); 96036412d79SJohn Baldwin } else { 96108812b39SBosko Milekic MPASS((m->mtx_lock & (MTX_RECURSED|MTX_CONTESTED)) == 0); 96236412d79SJohn Baldwin } 96336412d79SJohn Baldwin mtx_validate(m, MV_DESTROY); /* diagnostic */ 96436412d79SJohn Baldwin #endif 96536412d79SJohn Baldwin 96636412d79SJohn Baldwin #ifdef WITNESS 96736412d79SJohn Baldwin if (m->mtx_witness) 96836412d79SJohn Baldwin witness_destroy(m); 96936412d79SJohn Baldwin #endif /* WITNESS */ 97036412d79SJohn Baldwin 97136412d79SJohn Baldwin /* Remove from the all mutex queue */ 97236412d79SJohn Baldwin mtx_enter(&all_mtx, MTX_DEF); 97336412d79SJohn Baldwin m->mtx_next->mtx_prev = m->mtx_prev; 97436412d79SJohn Baldwin m->mtx_prev->mtx_next = m->mtx_next; 97536412d79SJohn Baldwin #ifdef MUTEX_DEBUG 97636412d79SJohn Baldwin m->mtx_next = m->mtx_prev = NULL; 9776936206eSJohn Baldwin #endif 9786936206eSJohn Baldwin #ifdef WITNESS 979d1c1b841SJason Evans free(m->mtx_union.mtxu_debug, M_DEVBUF); 980d1c1b841SJason Evans m->mtx_union.mtxu_debug = NULL; 98136412d79SJohn Baldwin #endif 98236412d79SJohn Baldwin mtx_cur_cnt--; 98336412d79SJohn Baldwin mtx_exit(&all_mtx, MTX_DEF); 98436412d79SJohn Baldwin } 9850384fff8SJason Evans 986d1c1b841SJason Evans static void 987d1c1b841SJason Evans witness_fixup(void *dummy __unused) 988d1c1b841SJason Evans { 989d1c1b841SJason Evans #ifdef WITNESS 990d1c1b841SJason Evans struct mtx *mp; 991d1c1b841SJason Evans const char *description; 992d1c1b841SJason Evans 993d1c1b841SJason Evans /* Iterate through all mutexes and finish up mutex initialization. */ 994d1c1b841SJason Evans for (mp = all_mtx.mtx_next; mp != &all_mtx; mp = mp->mtx_next) { 995d1c1b841SJason Evans description = mp->mtx_union.mtxu_description; 996d1c1b841SJason Evans 997d1c1b841SJason Evans /* XXX - should not use DEVBUF */ 998d1c1b841SJason Evans mp->mtx_union.mtxu_debug = malloc(sizeof(struct mtx_debug), 999d1c1b841SJason Evans M_DEVBUF, M_NOWAIT | M_ZERO); 1000d1c1b841SJason Evans MPASS(mp->mtx_union.mtxu_debug != NULL); 1001d1c1b841SJason Evans 1002d1c1b841SJason Evans mp->mtx_description = description; 1003d1c1b841SJason Evans 1004d1c1b841SJason Evans witness_init(mp, mp->mtx_flags); 1005d1c1b841SJason Evans } 1006d1c1b841SJason Evans 1007d1c1b841SJason Evans /* Mark the witness code as being ready for use. */ 1008d1c1b841SJason Evans atomic_store_rel_int(&witness_cold, 0); 1009d1c1b841SJason Evans #endif 1010d1c1b841SJason Evans } 1011d1c1b841SJason Evans SYSINIT(wtnsfxup, SI_SUB_MUTEX, SI_ORDER_FIRST, witness_fixup, NULL) 1012d1c1b841SJason Evans 10130384fff8SJason Evans /* 10140384fff8SJason Evans * The non-inlined versions of the mtx_*() functions are always built (above), 10156936206eSJohn Baldwin * but the witness code depends on the WITNESS kernel option being specified. 10160384fff8SJason Evans */ 10176936206eSJohn Baldwin #ifdef WITNESS 10180384fff8SJason Evans 10190384fff8SJason Evans #define WITNESS_COUNT 200 10200384fff8SJason Evans #define WITNESS_NCHILDREN 2 10210384fff8SJason Evans 102278f0da03SJohn Baldwin int witness_watch = 1; 10230384fff8SJason Evans 1024606f8eb2SJohn Baldwin struct witness { 10250384fff8SJason Evans struct witness *w_next; 1026b67a3e6eSJohn Baldwin const char *w_description; 102712473b76SJason Evans const char *w_file; 10280384fff8SJason Evans int w_line; 10290384fff8SJason Evans struct witness *w_morechildren; 10300384fff8SJason Evans u_char w_childcnt; 10310384fff8SJason Evans u_char w_Giant_squawked:1; 10320384fff8SJason Evans u_char w_other_squawked:1; 10330384fff8SJason Evans u_char w_same_squawked:1; 103408812b39SBosko Milekic u_char w_sleep:1; /* MTX_DEF type mutex. */ 103508812b39SBosko Milekic u_char w_spin:1; /* MTX_SPIN type mutex. */ 103608812b39SBosko Milekic u_char w_recurse:1; /* MTX_RECURSE mutex option. */ 10370384fff8SJason Evans u_int w_level; 10380384fff8SJason Evans struct witness *w_children[WITNESS_NCHILDREN]; 1039606f8eb2SJohn Baldwin }; 10400384fff8SJason Evans 1041606f8eb2SJohn Baldwin struct witness_blessed { 10420384fff8SJason Evans char *b_lock1; 10430384fff8SJason Evans char *b_lock2; 1044606f8eb2SJohn Baldwin }; 10450384fff8SJason Evans 1046a5a96a19SJohn Baldwin #ifdef DDB 10470384fff8SJason Evans /* 1048a5a96a19SJohn Baldwin * When DDB is enabled and witness_ddb is set to 1, it will cause the system to 10490384fff8SJason Evans * drop into kdebug() when: 10500384fff8SJason Evans * - a lock heirarchy violation occurs 10510384fff8SJason Evans * - locks are held when going to sleep. 10520384fff8SJason Evans */ 1053a5a96a19SJohn Baldwin #ifdef WITNESS_DDB 1054a5a96a19SJohn Baldwin int witness_ddb = 1; 1055a5a96a19SJohn Baldwin #else 1056a5a96a19SJohn Baldwin int witness_ddb = 0; 10570384fff8SJason Evans #endif 1058a5a96a19SJohn Baldwin SYSCTL_INT(_debug, OID_AUTO, witness_ddb, CTLFLAG_RW, &witness_ddb, 0, ""); 1059a5a96a19SJohn Baldwin #endif /* DDB */ 10600384fff8SJason Evans 1061a5a96a19SJohn Baldwin #ifdef WITNESS_SKIPSPIN 1062a5a96a19SJohn Baldwin int witness_skipspin = 1; 1063a5a96a19SJohn Baldwin #else 1064a5a96a19SJohn Baldwin int witness_skipspin = 0; 10650384fff8SJason Evans #endif 1066a5a96a19SJohn Baldwin SYSCTL_INT(_debug, OID_AUTO, witness_skipspin, CTLFLAG_RD, &witness_skipspin, 0, 1067a5a96a19SJohn Baldwin ""); 10680384fff8SJason Evans 1069d1c1b841SJason Evans static struct mtx w_mtx; 1070606f8eb2SJohn Baldwin static struct witness *w_free; 1071606f8eb2SJohn Baldwin static struct witness *w_all; 10720384fff8SJason Evans static int w_inited; 10730384fff8SJason Evans static int witness_dead; /* fatal error, probably no memory */ 10740384fff8SJason Evans 1075606f8eb2SJohn Baldwin static struct witness w_data[WITNESS_COUNT]; 10760384fff8SJason Evans 1077b67a3e6eSJohn Baldwin static struct witness *enroll __P((const char *description, int flag)); 1078606f8eb2SJohn Baldwin static int itismychild __P((struct witness *parent, struct witness *child)); 1079606f8eb2SJohn Baldwin static void removechild __P((struct witness *parent, struct witness *child)); 1080606f8eb2SJohn Baldwin static int isitmychild __P((struct witness *parent, struct witness *child)); 1081606f8eb2SJohn Baldwin static int isitmydescendant __P((struct witness *parent, struct witness *child)); 1082606f8eb2SJohn Baldwin static int dup_ok __P((struct witness *)); 1083606f8eb2SJohn Baldwin static int blessed __P((struct witness *, struct witness *)); 10840384fff8SJason Evans static void witness_displaydescendants 1085606f8eb2SJohn Baldwin __P((void(*)(const char *fmt, ...), struct witness *)); 1086606f8eb2SJohn Baldwin static void witness_leveldescendents __P((struct witness *parent, int level)); 10870384fff8SJason Evans static void witness_levelall __P((void)); 1088606f8eb2SJohn Baldwin static struct witness * witness_get __P((void)); 1089606f8eb2SJohn Baldwin static void witness_free __P((struct witness *m)); 10900384fff8SJason Evans 10910384fff8SJason Evans 10920384fff8SJason Evans static char *ignore_list[] = { 10930384fff8SJason Evans "witness lock", 10940384fff8SJason Evans NULL 10950384fff8SJason Evans }; 10960384fff8SJason Evans 10970384fff8SJason Evans static char *spin_order_list[] = { 1098a5a96a19SJohn Baldwin "sio", 10998f838cb5SJohn Baldwin "sched lock", 110020cdcc5bSJohn Baldwin #ifdef __i386__ 110120cdcc5bSJohn Baldwin "clk", 110220cdcc5bSJohn Baldwin #endif 1103fa2fbc3dSJake Burkholder "callout", 11040384fff8SJason Evans /* 11050384fff8SJason Evans * leaf locks 11060384fff8SJason Evans */ 11070384fff8SJason Evans NULL 11080384fff8SJason Evans }; 11090384fff8SJason Evans 11100384fff8SJason Evans static char *order_list[] = { 1111a5d5c61cSJake Burkholder "uidinfo hash", "uidinfo struct", NULL, 11120384fff8SJason Evans NULL 11130384fff8SJason Evans }; 11140384fff8SJason Evans 11150384fff8SJason Evans static char *dup_list[] = { 11160384fff8SJason Evans NULL 11170384fff8SJason Evans }; 11180384fff8SJason Evans 11190384fff8SJason Evans static char *sleep_list[] = { 11207da6f977SJake Burkholder "Giant", 11210384fff8SJason Evans NULL 11220384fff8SJason Evans }; 11230384fff8SJason Evans 11240384fff8SJason Evans /* 11250384fff8SJason Evans * Pairs of locks which have been blessed 11260384fff8SJason Evans * Don't complain about order problems with blessed locks 11270384fff8SJason Evans */ 1128606f8eb2SJohn Baldwin static struct witness_blessed blessed_list[] = { 11290384fff8SJason Evans }; 1130606f8eb2SJohn Baldwin static int blessed_count = sizeof(blessed_list) / sizeof(struct witness_blessed); 11310384fff8SJason Evans 11320cde2e34SJason Evans static void 1133606f8eb2SJohn Baldwin witness_init(struct mtx *m, int flag) 11340384fff8SJason Evans { 11350384fff8SJason Evans m->mtx_witness = enroll(m->mtx_description, flag); 11360384fff8SJason Evans } 11370384fff8SJason Evans 11380cde2e34SJason Evans static void 1139606f8eb2SJohn Baldwin witness_destroy(struct mtx *m) 11400384fff8SJason Evans { 1141606f8eb2SJohn Baldwin struct mtx *m1; 11420384fff8SJason Evans struct proc *p; 11430384fff8SJason Evans p = CURPROC; 11440384fff8SJason Evans for ((m1 = LIST_FIRST(&p->p_heldmtx)); m1 != NULL; 11450384fff8SJason Evans m1 = LIST_NEXT(m1, mtx_held)) { 11460384fff8SJason Evans if (m1 == m) { 11470384fff8SJason Evans LIST_REMOVE(m, mtx_held); 11480384fff8SJason Evans break; 11490384fff8SJason Evans } 11500384fff8SJason Evans } 11510384fff8SJason Evans return; 11520384fff8SJason Evans 11530384fff8SJason Evans } 11540384fff8SJason Evans 11550cde2e34SJason Evans static void 11560cde2e34SJason Evans witness_display(void(*prnt)(const char *fmt, ...)) 11570cde2e34SJason Evans { 11580cde2e34SJason Evans struct witness *w, *w1; 11590cde2e34SJason Evans 11600cde2e34SJason Evans KASSERT(!witness_cold, ("%s: witness_cold\n", __FUNCTION__)); 11610cde2e34SJason Evans witness_levelall(); 11620cde2e34SJason Evans 11630cde2e34SJason Evans for (w = w_all; w; w = w->w_next) { 11640cde2e34SJason Evans if (w->w_file == NULL) 11650cde2e34SJason Evans continue; 11660cde2e34SJason Evans for (w1 = w_all; w1; w1 = w1->w_next) { 11670cde2e34SJason Evans if (isitmychild(w1, w)) 11680cde2e34SJason Evans break; 11690cde2e34SJason Evans } 11700cde2e34SJason Evans if (w1 != NULL) 11710cde2e34SJason Evans continue; 11720cde2e34SJason Evans /* 11730cde2e34SJason Evans * This lock has no anscestors, display its descendants. 11740cde2e34SJason Evans */ 11750cde2e34SJason Evans witness_displaydescendants(prnt, w); 11760cde2e34SJason Evans } 11770cde2e34SJason Evans prnt("\nMutex which were never acquired\n"); 11780cde2e34SJason Evans for (w = w_all; w; w = w->w_next) { 11790cde2e34SJason Evans if (w->w_file != NULL) 11800cde2e34SJason Evans continue; 11810cde2e34SJason Evans prnt("%s\n", w->w_description); 11820cde2e34SJason Evans } 11830cde2e34SJason Evans } 11840cde2e34SJason Evans 11850384fff8SJason Evans void 1186606f8eb2SJohn Baldwin witness_enter(struct mtx *m, int flags, const char *file, int line) 11870384fff8SJason Evans { 1188606f8eb2SJohn Baldwin struct witness *w, *w1; 1189606f8eb2SJohn Baldwin struct mtx *m1; 11900384fff8SJason Evans struct proc *p; 11910384fff8SJason Evans int i; 1192a5a96a19SJohn Baldwin #ifdef DDB 1193a5a96a19SJohn Baldwin int go_into_ddb = 0; 1194a5a96a19SJohn Baldwin #endif /* DDB */ 11950384fff8SJason Evans 11960cde2e34SJason Evans if (witness_cold || m->mtx_witness == NULL || panicstr) 1197562e4ffeSJohn Baldwin return; 11980384fff8SJason Evans w = m->mtx_witness; 11990384fff8SJason Evans p = CURPROC; 12000384fff8SJason Evans 12010384fff8SJason Evans if (flags & MTX_SPIN) { 120208812b39SBosko Milekic if (!(w->w_spin)) 12035340642aSJason Evans panic("mutex_enter: MTX_SPIN on MTX_DEF mutex %s @" 12045340642aSJason Evans " %s:%d", m->mtx_description, file, line); 120508812b39SBosko Milekic if (mtx_recursed(m)) { 120608812b39SBosko Milekic if (!(w->w_recurse)) 120708812b39SBosko Milekic panic("mutex_enter: recursion on non-recursive" 120808812b39SBosko Milekic " mutex %s @ %s:%d", m->mtx_description, 120908812b39SBosko Milekic file, line); 12100384fff8SJason Evans return; 121108812b39SBosko Milekic } 1212562e4ffeSJohn Baldwin mtx_enter(&w_mtx, MTX_SPIN | MTX_QUIET); 1213ef73ae4bSJake Burkholder i = PCPU_GET(witness_spin_check); 12140384fff8SJason Evans if (i != 0 && w->w_level < i) { 1215562e4ffeSJohn Baldwin mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET); 12165340642aSJason Evans panic("mutex_enter(%s:%x, MTX_SPIN) out of order @" 12175340642aSJason Evans " %s:%d already holding %s:%x", 12180384fff8SJason Evans m->mtx_description, w->w_level, file, line, 12190384fff8SJason Evans spin_order_list[ffs(i)-1], i); 12200384fff8SJason Evans } 12210384fff8SJason Evans PCPU_SET(witness_spin_check, i | w->w_level); 1222562e4ffeSJohn Baldwin mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET); 1223bbc7a98aSJohn Baldwin w->w_file = file; 1224bbc7a98aSJohn Baldwin w->w_line = line; 1225bbc7a98aSJohn Baldwin m->mtx_line = line; 1226bbc7a98aSJohn Baldwin m->mtx_file = file; 12270384fff8SJason Evans return; 12280384fff8SJason Evans } 12290384fff8SJason Evans if (w->w_spin) 12300384fff8SJason Evans panic("mutex_enter: MTX_DEF on MTX_SPIN mutex %s @ %s:%d", 12310384fff8SJason Evans m->mtx_description, file, line); 12320384fff8SJason Evans 123308812b39SBosko Milekic if (mtx_recursed(m)) { 123408812b39SBosko Milekic if (!(w->w_recurse)) 123508812b39SBosko Milekic panic("mutex_enter: recursion on non-recursive" 123608812b39SBosko Milekic " mutex %s @ %s:%d", m->mtx_description, 123708812b39SBosko Milekic file, line); 12380384fff8SJason Evans return; 123908812b39SBosko Milekic } 12400384fff8SJason Evans if (witness_dead) 12410384fff8SJason Evans goto out; 1242562e4ffeSJohn Baldwin if (cold) 12430384fff8SJason Evans goto out; 12440384fff8SJason Evans 12450384fff8SJason Evans if (!mtx_legal2block()) 12460384fff8SJason Evans panic("blockable mtx_enter() of %s when not legal @ %s:%d", 12470384fff8SJason Evans m->mtx_description, file, line); 12480384fff8SJason Evans /* 12490384fff8SJason Evans * Is this the first mutex acquired 12500384fff8SJason Evans */ 12510384fff8SJason Evans if ((m1 = LIST_FIRST(&p->p_heldmtx)) == NULL) 12520384fff8SJason Evans goto out; 12530384fff8SJason Evans 12540384fff8SJason Evans if ((w1 = m1->mtx_witness) == w) { 12550384fff8SJason Evans if (w->w_same_squawked || dup_ok(w)) 12560384fff8SJason Evans goto out; 12570384fff8SJason Evans w->w_same_squawked = 1; 12580384fff8SJason Evans printf("acquring duplicate lock of same type: \"%s\"\n", 12590384fff8SJason Evans m->mtx_description); 12600384fff8SJason Evans printf(" 1st @ %s:%d\n", w->w_file, w->w_line); 12610384fff8SJason Evans printf(" 2nd @ %s:%d\n", file, line); 1262a5a96a19SJohn Baldwin #ifdef DDB 1263a5a96a19SJohn Baldwin go_into_ddb = 1; 1264a5a96a19SJohn Baldwin #endif /* DDB */ 12650384fff8SJason Evans goto out; 12660384fff8SJason Evans } 12670384fff8SJason Evans MPASS(!mtx_owned(&w_mtx)); 1268562e4ffeSJohn Baldwin mtx_enter(&w_mtx, MTX_SPIN | MTX_QUIET); 12690384fff8SJason Evans /* 12700384fff8SJason Evans * If we have a known higher number just say ok 12710384fff8SJason Evans */ 12720384fff8SJason Evans if (witness_watch > 1 && w->w_level > w1->w_level) { 1273562e4ffeSJohn Baldwin mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET); 12740384fff8SJason Evans goto out; 12750384fff8SJason Evans } 12760384fff8SJason Evans if (isitmydescendant(m1->mtx_witness, w)) { 1277562e4ffeSJohn Baldwin mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET); 12780384fff8SJason Evans goto out; 12790384fff8SJason Evans } 12800384fff8SJason Evans for (i = 0; m1 != NULL; m1 = LIST_NEXT(m1, mtx_held), i++) { 12810384fff8SJason Evans 128236412d79SJohn Baldwin MPASS(i < 200); 12830384fff8SJason Evans w1 = m1->mtx_witness; 12840384fff8SJason Evans if (isitmydescendant(w, w1)) { 1285562e4ffeSJohn Baldwin mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET); 12860384fff8SJason Evans if (blessed(w, w1)) 12870384fff8SJason Evans goto out; 12880384fff8SJason Evans if (m1 == &Giant) { 12890384fff8SJason Evans if (w1->w_Giant_squawked) 12900384fff8SJason Evans goto out; 12910384fff8SJason Evans else 12920384fff8SJason Evans w1->w_Giant_squawked = 1; 12930384fff8SJason Evans } else { 12940384fff8SJason Evans if (w1->w_other_squawked) 12950384fff8SJason Evans goto out; 12960384fff8SJason Evans else 12970384fff8SJason Evans w1->w_other_squawked = 1; 12980384fff8SJason Evans } 12990384fff8SJason Evans printf("lock order reversal\n"); 13000384fff8SJason Evans printf(" 1st %s last acquired @ %s:%d\n", 13010384fff8SJason Evans w->w_description, w->w_file, w->w_line); 13020384fff8SJason Evans printf(" 2nd %p %s @ %s:%d\n", 13030384fff8SJason Evans m1, w1->w_description, w1->w_file, w1->w_line); 13040384fff8SJason Evans printf(" 3rd %p %s @ %s:%d\n", 13050384fff8SJason Evans m, w->w_description, file, line); 1306a5a96a19SJohn Baldwin #ifdef DDB 1307a5a96a19SJohn Baldwin go_into_ddb = 1; 1308a5a96a19SJohn Baldwin #endif /* DDB */ 13090384fff8SJason Evans goto out; 13100384fff8SJason Evans } 13110384fff8SJason Evans } 13120384fff8SJason Evans m1 = LIST_FIRST(&p->p_heldmtx); 13130384fff8SJason Evans if (!itismychild(m1->mtx_witness, w)) 1314562e4ffeSJohn Baldwin mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET); 13150384fff8SJason Evans 13160384fff8SJason Evans out: 1317a5a96a19SJohn Baldwin #ifdef DDB 1318a5a96a19SJohn Baldwin if (witness_ddb && go_into_ddb) 1319a5a96a19SJohn Baldwin Debugger("witness_enter"); 1320a5a96a19SJohn Baldwin #endif /* DDB */ 13210384fff8SJason Evans w->w_file = file; 13220384fff8SJason Evans w->w_line = line; 13230384fff8SJason Evans m->mtx_line = line; 13240384fff8SJason Evans m->mtx_file = file; 13250384fff8SJason Evans 13260384fff8SJason Evans /* 13270384fff8SJason Evans * If this pays off it likely means that a mutex being witnessed 13280384fff8SJason Evans * is acquired in hardclock. Put it in the ignore list. It is 13290384fff8SJason Evans * likely not the mutex this assert fails on. 13300384fff8SJason Evans */ 133136412d79SJohn Baldwin MPASS(m->mtx_held.le_prev == NULL); 13320384fff8SJason Evans LIST_INSERT_HEAD(&p->p_heldmtx, (struct mtx*)m, mtx_held); 13330384fff8SJason Evans } 13340384fff8SJason Evans 13350384fff8SJason Evans void 1336606f8eb2SJohn Baldwin witness_try_enter(struct mtx *m, int flags, const char *file, int line) 13370384fff8SJason Evans { 13380384fff8SJason Evans struct proc *p; 1339606f8eb2SJohn Baldwin struct witness *w = m->mtx_witness; 13400384fff8SJason Evans 1341d1c1b841SJason Evans if (witness_cold) 1342d1c1b841SJason Evans return; 1343562e4ffeSJohn Baldwin if (panicstr) 1344562e4ffeSJohn Baldwin return; 13450384fff8SJason Evans if (flags & MTX_SPIN) { 134608812b39SBosko Milekic if (!(w->w_spin)) 13470384fff8SJason Evans panic("mutex_try_enter: " 13480384fff8SJason Evans "MTX_SPIN on MTX_DEF mutex %s @ %s:%d", 13490384fff8SJason Evans m->mtx_description, file, line); 135008812b39SBosko Milekic if (mtx_recursed(m)) { 135108812b39SBosko Milekic if (!(w->w_recurse)) 135208812b39SBosko Milekic panic("mutex_try_enter: recursion on" 135308812b39SBosko Milekic " non-recursive mutex %s @ %s:%d", 135408812b39SBosko Milekic m->mtx_description, file, line); 13550384fff8SJason Evans return; 135608812b39SBosko Milekic } 1357562e4ffeSJohn Baldwin mtx_enter(&w_mtx, MTX_SPIN | MTX_QUIET); 1358ef73ae4bSJake Burkholder PCPU_SET(witness_spin_check, 1359ef73ae4bSJake Burkholder PCPU_GET(witness_spin_check) | w->w_level); 1360562e4ffeSJohn Baldwin mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET); 1361bbc7a98aSJohn Baldwin w->w_file = file; 1362bbc7a98aSJohn Baldwin w->w_line = line; 1363bbc7a98aSJohn Baldwin m->mtx_line = line; 1364bbc7a98aSJohn Baldwin m->mtx_file = file; 13650384fff8SJason Evans return; 13660384fff8SJason Evans } 13670384fff8SJason Evans 13680384fff8SJason Evans if (w->w_spin) 13690384fff8SJason Evans panic("mutex_try_enter: MTX_DEF on MTX_SPIN mutex %s @ %s:%d", 13700384fff8SJason Evans m->mtx_description, file, line); 13710384fff8SJason Evans 137208812b39SBosko Milekic if (mtx_recursed(m)) { 137308812b39SBosko Milekic if (!(w->w_recurse)) 137408812b39SBosko Milekic panic("mutex_try_enter: recursion on non-recursive" 137508812b39SBosko Milekic " mutex %s @ %s:%d", m->mtx_description, file, 137608812b39SBosko Milekic line); 13770384fff8SJason Evans return; 137808812b39SBosko Milekic } 13790384fff8SJason Evans w->w_file = file; 13800384fff8SJason Evans w->w_line = line; 13810384fff8SJason Evans m->mtx_line = line; 13820384fff8SJason Evans m->mtx_file = file; 13830384fff8SJason Evans p = CURPROC; 138436412d79SJohn Baldwin MPASS(m->mtx_held.le_prev == NULL); 13850384fff8SJason Evans LIST_INSERT_HEAD(&p->p_heldmtx, (struct mtx*)m, mtx_held); 13860384fff8SJason Evans } 13870384fff8SJason Evans 13880384fff8SJason Evans void 13890cde2e34SJason Evans witness_exit(struct mtx *m, int flags, const char *file, int line) 13900384fff8SJason Evans { 13910cde2e34SJason Evans struct witness *w; 13920384fff8SJason Evans 13930cde2e34SJason Evans if (witness_cold || m->mtx_witness == NULL || panicstr) 13940cde2e34SJason Evans return; 13950cde2e34SJason Evans w = m->mtx_witness; 13960384fff8SJason Evans 13970cde2e34SJason Evans if (flags & MTX_SPIN) { 13980cde2e34SJason Evans if (!(w->w_spin)) 13990cde2e34SJason Evans panic("mutex_exit: MTX_SPIN on MTX_DEF mutex %s @" 14000cde2e34SJason Evans " %s:%d", m->mtx_description, file, line); 14010cde2e34SJason Evans if (mtx_recursed(m)) { 14020cde2e34SJason Evans if (!(w->w_recurse)) 14030cde2e34SJason Evans panic("mutex_exit: recursion on non-recursive" 14040cde2e34SJason Evans " mutex %s @ %s:%d", m->mtx_description, 14050cde2e34SJason Evans file, line); 14060cde2e34SJason Evans return; 14070384fff8SJason Evans } 14080cde2e34SJason Evans mtx_enter(&w_mtx, MTX_SPIN | MTX_QUIET); 14090cde2e34SJason Evans PCPU_SET(witness_spin_check, 14100cde2e34SJason Evans PCPU_GET(witness_spin_check) & ~w->w_level); 14110cde2e34SJason Evans mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET); 14120cde2e34SJason Evans return; 14130384fff8SJason Evans } 14140cde2e34SJason Evans if (w->w_spin) 14150cde2e34SJason Evans panic("mutex_exit: MTX_DEF on MTX_SPIN mutex %s @ %s:%d", 14160cde2e34SJason Evans m->mtx_description, file, line); 14170cde2e34SJason Evans 14180cde2e34SJason Evans if (mtx_recursed(m)) { 14190cde2e34SJason Evans if (!(w->w_recurse)) 14200cde2e34SJason Evans panic("mutex_exit: recursion on non-recursive" 14210cde2e34SJason Evans " mutex %s @ %s:%d", m->mtx_description, 14220cde2e34SJason Evans file, line); 14230cde2e34SJason Evans return; 14240384fff8SJason Evans } 14250cde2e34SJason Evans 14260cde2e34SJason Evans if ((flags & MTX_NOSWITCH) == 0 && !mtx_legal2block() && !cold) 14270cde2e34SJason Evans panic("switchable mtx_exit() of %s when not legal @ %s:%d", 14280cde2e34SJason Evans m->mtx_description, file, line); 14290cde2e34SJason Evans LIST_REMOVE(m, mtx_held); 14300cde2e34SJason Evans m->mtx_held.le_prev = NULL; 14310384fff8SJason Evans } 14320384fff8SJason Evans 14330384fff8SJason Evans int 1434606f8eb2SJohn Baldwin witness_sleep(int check_only, struct mtx *mtx, const char *file, int line) 14350384fff8SJason Evans { 1436606f8eb2SJohn Baldwin struct mtx *m; 14370384fff8SJason Evans struct proc *p; 14380384fff8SJason Evans char **sleep; 14390384fff8SJason Evans int n = 0; 14400384fff8SJason Evans 1441d1c1b841SJason Evans KASSERT(!witness_cold, ("%s: witness_cold\n", __FUNCTION__)); 14420384fff8SJason Evans p = CURPROC; 14430384fff8SJason Evans for ((m = LIST_FIRST(&p->p_heldmtx)); m != NULL; 14440384fff8SJason Evans m = LIST_NEXT(m, mtx_held)) { 14450384fff8SJason Evans if (m == mtx) 14460384fff8SJason Evans continue; 14470384fff8SJason Evans for (sleep = sleep_list; *sleep!= NULL; sleep++) 14480384fff8SJason Evans if (strcmp(m->mtx_description, *sleep) == 0) 14490384fff8SJason Evans goto next; 14500384fff8SJason Evans printf("%s:%d: %s with \"%s\" locked from %s:%d\n", 14510384fff8SJason Evans file, line, check_only ? "could sleep" : "sleeping", 14520384fff8SJason Evans m->mtx_description, 14530384fff8SJason Evans m->mtx_witness->w_file, m->mtx_witness->w_line); 14540384fff8SJason Evans n++; 14550384fff8SJason Evans next: 14560384fff8SJason Evans } 1457a5a96a19SJohn Baldwin #ifdef DDB 1458a5a96a19SJohn Baldwin if (witness_ddb && n) 1459a5a96a19SJohn Baldwin Debugger("witness_sleep"); 1460a5a96a19SJohn Baldwin #endif /* DDB */ 14610384fff8SJason Evans return (n); 14620384fff8SJason Evans } 14630384fff8SJason Evans 1464606f8eb2SJohn Baldwin static struct witness * 1465b67a3e6eSJohn Baldwin enroll(const char *description, int flag) 14660384fff8SJason Evans { 14670384fff8SJason Evans int i; 1468606f8eb2SJohn Baldwin struct witness *w, *w1; 14690384fff8SJason Evans char **ignore; 14700384fff8SJason Evans char **order; 14710384fff8SJason Evans 14720384fff8SJason Evans if (!witness_watch) 14730384fff8SJason Evans return (NULL); 14740384fff8SJason Evans for (ignore = ignore_list; *ignore != NULL; ignore++) 14750384fff8SJason Evans if (strcmp(description, *ignore) == 0) 14760384fff8SJason Evans return (NULL); 14770384fff8SJason Evans 14780384fff8SJason Evans if (w_inited == 0) { 1479d1c1b841SJason Evans mtx_init(&w_mtx, "witness lock", MTX_SPIN); 14800384fff8SJason Evans for (i = 0; i < WITNESS_COUNT; i++) { 14810384fff8SJason Evans w = &w_data[i]; 14820384fff8SJason Evans witness_free(w); 14830384fff8SJason Evans } 14840384fff8SJason Evans w_inited = 1; 14850384fff8SJason Evans for (order = order_list; *order != NULL; order++) { 14860384fff8SJason Evans w = enroll(*order, MTX_DEF); 14870384fff8SJason Evans w->w_file = "order list"; 14880384fff8SJason Evans for (order++; *order != NULL; order++) { 14890384fff8SJason Evans w1 = enroll(*order, MTX_DEF); 14900384fff8SJason Evans w1->w_file = "order list"; 14910384fff8SJason Evans itismychild(w, w1); 14920384fff8SJason Evans w = w1; 14930384fff8SJason Evans } 14940384fff8SJason Evans } 14950384fff8SJason Evans } 14960384fff8SJason Evans if ((flag & MTX_SPIN) && witness_skipspin) 14970384fff8SJason Evans return (NULL); 1498562e4ffeSJohn Baldwin mtx_enter(&w_mtx, MTX_SPIN | MTX_QUIET); 14990384fff8SJason Evans for (w = w_all; w; w = w->w_next) { 15000384fff8SJason Evans if (strcmp(description, w->w_description) == 0) { 1501562e4ffeSJohn Baldwin mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET); 15020384fff8SJason Evans return (w); 15030384fff8SJason Evans } 15040384fff8SJason Evans } 15050384fff8SJason Evans if ((w = witness_get()) == NULL) 15060384fff8SJason Evans return (NULL); 15070384fff8SJason Evans w->w_next = w_all; 15080384fff8SJason Evans w_all = w; 15090384fff8SJason Evans w->w_description = description; 1510562e4ffeSJohn Baldwin mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET); 15110384fff8SJason Evans if (flag & MTX_SPIN) { 15120384fff8SJason Evans w->w_spin = 1; 15130384fff8SJason Evans 15140384fff8SJason Evans i = 1; 15150384fff8SJason Evans for (order = spin_order_list; *order != NULL; order++) { 15160384fff8SJason Evans if (strcmp(description, *order) == 0) 15170384fff8SJason Evans break; 15180384fff8SJason Evans i <<= 1; 15190384fff8SJason Evans } 15200384fff8SJason Evans if (*order == NULL) 15210384fff8SJason Evans panic("spin lock %s not in order list", description); 15220384fff8SJason Evans w->w_level = i; 152308812b39SBosko Milekic } else 152408812b39SBosko Milekic w->w_sleep = 1; 152508812b39SBosko Milekic 152608812b39SBosko Milekic if (flag & MTX_RECURSE) 152708812b39SBosko Milekic w->w_recurse = 1; 152808812b39SBosko Milekic 15290384fff8SJason Evans return (w); 15300384fff8SJason Evans } 15310384fff8SJason Evans 15320384fff8SJason Evans static int 1533606f8eb2SJohn Baldwin itismychild(struct witness *parent, struct witness *child) 15340384fff8SJason Evans { 15350384fff8SJason Evans static int recursed; 15360384fff8SJason Evans 15370384fff8SJason Evans /* 15380384fff8SJason Evans * Insert "child" after "parent" 15390384fff8SJason Evans */ 15400384fff8SJason Evans while (parent->w_morechildren) 15410384fff8SJason Evans parent = parent->w_morechildren; 15420384fff8SJason Evans 15430384fff8SJason Evans if (parent->w_childcnt == WITNESS_NCHILDREN) { 15440384fff8SJason Evans if ((parent->w_morechildren = witness_get()) == NULL) 15450384fff8SJason Evans return (1); 15460384fff8SJason Evans parent = parent->w_morechildren; 15470384fff8SJason Evans } 154836412d79SJohn Baldwin MPASS(child != NULL); 15490384fff8SJason Evans parent->w_children[parent->w_childcnt++] = child; 15500384fff8SJason Evans /* 15510384fff8SJason Evans * now prune whole tree 15520384fff8SJason Evans */ 15530384fff8SJason Evans if (recursed) 15540384fff8SJason Evans return (0); 15550384fff8SJason Evans recursed = 1; 15560384fff8SJason Evans for (child = w_all; child != NULL; child = child->w_next) { 15570384fff8SJason Evans for (parent = w_all; parent != NULL; 15580384fff8SJason Evans parent = parent->w_next) { 15590384fff8SJason Evans if (!isitmychild(parent, child)) 15600384fff8SJason Evans continue; 15610384fff8SJason Evans removechild(parent, child); 15620384fff8SJason Evans if (isitmydescendant(parent, child)) 15630384fff8SJason Evans continue; 15640384fff8SJason Evans itismychild(parent, child); 15650384fff8SJason Evans } 15660384fff8SJason Evans } 15670384fff8SJason Evans recursed = 0; 15680384fff8SJason Evans witness_levelall(); 15690384fff8SJason Evans return (0); 15700384fff8SJason Evans } 15710384fff8SJason Evans 15720384fff8SJason Evans static void 1573606f8eb2SJohn Baldwin removechild(struct witness *parent, struct witness *child) 15740384fff8SJason Evans { 1575606f8eb2SJohn Baldwin struct witness *w, *w1; 15760384fff8SJason Evans int i; 15770384fff8SJason Evans 15780384fff8SJason Evans for (w = parent; w != NULL; w = w->w_morechildren) 15790384fff8SJason Evans for (i = 0; i < w->w_childcnt; i++) 15800384fff8SJason Evans if (w->w_children[i] == child) 15810384fff8SJason Evans goto found; 15820384fff8SJason Evans return; 15830384fff8SJason Evans found: 15840384fff8SJason Evans for (w1 = w; w1->w_morechildren != NULL; w1 = w1->w_morechildren) 15850384fff8SJason Evans continue; 15860384fff8SJason Evans w->w_children[i] = w1->w_children[--w1->w_childcnt]; 158736412d79SJohn Baldwin MPASS(w->w_children[i] != NULL); 15880384fff8SJason Evans 15890384fff8SJason Evans if (w1->w_childcnt != 0) 15900384fff8SJason Evans return; 15910384fff8SJason Evans 15920384fff8SJason Evans if (w1 == parent) 15930384fff8SJason Evans return; 15940384fff8SJason Evans for (w = parent; w->w_morechildren != w1; w = w->w_morechildren) 15950384fff8SJason Evans continue; 15960384fff8SJason Evans w->w_morechildren = 0; 15970384fff8SJason Evans witness_free(w1); 15980384fff8SJason Evans } 15990384fff8SJason Evans 16000384fff8SJason Evans static int 1601606f8eb2SJohn Baldwin isitmychild(struct witness *parent, struct witness *child) 16020384fff8SJason Evans { 1603606f8eb2SJohn Baldwin struct witness *w; 16040384fff8SJason Evans int i; 16050384fff8SJason Evans 16060384fff8SJason Evans for (w = parent; w != NULL; w = w->w_morechildren) { 16070384fff8SJason Evans for (i = 0; i < w->w_childcnt; i++) { 16080384fff8SJason Evans if (w->w_children[i] == child) 16090384fff8SJason Evans return (1); 16100384fff8SJason Evans } 16110384fff8SJason Evans } 16120384fff8SJason Evans return (0); 16130384fff8SJason Evans } 16140384fff8SJason Evans 16150384fff8SJason Evans static int 1616606f8eb2SJohn Baldwin isitmydescendant(struct witness *parent, struct witness *child) 16170384fff8SJason Evans { 1618606f8eb2SJohn Baldwin struct witness *w; 16190384fff8SJason Evans int i; 16200384fff8SJason Evans int j; 16210384fff8SJason Evans 16220384fff8SJason Evans for (j = 0, w = parent; w != NULL; w = w->w_morechildren, j++) { 162336412d79SJohn Baldwin MPASS(j < 1000); 16240384fff8SJason Evans for (i = 0; i < w->w_childcnt; i++) { 16250384fff8SJason Evans if (w->w_children[i] == child) 16260384fff8SJason Evans return (1); 16270384fff8SJason Evans } 16280384fff8SJason Evans for (i = 0; i < w->w_childcnt; i++) { 16290384fff8SJason Evans if (isitmydescendant(w->w_children[i], child)) 16300384fff8SJason Evans return (1); 16310384fff8SJason Evans } 16320384fff8SJason Evans } 16330384fff8SJason Evans return (0); 16340384fff8SJason Evans } 16350384fff8SJason Evans 16360384fff8SJason Evans void 16370384fff8SJason Evans witness_levelall (void) 16380384fff8SJason Evans { 1639606f8eb2SJohn Baldwin struct witness *w, *w1; 16400384fff8SJason Evans 16410384fff8SJason Evans for (w = w_all; w; w = w->w_next) 164208812b39SBosko Milekic if (!(w->w_spin)) 16430384fff8SJason Evans w->w_level = 0; 16440384fff8SJason Evans for (w = w_all; w; w = w->w_next) { 16450384fff8SJason Evans if (w->w_spin) 16460384fff8SJason Evans continue; 16470384fff8SJason Evans for (w1 = w_all; w1; w1 = w1->w_next) { 16480384fff8SJason Evans if (isitmychild(w1, w)) 16490384fff8SJason Evans break; 16500384fff8SJason Evans } 16510384fff8SJason Evans if (w1 != NULL) 16520384fff8SJason Evans continue; 16530384fff8SJason Evans witness_leveldescendents(w, 0); 16540384fff8SJason Evans } 16550384fff8SJason Evans } 16560384fff8SJason Evans 16570384fff8SJason Evans static void 1658606f8eb2SJohn Baldwin witness_leveldescendents(struct witness *parent, int level) 16590384fff8SJason Evans { 16600384fff8SJason Evans int i; 1661606f8eb2SJohn Baldwin struct witness *w; 16620384fff8SJason Evans 16630384fff8SJason Evans if (parent->w_level < level) 16640384fff8SJason Evans parent->w_level = level; 16650384fff8SJason Evans level++; 16660384fff8SJason Evans for (w = parent; w != NULL; w = w->w_morechildren) 16670384fff8SJason Evans for (i = 0; i < w->w_childcnt; i++) 16680384fff8SJason Evans witness_leveldescendents(w->w_children[i], level); 16690384fff8SJason Evans } 16700384fff8SJason Evans 16710384fff8SJason Evans static void 1672606f8eb2SJohn Baldwin witness_displaydescendants(void(*prnt)(const char *fmt, ...), 1673606f8eb2SJohn Baldwin struct witness *parent) 16740384fff8SJason Evans { 1675606f8eb2SJohn Baldwin struct witness *w; 16760384fff8SJason Evans int i; 16770384fff8SJason Evans int level = parent->w_level; 16780384fff8SJason Evans 16790384fff8SJason Evans prnt("%d", level); 16800384fff8SJason Evans if (level < 10) 16810384fff8SJason Evans prnt(" "); 16820384fff8SJason Evans for (i = 0; i < level; i++) 16830384fff8SJason Evans prnt(" "); 16840384fff8SJason Evans prnt("%s", parent->w_description); 16850384fff8SJason Evans if (parent->w_file != NULL) { 16860384fff8SJason Evans prnt(" -- last acquired @ %s", parent->w_file); 16870384fff8SJason Evans #ifndef W_USE_WHERE 16880384fff8SJason Evans prnt(":%d", parent->w_line); 16890384fff8SJason Evans #endif 16900384fff8SJason Evans prnt("\n"); 16910384fff8SJason Evans } 16920384fff8SJason Evans 16930384fff8SJason Evans for (w = parent; w != NULL; w = w->w_morechildren) 16940384fff8SJason Evans for (i = 0; i < w->w_childcnt; i++) 16950384fff8SJason Evans witness_displaydescendants(prnt, w->w_children[i]); 16960384fff8SJason Evans } 16970384fff8SJason Evans 16980384fff8SJason Evans static int 1699606f8eb2SJohn Baldwin dup_ok(struct witness *w) 17000384fff8SJason Evans { 17010384fff8SJason Evans char **dup; 17020384fff8SJason Evans 17030384fff8SJason Evans for (dup = dup_list; *dup!= NULL; dup++) 17040384fff8SJason Evans if (strcmp(w->w_description, *dup) == 0) 17050384fff8SJason Evans return (1); 17060384fff8SJason Evans return (0); 17070384fff8SJason Evans } 17080384fff8SJason Evans 17090384fff8SJason Evans static int 1710606f8eb2SJohn Baldwin blessed(struct witness *w1, struct witness *w2) 17110384fff8SJason Evans { 17120384fff8SJason Evans int i; 1713606f8eb2SJohn Baldwin struct witness_blessed *b; 17140384fff8SJason Evans 17150384fff8SJason Evans for (i = 0; i < blessed_count; i++) { 17160384fff8SJason Evans b = &blessed_list[i]; 17170384fff8SJason Evans if (strcmp(w1->w_description, b->b_lock1) == 0) { 17180384fff8SJason Evans if (strcmp(w2->w_description, b->b_lock2) == 0) 17190384fff8SJason Evans return (1); 17200384fff8SJason Evans continue; 17210384fff8SJason Evans } 17220384fff8SJason Evans if (strcmp(w1->w_description, b->b_lock2) == 0) 17230384fff8SJason Evans if (strcmp(w2->w_description, b->b_lock1) == 0) 17240384fff8SJason Evans return (1); 17250384fff8SJason Evans } 17260384fff8SJason Evans return (0); 17270384fff8SJason Evans } 17280384fff8SJason Evans 1729606f8eb2SJohn Baldwin static struct witness * 17300384fff8SJason Evans witness_get() 17310384fff8SJason Evans { 1732606f8eb2SJohn Baldwin struct witness *w; 17330384fff8SJason Evans 17340384fff8SJason Evans if ((w = w_free) == NULL) { 17350384fff8SJason Evans witness_dead = 1; 1736562e4ffeSJohn Baldwin mtx_exit(&w_mtx, MTX_SPIN | MTX_QUIET); 17370384fff8SJason Evans printf("witness exhausted\n"); 17380384fff8SJason Evans return (NULL); 17390384fff8SJason Evans } 17400384fff8SJason Evans w_free = w->w_next; 17410384fff8SJason Evans bzero(w, sizeof(*w)); 17420384fff8SJason Evans return (w); 17430384fff8SJason Evans } 17440384fff8SJason Evans 17450384fff8SJason Evans static void 1746606f8eb2SJohn Baldwin witness_free(struct witness *w) 17470384fff8SJason Evans { 17480384fff8SJason Evans w->w_next = w_free; 17490384fff8SJason Evans w_free = w; 17500384fff8SJason Evans } 17510384fff8SJason Evans 175292cf772dSJake Burkholder int 17530384fff8SJason Evans witness_list(struct proc *p) 17540384fff8SJason Evans { 1755606f8eb2SJohn Baldwin struct mtx *m; 175692cf772dSJake Burkholder int nheld; 17570384fff8SJason Evans 1758d1c1b841SJason Evans KASSERT(!witness_cold, ("%s: witness_cold\n", __FUNCTION__)); 175992cf772dSJake Burkholder nheld = 0; 17600384fff8SJason Evans for ((m = LIST_FIRST(&p->p_heldmtx)); m != NULL; 17610384fff8SJason Evans m = LIST_NEXT(m, mtx_held)) { 17620384fff8SJason Evans printf("\t\"%s\" (%p) locked at %s:%d\n", 17630384fff8SJason Evans m->mtx_description, m, 17640384fff8SJason Evans m->mtx_witness->w_file, m->mtx_witness->w_line); 176592cf772dSJake Burkholder nheld++; 17660384fff8SJason Evans } 176792cf772dSJake Burkholder 176892cf772dSJake Burkholder return (nheld); 17690384fff8SJason Evans } 17700384fff8SJason Evans 17710384fff8SJason Evans void 1772606f8eb2SJohn Baldwin witness_save(struct mtx *m, const char **filep, int *linep) 17730384fff8SJason Evans { 1774d1c1b841SJason Evans 1775d1c1b841SJason Evans KASSERT(!witness_cold, ("%s: witness_cold\n", __FUNCTION__)); 17760cde2e34SJason Evans if (m->mtx_witness == NULL) 17770cde2e34SJason Evans return; 17780cde2e34SJason Evans 17790384fff8SJason Evans *filep = m->mtx_witness->w_file; 17800384fff8SJason Evans *linep = m->mtx_witness->w_line; 17810384fff8SJason Evans } 17820384fff8SJason Evans 17830384fff8SJason Evans void 1784606f8eb2SJohn Baldwin witness_restore(struct mtx *m, const char *file, int line) 17850384fff8SJason Evans { 1786d1c1b841SJason Evans 1787d1c1b841SJason Evans KASSERT(!witness_cold, ("%s: witness_cold\n", __FUNCTION__)); 17880cde2e34SJason Evans if (m->mtx_witness == NULL) 17890cde2e34SJason Evans return; 17900cde2e34SJason Evans 17910384fff8SJason Evans m->mtx_witness->w_file = file; 17920384fff8SJason Evans m->mtx_witness->w_line = line; 17930384fff8SJason Evans } 17940384fff8SJason Evans 17956936206eSJohn Baldwin #endif /* WITNESS */ 1796