xref: /freebsd/sys/kern/subr_turnstile.c (revision 4f506694bbbeefe0998cf8d784aee28d95e4a598)
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  */
310384fff8SJason Evans 
320384fff8SJason Evans /*
33961a7b24SJohn Baldwin  * Implementation of turnstiles used to hold queue of threads blocked on
34961a7b24SJohn Baldwin  * non-sleepable locks.  Sleepable locks use condition variables to
35961a7b24SJohn Baldwin  * implement their queues.  Turnstiles differ from a sleep queue in that
36961a7b24SJohn Baldwin  * turnstile queue's are assigned to a lock held by an owning thread.  Thus,
37961a7b24SJohn Baldwin  * when one thread is enqueued onto a turnstile, it can lend its priority
38961a7b24SJohn Baldwin  * to the owning thread.
39961a7b24SJohn Baldwin  *
40961a7b24SJohn Baldwin  * We wish to avoid bloating locks with an embedded turnstile and we do not
41961a7b24SJohn Baldwin  * want to use back-pointers in the locks for the same reason.  Thus, we
42961a7b24SJohn Baldwin  * use a similar approach to that of Solaris 7 as described in Solaris
43961a7b24SJohn Baldwin  * Internals by Jim Mauro and Richard McDougall.  Turnstiles are looked up
44961a7b24SJohn Baldwin  * in a hash table based on the address of the lock.  Each entry in the
45961a7b24SJohn Baldwin  * hash table is a linked-lists of turnstiles and is called a turnstile
46961a7b24SJohn Baldwin  * chain.  Each chain contains a spin mutex that protects all of the
47961a7b24SJohn Baldwin  * turnstiles in the chain.
48961a7b24SJohn Baldwin  *
49961a7b24SJohn Baldwin  * Each time a thread is created, a turnstile is malloc'd and attached to
50961a7b24SJohn Baldwin  * that thread.  When a thread blocks on a lock, if it is the first thread
51961a7b24SJohn Baldwin  * to block, it lends its turnstile to the lock.  If the lock already has
52961a7b24SJohn Baldwin  * a turnstile, then it gives its turnstile to the lock's turnstile's free
53861a7db5SJohn Baldwin  * list.  When a thread is woken up, it takes a turnstile from the free list
54961a7b24SJohn Baldwin  * if there are any other waiters.  If it is the only thread blocked on the
55961a7b24SJohn Baldwin  * lock, then it reclaims the turnstile associated with the lock and removes
56961a7b24SJohn Baldwin  * it from the hash table.
570384fff8SJason Evans  */
580384fff8SJason Evans 
59677b542eSDavid E. O'Brien #include <sys/cdefs.h>
60677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$");
61677b542eSDavid E. O'Brien 
627aa4f685SJohn Baldwin #include "opt_ddb.h"
637aa4f685SJohn Baldwin #include "opt_turnstile_profiling.h"
647aa4f685SJohn Baldwin 
650384fff8SJason Evans #include <sys/param.h>
666c35e809SDag-Erling Smørgrav #include <sys/systm.h>
6736412d79SJohn Baldwin #include <sys/kernel.h>
686c35e809SDag-Erling Smørgrav #include <sys/ktr.h>
6919284646SJohn Baldwin #include <sys/lock.h>
70fb919e4dSMark Murray #include <sys/malloc.h>
7119284646SJohn Baldwin #include <sys/mutex.h>
720384fff8SJason Evans #include <sys/proc.h>
73961a7b24SJohn Baldwin #include <sys/queue.h>
74b43179fbSJeff Roberson #include <sys/sched.h>
75ef0ebfc3SJohn Baldwin #include <sys/sysctl.h>
76ef0ebfc3SJohn Baldwin #include <sys/turnstile.h>
7736412d79SJohn Baldwin 
787aa4f685SJohn Baldwin #ifdef DDB
79ae110b53SJohn Baldwin #include <sys/kdb.h>
807aa4f685SJohn Baldwin #include <ddb/ddb.h>
81462a7addSJohn Baldwin #include <sys/lockmgr.h>
82462a7addSJohn Baldwin #include <sys/sx.h>
837aa4f685SJohn Baldwin #endif
847aa4f685SJohn Baldwin 
850cde2e34SJason Evans /*
86961a7b24SJohn Baldwin  * Constants for the hash table of turnstile chains.  TC_SHIFT is a magic
87961a7b24SJohn Baldwin  * number chosen because the sleep queue's use the same value for the
88961a7b24SJohn Baldwin  * shift.  Basically, we ignore the lower 8 bits of the address.
89961a7b24SJohn Baldwin  * TC_TABLESIZE must be a power of two for TC_MASK to work properly.
900cde2e34SJason Evans  */
91961a7b24SJohn Baldwin #define	TC_TABLESIZE	128			/* Must be power of 2. */
92961a7b24SJohn Baldwin #define	TC_MASK		(TC_TABLESIZE - 1)
93961a7b24SJohn Baldwin #define	TC_SHIFT	8
94961a7b24SJohn Baldwin #define	TC_HASH(lock)	(((uintptr_t)(lock) >> TC_SHIFT) & TC_MASK)
95961a7b24SJohn Baldwin #define	TC_LOOKUP(lock)	&turnstile_chains[TC_HASH(lock)]
969ed346baSBosko Milekic 
970cde2e34SJason Evans /*
98961a7b24SJohn Baldwin  * There are three different lists of turnstiles as follows.  The list
99961a7b24SJohn Baldwin  * connected by ts_link entries is a per-thread list of all the turnstiles
100961a7b24SJohn Baldwin  * attached to locks that we own.  This is used to fixup our priority when
101961a7b24SJohn Baldwin  * a lock is released.  The other two lists use the ts_hash entries.  The
1025b7de7e1SJohn Baldwin  * first of these two is the turnstile chain list that a turnstile is on
1035b7de7e1SJohn Baldwin  * when it is attached to a lock.  The second list to use ts_hash is the
1045b7de7e1SJohn Baldwin  * free list hung off of a turnstile that is attached to a lock.
105961a7b24SJohn Baldwin  *
1067aa4f685SJohn Baldwin  * Each turnstile contains three lists of threads.  The two ts_blocked lists
1077aa4f685SJohn Baldwin  * are linked list of threads blocked on the turnstile's lock.  One list is
1087aa4f685SJohn Baldwin  * for exclusive waiters, and the other is for shared waiters.  The
109595bc82aSJohn Baldwin  * ts_pending list is a linked list of threads previously awakened by
110961a7b24SJohn Baldwin  * turnstile_signal() or turnstile_wait() that are waiting to be put on
111961a7b24SJohn Baldwin  * the run queue.
112961a7b24SJohn Baldwin  *
113961a7b24SJohn Baldwin  * Locking key:
114961a7b24SJohn Baldwin  *  c - turnstile chain lock
115961a7b24SJohn Baldwin  *  q - td_contested lock
1160cde2e34SJason Evans  */
117961a7b24SJohn Baldwin struct turnstile {
1187aa4f685SJohn Baldwin 	struct threadqueue ts_blocked[2];	/* (c + q) Blocked threads. */
1197aa4f685SJohn Baldwin 	struct threadqueue ts_pending;		/* (c) Pending threads. */
120961a7b24SJohn Baldwin 	LIST_ENTRY(turnstile) ts_hash;		/* (c) Chain and free list. */
121961a7b24SJohn Baldwin 	LIST_ENTRY(turnstile) ts_link;		/* (q) Contested locks. */
122961a7b24SJohn Baldwin 	LIST_HEAD(, turnstile) ts_free;		/* (c) Free turnstiles. */
123961a7b24SJohn Baldwin 	struct lock_object *ts_lockobj;		/* (c) Lock we reference. */
12479a13d01SJohn Baldwin 	struct thread *ts_owner;		/* (c + q) Who owns the lock. */
1258484de75SJohn Baldwin };
1268484de75SJohn Baldwin 
127961a7b24SJohn Baldwin struct turnstile_chain {
128961a7b24SJohn Baldwin 	LIST_HEAD(, turnstile) tc_turnstiles;	/* List of turnstiles. */
129961a7b24SJohn Baldwin 	struct mtx tc_lock;			/* Spin lock for this chain. */
130ef0ebfc3SJohn Baldwin #ifdef TURNSTILE_PROFILING
131ef0ebfc3SJohn Baldwin 	u_int	tc_depth;			/* Length of tc_queues. */
132ef0ebfc3SJohn Baldwin 	u_int	tc_max_depth;			/* Max length of tc_queues. */
133ef0ebfc3SJohn Baldwin #endif
134961a7b24SJohn Baldwin };
135961a7b24SJohn Baldwin 
136ef0ebfc3SJohn Baldwin #ifdef TURNSTILE_PROFILING
137ef0ebfc3SJohn Baldwin u_int turnstile_max_depth;
138ef0ebfc3SJohn Baldwin SYSCTL_NODE(_debug, OID_AUTO, turnstile, CTLFLAG_RD, 0, "turnstile profiling");
139ef0ebfc3SJohn Baldwin SYSCTL_NODE(_debug_turnstile, OID_AUTO, chains, CTLFLAG_RD, 0,
140ef0ebfc3SJohn Baldwin     "turnstile chain stats");
141ef0ebfc3SJohn Baldwin SYSCTL_UINT(_debug_turnstile, OID_AUTO, max_depth, CTLFLAG_RD,
142ef0ebfc3SJohn Baldwin     &turnstile_max_depth, 0, "maxmimum depth achieved of a single chain");
143ef0ebfc3SJohn Baldwin #endif
144961a7b24SJohn Baldwin static struct mtx td_contested_lock;
145961a7b24SJohn Baldwin static struct turnstile_chain turnstile_chains[TC_TABLESIZE];
146961a7b24SJohn Baldwin 
147c711aea6SPoul-Henning Kamp static MALLOC_DEFINE(M_TURNSTILE, "turnstiles", "turnstiles");
148c53c013bSJohn Baldwin 
149c53c013bSJohn Baldwin /*
1509ed346baSBosko Milekic  * Prototypes for non-exported routines.
1519ed346baSBosko Milekic  */
152961a7b24SJohn Baldwin static void	init_turnstile0(void *dummy);
15301bd10e1SJohn Baldwin #ifdef TURNSTILE_PROFILING
15401bd10e1SJohn Baldwin static void	init_turnstile_profiling(void *arg);
15501bd10e1SJohn Baldwin #endif
156f5c157d9SJohn Baldwin static void	propagate_priority(struct thread *td);
157f5c157d9SJohn Baldwin static int	turnstile_adjust_thread(struct turnstile *ts,
158f5c157d9SJohn Baldwin 		    struct thread *td);
1597aa4f685SJohn Baldwin static struct thread *turnstile_first_waiter(struct turnstile *ts);
160961a7b24SJohn Baldwin static void	turnstile_setowner(struct turnstile *ts, struct thread *owner);
16136412d79SJohn Baldwin 
162961a7b24SJohn Baldwin /*
163961a7b24SJohn Baldwin  * Walks the chain of turnstiles and their owners to propagate the priority
164961a7b24SJohn Baldwin  * of the thread being blocked to all the threads holding locks that have to
165961a7b24SJohn Baldwin  * release their locks before this thread can run again.
166961a7b24SJohn Baldwin  */
16736412d79SJohn Baldwin static void
168b40ce416SJulian Elischer propagate_priority(struct thread *td)
16936412d79SJohn Baldwin {
170961a7b24SJohn Baldwin 	struct turnstile_chain *tc;
171961a7b24SJohn Baldwin 	struct turnstile *ts;
172961a7b24SJohn Baldwin 	int pri;
17336412d79SJohn Baldwin 
1741bd0eefbSJohn Baldwin 	mtx_assert(&sched_lock, MA_OWNED);
175961a7b24SJohn Baldwin 	pri = td->td_priority;
176961a7b24SJohn Baldwin 	ts = td->td_blocked;
17736412d79SJohn Baldwin 	for (;;) {
178961a7b24SJohn Baldwin 		td = ts->ts_owner;
17936412d79SJohn Baldwin 
180b40ce416SJulian Elischer 		if (td == NULL) {
18136412d79SJohn Baldwin 			/*
1827aa4f685SJohn Baldwin 			 * This might be a read lock with no owner.  There's
1837aa4f685SJohn Baldwin 			 * not much we can do, so just bail.
18436412d79SJohn Baldwin 			 */
18536412d79SJohn Baldwin 			return;
18636412d79SJohn Baldwin 		}
1879ed346baSBosko Milekic 
188e602ba25SJulian Elischer 		MPASS(td->td_proc != NULL);
189b40ce416SJulian Elischer 		MPASS(td->td_proc->p_magic == P_MAGIC);
1901bd0eefbSJohn Baldwin 
191961a7b24SJohn Baldwin 		/*
1924b3b0413SJohn Baldwin 		 * If the thread is asleep, then we are probably about
1934b3b0413SJohn Baldwin 		 * to deadlock.  To make debugging this easier, just
1944b3b0413SJohn Baldwin 		 * panic and tell the user which thread misbehaved so
1954b3b0413SJohn Baldwin 		 * they can hopefully get a stack trace from the truly
1964b3b0413SJohn Baldwin 		 * misbehaving thread.
197961a7b24SJohn Baldwin 		 */
1984b3b0413SJohn Baldwin 		if (TD_IS_SLEEPING(td)) {
1994b3b0413SJohn Baldwin 			printf(
2004b3b0413SJohn Baldwin 		"Sleeping thread (tid %d, pid %d) owns a non-sleepable lock\n",
2014b3b0413SJohn Baldwin 			    td->td_tid, td->td_proc->p_pid);
2024b3b0413SJohn Baldwin #ifdef DDB
2034b3b0413SJohn Baldwin 			db_trace_thread(td, -1);
2044b3b0413SJohn Baldwin #endif
2054b3b0413SJohn Baldwin 			panic("sleeping thread");
2064b3b0413SJohn Baldwin 		}
207961a7b24SJohn Baldwin 
208961a7b24SJohn Baldwin 		/*
209961a7b24SJohn Baldwin 		 * If this thread already has higher priority than the
210961a7b24SJohn Baldwin 		 * thread that is being blocked, we are finished.
211961a7b24SJohn Baldwin 		 */
212961a7b24SJohn Baldwin 		if (td->td_priority <= pri)
213961a7b24SJohn Baldwin 			return;
2141bd0eefbSJohn Baldwin 
21536412d79SJohn Baldwin 		/*
216f5c157d9SJohn Baldwin 		 * Bump this thread's priority.
21736412d79SJohn Baldwin 		 */
218f5c157d9SJohn Baldwin 		sched_lend_prio(td, pri);
219f5c157d9SJohn Baldwin 
220f5c157d9SJohn Baldwin 		/*
221f5c157d9SJohn Baldwin 		 * If lock holder is actually running or on the run queue
222f5c157d9SJohn Baldwin 		 * then we are done.
223f5c157d9SJohn Baldwin 		 */
224f5c157d9SJohn Baldwin 		if (TD_IS_RUNNING(td) || TD_ON_RUNQ(td)) {
225f5c157d9SJohn Baldwin 			MPASS(td->td_blocked == NULL);
22636412d79SJohn Baldwin 			return;
22736412d79SJohn Baldwin 		}
228d5a08a60SJake Burkholder 
2291b43703bSJohn Baldwin #ifndef SMP
2301b43703bSJohn Baldwin 		/*
231b40ce416SJulian Elischer 		 * For UP, we check to see if td is curthread (this shouldn't
2321b43703bSJohn Baldwin 		 * ever happen however as it would mean we are in a deadlock.)
2331b43703bSJohn Baldwin 		 */
234b40ce416SJulian Elischer 		KASSERT(td != curthread, ("Deadlock detected"));
2351b43703bSJohn Baldwin #endif
2361b43703bSJohn Baldwin 
23736412d79SJohn Baldwin 		/*
238961a7b24SJohn Baldwin 		 * If we aren't blocked on a lock, we should be.
23936412d79SJohn Baldwin 		 */
240551cf4e1SJohn Baldwin 		KASSERT(TD_ON_LOCK(td), (
241f5c157d9SJohn Baldwin 		    "thread %d(%s):%d holds %s but isn't blocked on a lock\n",
242f5c157d9SJohn Baldwin 		    td->td_tid, td->td_proc->p_comm, td->td_state,
243961a7b24SJohn Baldwin 		    ts->ts_lockobj->lo_name));
24436412d79SJohn Baldwin 
24536412d79SJohn Baldwin 		/*
246961a7b24SJohn Baldwin 		 * Pick up the lock that td is blocked on.
24736412d79SJohn Baldwin 		 */
248961a7b24SJohn Baldwin 		ts = td->td_blocked;
249961a7b24SJohn Baldwin 		MPASS(ts != NULL);
250961a7b24SJohn Baldwin 		tc = TC_LOOKUP(ts->ts_lockobj);
251961a7b24SJohn Baldwin 		mtx_lock_spin(&tc->tc_lock);
25236412d79SJohn Baldwin 
253f5c157d9SJohn Baldwin 		/* Resort td on the list if needed. */
254f5c157d9SJohn Baldwin 		if (!turnstile_adjust_thread(ts, td)) {
255f5c157d9SJohn Baldwin 			mtx_unlock_spin(&tc->tc_lock);
256f5c157d9SJohn Baldwin 			return;
257f5c157d9SJohn Baldwin 		}
258f5c157d9SJohn Baldwin 		mtx_unlock_spin(&tc->tc_lock);
259f5c157d9SJohn Baldwin 	}
260f5c157d9SJohn Baldwin }
261f5c157d9SJohn Baldwin 
262f5c157d9SJohn Baldwin /*
263f5c157d9SJohn Baldwin  * Adjust the thread's position on a turnstile after its priority has been
264f5c157d9SJohn Baldwin  * changed.
265f5c157d9SJohn Baldwin  */
266f5c157d9SJohn Baldwin static int
267f5c157d9SJohn Baldwin turnstile_adjust_thread(struct turnstile *ts, struct thread *td)
268f5c157d9SJohn Baldwin {
269f5c157d9SJohn Baldwin 	struct turnstile_chain *tc;
270f5c157d9SJohn Baldwin 	struct thread *td1, *td2;
2717aa4f685SJohn Baldwin 	int queue;
272f5c157d9SJohn Baldwin 
273f5c157d9SJohn Baldwin 	mtx_assert(&sched_lock, MA_OWNED);
274f5c157d9SJohn Baldwin 	MPASS(TD_ON_LOCK(td));
275f5c157d9SJohn Baldwin 
27636412d79SJohn Baldwin 	/*
2776b6bd95eSJohn Baldwin 	 * This thread may not be blocked on this turnstile anymore
2786b6bd95eSJohn Baldwin 	 * but instead might already be woken up on another CPU
2796b6bd95eSJohn Baldwin 	 * that is waiting on sched_lock in turnstile_unpend() to
2806b6bd95eSJohn Baldwin 	 * finish waking this thread up.  We can detect this case
2816b6bd95eSJohn Baldwin 	 * by checking to see if this thread has been given a
2826b6bd95eSJohn Baldwin 	 * turnstile by either turnstile_signal() or
283ef2c0ba7SJohn Baldwin 	 * turnstile_broadcast().  In this case, treat the thread as
2846b6bd95eSJohn Baldwin 	 * if it was already running.
28579a13d01SJohn Baldwin 	 */
286f5c157d9SJohn Baldwin 	if (td->td_turnstile != NULL)
287f5c157d9SJohn Baldwin 		return (0);
28879a13d01SJohn Baldwin 
28979a13d01SJohn Baldwin 	/*
290f5c157d9SJohn Baldwin 	 * Check if the thread needs to be moved on the blocked chain.
291f5c157d9SJohn Baldwin 	 * It needs to be moved if either its priority is lower than
292f5c157d9SJohn Baldwin 	 * the previous thread or higher than the next thread.
29336412d79SJohn Baldwin 	 */
294f5c157d9SJohn Baldwin 	tc = TC_LOOKUP(ts->ts_lockobj);
295f5c157d9SJohn Baldwin 	mtx_assert(&tc->tc_lock, MA_OWNED);
296551cf4e1SJohn Baldwin 	td1 = TAILQ_PREV(td, threadqueue, td_lockq);
297f5c157d9SJohn Baldwin 	td2 = TAILQ_NEXT(td, td_lockq);
298f5c157d9SJohn Baldwin 	if ((td1 != NULL && td->td_priority < td1->td_priority) ||
299f5c157d9SJohn Baldwin 	    (td2 != NULL && td->td_priority > td2->td_priority)) {
30036412d79SJohn Baldwin 
30136412d79SJohn Baldwin 		/*
302b40ce416SJulian Elischer 		 * Remove thread from blocked chain and determine where
303f5c157d9SJohn Baldwin 		 * it should be moved to.
30436412d79SJohn Baldwin 		 */
3057aa4f685SJohn Baldwin 		queue = td->td_tsqueue;
3067aa4f685SJohn Baldwin 		MPASS(queue == TS_EXCLUSIVE_QUEUE || queue == TS_SHARED_QUEUE);
307961a7b24SJohn Baldwin 		mtx_lock_spin(&td_contested_lock);
3087aa4f685SJohn Baldwin 		TAILQ_REMOVE(&ts->ts_blocked[queue], td, td_lockq);
3097aa4f685SJohn Baldwin 		TAILQ_FOREACH(td1, &ts->ts_blocked[queue], td_lockq) {
310b40ce416SJulian Elischer 			MPASS(td1->td_proc->p_magic == P_MAGIC);
311f5c157d9SJohn Baldwin 			if (td1->td_priority > td->td_priority)
31236412d79SJohn Baldwin 				break;
31336412d79SJohn Baldwin 		}
3149ed346baSBosko Milekic 
315f5c157d9SJohn Baldwin 		if (td1 == NULL)
3167aa4f685SJohn Baldwin 			TAILQ_INSERT_TAIL(&ts->ts_blocked[queue], td, td_lockq);
317f5c157d9SJohn Baldwin 		else
318551cf4e1SJohn Baldwin 			TAILQ_INSERT_BEFORE(td1, td, td_lockq);
319961a7b24SJohn Baldwin 		mtx_unlock_spin(&td_contested_lock);
320f5c157d9SJohn Baldwin 		if (td1 == NULL)
321f5c157d9SJohn Baldwin 			CTR3(KTR_LOCK,
322f5c157d9SJohn Baldwin 		    "turnstile_adjust_thread: td %d put at tail on [%p] %s",
323f5c157d9SJohn Baldwin 			    td->td_tid, ts->ts_lockobj, ts->ts_lockobj->lo_name);
324f5c157d9SJohn Baldwin 		else
32536412d79SJohn Baldwin 			CTR4(KTR_LOCK,
326f5c157d9SJohn Baldwin 		    "turnstile_adjust_thread: td %d moved before %d on [%p] %s",
327f5c157d9SJohn Baldwin 			    td->td_tid, td1->td_tid, ts->ts_lockobj,
328f5c157d9SJohn Baldwin 			    ts->ts_lockobj->lo_name);
32936412d79SJohn Baldwin 	}
330f5c157d9SJohn Baldwin 	return (1);
33136412d79SJohn Baldwin }
33236412d79SJohn Baldwin 
3336c35e809SDag-Erling Smørgrav /*
334961a7b24SJohn Baldwin  * Early initialization of turnstiles.  This is not done via a SYSINIT()
335961a7b24SJohn Baldwin  * since this needs to be initialized very early when mutexes are first
336961a7b24SJohn Baldwin  * initialized.
3376283b7d0SJohn Baldwin  */
3386283b7d0SJohn Baldwin void
339961a7b24SJohn Baldwin init_turnstiles(void)
3406283b7d0SJohn Baldwin {
341961a7b24SJohn Baldwin 	int i;
3426283b7d0SJohn Baldwin 
343961a7b24SJohn Baldwin 	for (i = 0; i < TC_TABLESIZE; i++) {
344961a7b24SJohn Baldwin 		LIST_INIT(&turnstile_chains[i].tc_turnstiles);
345961a7b24SJohn Baldwin 		mtx_init(&turnstile_chains[i].tc_lock, "turnstile chain",
346961a7b24SJohn Baldwin 		    NULL, MTX_SPIN);
34701bd10e1SJohn Baldwin 	}
34801bd10e1SJohn Baldwin 	mtx_init(&td_contested_lock, "td_contested", NULL, MTX_SPIN);
349550d1c93SJohn Baldwin 	LIST_INIT(&thread0.td_contested);
35001bd10e1SJohn Baldwin 	thread0.td_turnstile = NULL;
35101bd10e1SJohn Baldwin }
35201bd10e1SJohn Baldwin 
353ef0ebfc3SJohn Baldwin #ifdef TURNSTILE_PROFILING
35401bd10e1SJohn Baldwin static void
35501bd10e1SJohn Baldwin init_turnstile_profiling(void *arg)
35601bd10e1SJohn Baldwin {
35701bd10e1SJohn Baldwin 	struct sysctl_oid *chain_oid;
35801bd10e1SJohn Baldwin 	char chain_name[10];
35901bd10e1SJohn Baldwin 	int i;
36001bd10e1SJohn Baldwin 
36101bd10e1SJohn Baldwin 	for (i = 0; i < TC_TABLESIZE; i++) {
362ef0ebfc3SJohn Baldwin 		snprintf(chain_name, sizeof(chain_name), "%d", i);
363ef0ebfc3SJohn Baldwin 		chain_oid = SYSCTL_ADD_NODE(NULL,
364ef0ebfc3SJohn Baldwin 		    SYSCTL_STATIC_CHILDREN(_debug_turnstile_chains), OID_AUTO,
365ef0ebfc3SJohn Baldwin 		    chain_name, CTLFLAG_RD, NULL, "turnstile chain stats");
366ef0ebfc3SJohn Baldwin 		SYSCTL_ADD_UINT(NULL, SYSCTL_CHILDREN(chain_oid), OID_AUTO,
367ef0ebfc3SJohn Baldwin 		    "depth", CTLFLAG_RD, &turnstile_chains[i].tc_depth, 0,
368ef0ebfc3SJohn Baldwin 		    NULL);
369ef0ebfc3SJohn Baldwin 		SYSCTL_ADD_UINT(NULL, SYSCTL_CHILDREN(chain_oid), OID_AUTO,
370ef0ebfc3SJohn Baldwin 		    "max_depth", CTLFLAG_RD, &turnstile_chains[i].tc_max_depth,
371ef0ebfc3SJohn Baldwin 		    0, NULL);
37201bd10e1SJohn Baldwin 	}
37301bd10e1SJohn Baldwin }
37401bd10e1SJohn Baldwin SYSINIT(turnstile_profiling, SI_SUB_LOCK, SI_ORDER_ANY,
37501bd10e1SJohn Baldwin     init_turnstile_profiling, NULL);
376ef0ebfc3SJohn Baldwin #endif
3776283b7d0SJohn Baldwin 
378961a7b24SJohn Baldwin static void
379961a7b24SJohn Baldwin init_turnstile0(void *dummy)
3806283b7d0SJohn Baldwin {
3816283b7d0SJohn Baldwin 
382961a7b24SJohn Baldwin 	thread0.td_turnstile = turnstile_alloc();
383961a7b24SJohn Baldwin }
384961a7b24SJohn Baldwin SYSINIT(turnstile0, SI_SUB_LOCK, SI_ORDER_ANY, init_turnstile0, NULL);
3856c35e809SDag-Erling Smørgrav 
386961a7b24SJohn Baldwin /*
387f5c157d9SJohn Baldwin  * Update a thread on the turnstile list after it's priority has been changed.
388f5c157d9SJohn Baldwin  * The old priority is passed in as an argument.
389f5c157d9SJohn Baldwin  */
390f5c157d9SJohn Baldwin void
391f5c157d9SJohn Baldwin turnstile_adjust(struct thread *td, u_char oldpri)
392f5c157d9SJohn Baldwin {
393f5c157d9SJohn Baldwin 	struct turnstile_chain *tc;
394f5c157d9SJohn Baldwin 	struct turnstile *ts;
395f5c157d9SJohn Baldwin 
396f5c157d9SJohn Baldwin 	mtx_assert(&sched_lock, MA_OWNED);
397f5c157d9SJohn Baldwin 	MPASS(TD_ON_LOCK(td));
398f5c157d9SJohn Baldwin 
399f5c157d9SJohn Baldwin 	/*
400f5c157d9SJohn Baldwin 	 * Pick up the lock that td is blocked on.
401f5c157d9SJohn Baldwin 	 */
402f5c157d9SJohn Baldwin 	ts = td->td_blocked;
403f5c157d9SJohn Baldwin 	MPASS(ts != NULL);
404f5c157d9SJohn Baldwin 	tc = TC_LOOKUP(ts->ts_lockobj);
405f5c157d9SJohn Baldwin 	mtx_lock_spin(&tc->tc_lock);
406f5c157d9SJohn Baldwin 
407f5c157d9SJohn Baldwin 	/* Resort the turnstile on the list. */
408f5c157d9SJohn Baldwin 	if (!turnstile_adjust_thread(ts, td)) {
409f5c157d9SJohn Baldwin 		mtx_unlock_spin(&tc->tc_lock);
410f5c157d9SJohn Baldwin 		return;
411f5c157d9SJohn Baldwin 	}
412f5c157d9SJohn Baldwin 
413f5c157d9SJohn Baldwin 	/*
414f5c157d9SJohn Baldwin 	 * If our priority was lowered and we are at the head of the
415f5c157d9SJohn Baldwin 	 * turnstile, then propagate our new priority up the chain.
416f5c157d9SJohn Baldwin 	 * Note that we currently don't try to revoke lent priorities
417f5c157d9SJohn Baldwin 	 * when our priority goes up.
418f5c157d9SJohn Baldwin 	 */
4197aa4f685SJohn Baldwin 	MPASS(td->td_tsqueue == TS_EXCLUSIVE_QUEUE ||
4207aa4f685SJohn Baldwin 	    td->td_tsqueue == TS_SHARED_QUEUE);
4217aa4f685SJohn Baldwin 	if (td == TAILQ_FIRST(&ts->ts_blocked[td->td_tsqueue]) &&
4227aa4f685SJohn Baldwin 	    td->td_priority < oldpri) {
423f5c157d9SJohn Baldwin 		mtx_unlock_spin(&tc->tc_lock);
42419c80b26SJohn Baldwin 		critical_enter();
425f5c157d9SJohn Baldwin 		propagate_priority(td);
42619c80b26SJohn Baldwin 		critical_exit();
427f5c157d9SJohn Baldwin 	} else
428f5c157d9SJohn Baldwin 		mtx_unlock_spin(&tc->tc_lock);
429f5c157d9SJohn Baldwin }
430f5c157d9SJohn Baldwin 
431f5c157d9SJohn Baldwin /*
432961a7b24SJohn Baldwin  * Set the owner of the lock this turnstile is attached to.
433961a7b24SJohn Baldwin  */
434961a7b24SJohn Baldwin static void
435961a7b24SJohn Baldwin turnstile_setowner(struct turnstile *ts, struct thread *owner)
436961a7b24SJohn Baldwin {
437961a7b24SJohn Baldwin 
438961a7b24SJohn Baldwin 	mtx_assert(&td_contested_lock, MA_OWNED);
439961a7b24SJohn Baldwin 	MPASS(ts->ts_owner == NULL);
4407aa4f685SJohn Baldwin 
4417aa4f685SJohn Baldwin 	/* A shared lock might not have an owner. */
4427aa4f685SJohn Baldwin 	if (owner == NULL)
4437aa4f685SJohn Baldwin 		return;
4447aa4f685SJohn Baldwin 
4457aa4f685SJohn Baldwin 	MPASS(owner->td_proc->p_magic == P_MAGIC);
446961a7b24SJohn Baldwin 	ts->ts_owner = owner;
447961a7b24SJohn Baldwin 	LIST_INSERT_HEAD(&owner->td_contested, ts, ts_link);
448961a7b24SJohn Baldwin }
449961a7b24SJohn Baldwin 
450961a7b24SJohn Baldwin /*
451961a7b24SJohn Baldwin  * Malloc a turnstile for a new thread, initialize it and return it.
452961a7b24SJohn Baldwin  */
453961a7b24SJohn Baldwin struct turnstile *
454961a7b24SJohn Baldwin turnstile_alloc(void)
455961a7b24SJohn Baldwin {
456961a7b24SJohn Baldwin 	struct turnstile *ts;
457961a7b24SJohn Baldwin 
458961a7b24SJohn Baldwin 	ts = malloc(sizeof(struct turnstile), M_TURNSTILE, M_WAITOK | M_ZERO);
4597aa4f685SJohn Baldwin 	TAILQ_INIT(&ts->ts_blocked[TS_EXCLUSIVE_QUEUE]);
4607aa4f685SJohn Baldwin 	TAILQ_INIT(&ts->ts_blocked[TS_SHARED_QUEUE]);
461961a7b24SJohn Baldwin 	TAILQ_INIT(&ts->ts_pending);
462961a7b24SJohn Baldwin 	LIST_INIT(&ts->ts_free);
463961a7b24SJohn Baldwin 	return (ts);
464961a7b24SJohn Baldwin }
465961a7b24SJohn Baldwin 
466961a7b24SJohn Baldwin /*
467961a7b24SJohn Baldwin  * Free a turnstile when a thread is destroyed.
468961a7b24SJohn Baldwin  */
469961a7b24SJohn Baldwin void
470961a7b24SJohn Baldwin turnstile_free(struct turnstile *ts)
471961a7b24SJohn Baldwin {
472961a7b24SJohn Baldwin 
473961a7b24SJohn Baldwin 	MPASS(ts != NULL);
4747aa4f685SJohn Baldwin 	MPASS(TAILQ_EMPTY(&ts->ts_blocked[TS_EXCLUSIVE_QUEUE]));
4757aa4f685SJohn Baldwin 	MPASS(TAILQ_EMPTY(&ts->ts_blocked[TS_SHARED_QUEUE]));
476961a7b24SJohn Baldwin 	MPASS(TAILQ_EMPTY(&ts->ts_pending));
477961a7b24SJohn Baldwin 	free(ts, M_TURNSTILE);
478961a7b24SJohn Baldwin }
479961a7b24SJohn Baldwin 
480961a7b24SJohn Baldwin /*
4812ff0e645SJohn Baldwin  * Lock the turnstile chain associated with the specified lock.
4822ff0e645SJohn Baldwin  */
4832ff0e645SJohn Baldwin void
4842ff0e645SJohn Baldwin turnstile_lock(struct lock_object *lock)
4852ff0e645SJohn Baldwin {
4862ff0e645SJohn Baldwin 	struct turnstile_chain *tc;
4872ff0e645SJohn Baldwin 
4882ff0e645SJohn Baldwin 	tc = TC_LOOKUP(lock);
4892ff0e645SJohn Baldwin 	mtx_lock_spin(&tc->tc_lock);
4902ff0e645SJohn Baldwin }
4912ff0e645SJohn Baldwin 
4922ff0e645SJohn Baldwin /*
493961a7b24SJohn Baldwin  * Look up the turnstile for a lock in the hash table locking the associated
4942ff0e645SJohn Baldwin  * turnstile chain along the way.  If no turnstile is found in the hash
4952ff0e645SJohn Baldwin  * table, NULL is returned.
496961a7b24SJohn Baldwin  */
497961a7b24SJohn Baldwin struct turnstile *
498961a7b24SJohn Baldwin turnstile_lookup(struct lock_object *lock)
499961a7b24SJohn Baldwin {
500961a7b24SJohn Baldwin 	struct turnstile_chain *tc;
501961a7b24SJohn Baldwin 	struct turnstile *ts;
502961a7b24SJohn Baldwin 
503961a7b24SJohn Baldwin 	tc = TC_LOOKUP(lock);
5042ff0e645SJohn Baldwin 	mtx_assert(&tc->tc_lock, MA_OWNED);
505961a7b24SJohn Baldwin 	LIST_FOREACH(ts, &tc->tc_turnstiles, ts_hash)
506961a7b24SJohn Baldwin 		if (ts->ts_lockobj == lock)
507961a7b24SJohn Baldwin 			return (ts);
508961a7b24SJohn Baldwin 	return (NULL);
509961a7b24SJohn Baldwin }
510961a7b24SJohn Baldwin 
511961a7b24SJohn Baldwin /*
512961a7b24SJohn Baldwin  * Unlock the turnstile chain associated with a given lock.
513961a7b24SJohn Baldwin  */
514961a7b24SJohn Baldwin void
515961a7b24SJohn Baldwin turnstile_release(struct lock_object *lock)
516961a7b24SJohn Baldwin {
517961a7b24SJohn Baldwin 	struct turnstile_chain *tc;
518961a7b24SJohn Baldwin 
519961a7b24SJohn Baldwin 	tc = TC_LOOKUP(lock);
520961a7b24SJohn Baldwin 	mtx_unlock_spin(&tc->tc_lock);
521961a7b24SJohn Baldwin }
522961a7b24SJohn Baldwin 
523961a7b24SJohn Baldwin /*
5247aa4f685SJohn Baldwin  * Return a pointer to the thread waiting on this turnstile with the
5257aa4f685SJohn Baldwin  * most important priority or NULL if the turnstile has no waiters.
5267aa4f685SJohn Baldwin  */
5277aa4f685SJohn Baldwin static struct thread *
5287aa4f685SJohn Baldwin turnstile_first_waiter(struct turnstile *ts)
5297aa4f685SJohn Baldwin {
5307aa4f685SJohn Baldwin 	struct thread *std, *xtd;
5317aa4f685SJohn Baldwin 
5327aa4f685SJohn Baldwin 	std = TAILQ_FIRST(&ts->ts_blocked[TS_SHARED_QUEUE]);
5337aa4f685SJohn Baldwin 	xtd = TAILQ_FIRST(&ts->ts_blocked[TS_EXCLUSIVE_QUEUE]);
5347aa4f685SJohn Baldwin 	if (xtd == NULL || (std != NULL && std->td_priority < xtd->td_priority))
5357aa4f685SJohn Baldwin 		return (std);
5367aa4f685SJohn Baldwin 	return (xtd);
5377aa4f685SJohn Baldwin }
5387aa4f685SJohn Baldwin 
5397aa4f685SJohn Baldwin /*
540961a7b24SJohn Baldwin  * Take ownership of a turnstile and adjust the priority of the new
541961a7b24SJohn Baldwin  * owner appropriately.
542961a7b24SJohn Baldwin  */
543961a7b24SJohn Baldwin void
5442ff0e645SJohn Baldwin turnstile_claim(struct lock_object *lock)
545961a7b24SJohn Baldwin {
546961a7b24SJohn Baldwin 	struct turnstile_chain *tc;
5472ff0e645SJohn Baldwin 	struct turnstile *ts;
548961a7b24SJohn Baldwin 	struct thread *td, *owner;
549961a7b24SJohn Baldwin 
5502ff0e645SJohn Baldwin 	tc = TC_LOOKUP(lock);
551961a7b24SJohn Baldwin 	mtx_assert(&tc->tc_lock, MA_OWNED);
5522ff0e645SJohn Baldwin 	ts = turnstile_lookup(lock);
5532ff0e645SJohn Baldwin 	MPASS(ts != NULL);
554961a7b24SJohn Baldwin 
555961a7b24SJohn Baldwin 	owner = curthread;
556961a7b24SJohn Baldwin 	mtx_lock_spin(&td_contested_lock);
557961a7b24SJohn Baldwin 	turnstile_setowner(ts, owner);
558961a7b24SJohn Baldwin 	mtx_unlock_spin(&td_contested_lock);
559961a7b24SJohn Baldwin 
5607aa4f685SJohn Baldwin 	td = turnstile_first_waiter(ts);
561961a7b24SJohn Baldwin 	MPASS(td != NULL);
562961a7b24SJohn Baldwin 	MPASS(td->td_proc->p_magic == P_MAGIC);
563961a7b24SJohn Baldwin 	mtx_unlock_spin(&tc->tc_lock);
564961a7b24SJohn Baldwin 
565961a7b24SJohn Baldwin 	/*
566961a7b24SJohn Baldwin 	 * Update the priority of the new owner if needed.
567961a7b24SJohn Baldwin 	 */
568961a7b24SJohn Baldwin 	mtx_lock_spin(&sched_lock);
569961a7b24SJohn Baldwin 	if (td->td_priority < owner->td_priority)
570f5c157d9SJohn Baldwin 		sched_lend_prio(owner, td->td_priority);
571961a7b24SJohn Baldwin 	mtx_unlock_spin(&sched_lock);
572961a7b24SJohn Baldwin }
573961a7b24SJohn Baldwin 
574961a7b24SJohn Baldwin /*
5752ff0e645SJohn Baldwin  * Block the current thread on the turnstile assicated with 'lock'.  This
5762ff0e645SJohn Baldwin  * function will context switch and not return until this thread has been
5772ff0e645SJohn Baldwin  * woken back up.  This function must be called with the appropriate
5782ff0e645SJohn Baldwin  * turnstile chain locked and will return with it unlocked.
579961a7b24SJohn Baldwin  */
580961a7b24SJohn Baldwin void
5817aa4f685SJohn Baldwin turnstile_wait(struct lock_object *lock, struct thread *owner, int queue)
582961a7b24SJohn Baldwin {
583961a7b24SJohn Baldwin 	struct turnstile_chain *tc;
5842ff0e645SJohn Baldwin 	struct turnstile *ts;
585961a7b24SJohn Baldwin 	struct thread *td, *td1;
586961a7b24SJohn Baldwin 
587961a7b24SJohn Baldwin 	td = curthread;
588961a7b24SJohn Baldwin 	tc = TC_LOOKUP(lock);
589961a7b24SJohn Baldwin 	mtx_assert(&tc->tc_lock, MA_OWNED);
590961a7b24SJohn Baldwin 	MPASS(td->td_turnstile != NULL);
5917aa4f685SJohn Baldwin 	if (queue == TS_SHARED_QUEUE)
592961a7b24SJohn Baldwin 		MPASS(owner != NULL);
5937aa4f685SJohn Baldwin 	if (owner)
594961a7b24SJohn Baldwin 		MPASS(owner->td_proc->p_magic == P_MAGIC);
5957aa4f685SJohn Baldwin 	MPASS(queue == TS_SHARED_QUEUE || queue == TS_EXCLUSIVE_QUEUE);
596961a7b24SJohn Baldwin 
5972ff0e645SJohn Baldwin 	/* Look up the turnstile associated with the lock 'lock'. */
5982ff0e645SJohn Baldwin 	ts = turnstile_lookup(lock);
5992ff0e645SJohn Baldwin 
6002ff0e645SJohn Baldwin 	/*
6012ff0e645SJohn Baldwin 	 * If the lock does not already have a turnstile, use this thread's
6022ff0e645SJohn Baldwin 	 * turnstile.  Otherwise insert the current thread into the
6032ff0e645SJohn Baldwin 	 * turnstile already in use by this lock.
6042ff0e645SJohn Baldwin 	 */
605961a7b24SJohn Baldwin 	if (ts == NULL) {
606ef0ebfc3SJohn Baldwin #ifdef TURNSTILE_PROFILING
607ef0ebfc3SJohn Baldwin 		tc->tc_depth++;
608ef0ebfc3SJohn Baldwin 		if (tc->tc_depth > tc->tc_max_depth) {
609ef0ebfc3SJohn Baldwin 			tc->tc_max_depth = tc->tc_depth;
610ef0ebfc3SJohn Baldwin 			if (tc->tc_max_depth > turnstile_max_depth)
611ef0ebfc3SJohn Baldwin 				turnstile_max_depth = tc->tc_max_depth;
612ef0ebfc3SJohn Baldwin 		}
613ef0ebfc3SJohn Baldwin #endif
614961a7b24SJohn Baldwin 		ts = td->td_turnstile;
615961a7b24SJohn Baldwin 		LIST_INSERT_HEAD(&tc->tc_turnstiles, ts, ts_hash);
616961a7b24SJohn Baldwin 		KASSERT(TAILQ_EMPTY(&ts->ts_pending),
617961a7b24SJohn Baldwin 		    ("thread's turnstile has pending threads"));
6187aa4f685SJohn Baldwin 		KASSERT(TAILQ_EMPTY(&ts->ts_blocked[TS_EXCLUSIVE_QUEUE]),
6197aa4f685SJohn Baldwin 		    ("thread's turnstile has exclusive waiters"));
6207aa4f685SJohn Baldwin 		KASSERT(TAILQ_EMPTY(&ts->ts_blocked[TS_SHARED_QUEUE]),
6217aa4f685SJohn Baldwin 		    ("thread's turnstile has shared waiters"));
622961a7b24SJohn Baldwin 		KASSERT(LIST_EMPTY(&ts->ts_free),
623961a7b24SJohn Baldwin 		    ("thread's turnstile has a non-empty free list"));
624961a7b24SJohn Baldwin 		KASSERT(ts->ts_lockobj == NULL, ("stale ts_lockobj pointer"));
625961a7b24SJohn Baldwin 		ts->ts_lockobj = lock;
626961a7b24SJohn Baldwin 		mtx_lock_spin(&td_contested_lock);
6277aa4f685SJohn Baldwin 		TAILQ_INSERT_TAIL(&ts->ts_blocked[queue], td, td_lockq);
628961a7b24SJohn Baldwin 		turnstile_setowner(ts, owner);
629961a7b24SJohn Baldwin 		mtx_unlock_spin(&td_contested_lock);
630961a7b24SJohn Baldwin 	} else {
6317aa4f685SJohn Baldwin 		TAILQ_FOREACH(td1, &ts->ts_blocked[queue], td_lockq)
632961a7b24SJohn Baldwin 			if (td1->td_priority > td->td_priority)
6336c35e809SDag-Erling Smørgrav 				break;
634961a7b24SJohn Baldwin 		mtx_lock_spin(&td_contested_lock);
635961a7b24SJohn Baldwin 		if (td1 != NULL)
636961a7b24SJohn Baldwin 			TAILQ_INSERT_BEFORE(td1, td, td_lockq);
637961a7b24SJohn Baldwin 		else
6387aa4f685SJohn Baldwin 			TAILQ_INSERT_TAIL(&ts->ts_blocked[queue], td, td_lockq);
6397aa4f685SJohn Baldwin 		MPASS(owner == ts->ts_owner);
640961a7b24SJohn Baldwin 		mtx_unlock_spin(&td_contested_lock);
641961a7b24SJohn Baldwin 		MPASS(td->td_turnstile != NULL);
642961a7b24SJohn Baldwin 		LIST_INSERT_HEAD(&ts->ts_free, td->td_turnstile, ts_hash);
6436c35e809SDag-Erling Smørgrav 	}
644961a7b24SJohn Baldwin 	td->td_turnstile = NULL;
645961a7b24SJohn Baldwin 	mtx_unlock_spin(&tc->tc_lock);
64636412d79SJohn Baldwin 
6479ed346baSBosko Milekic 	mtx_lock_spin(&sched_lock);
64836412d79SJohn Baldwin 	/*
649961a7b24SJohn Baldwin 	 * Handle race condition where a thread on another CPU that owns
650961a7b24SJohn Baldwin 	 * lock 'lock' could have woken us in between us dropping the
651961a7b24SJohn Baldwin 	 * turnstile chain lock and acquiring the sched_lock.
65236412d79SJohn Baldwin 	 */
653961a7b24SJohn Baldwin 	if (td->td_flags & TDF_TSNOBLOCK) {
654961a7b24SJohn Baldwin 		td->td_flags &= ~TDF_TSNOBLOCK;
6559ed346baSBosko Milekic 		mtx_unlock_spin(&sched_lock);
65636412d79SJohn Baldwin 		return;
65736412d79SJohn Baldwin 	}
6589ed346baSBosko Milekic 
65936412d79SJohn Baldwin #ifdef notyet
66036412d79SJohn Baldwin 	/*
6619ed346baSBosko Milekic 	 * If we're borrowing an interrupted thread's VM context, we
6629ed346baSBosko Milekic 	 * must clean up before going to sleep.
66336412d79SJohn Baldwin 	 */
664b40ce416SJulian Elischer 	if (td->td_ithd != NULL) {
665b40ce416SJulian Elischer 		struct ithd *it = td->td_ithd;
66636412d79SJohn Baldwin 
66736412d79SJohn Baldwin 		if (it->it_interrupted) {
668961a7b24SJohn Baldwin 			if (LOCK_LOG_TEST(lock, 0))
669961a7b24SJohn Baldwin 				CTR3(KTR_LOCK, "%s: %p interrupted %p",
670961a7b24SJohn Baldwin 				    __func__, it, it->it_interrupted);
67136412d79SJohn Baldwin 			intr_thd_fixup(it);
67236412d79SJohn Baldwin 		}
67336412d79SJohn Baldwin 	}
67436412d79SJohn Baldwin #endif
67536412d79SJohn Baldwin 
676961a7b24SJohn Baldwin 	/* Save who we are blocked on and switch. */
6777aa4f685SJohn Baldwin 	td->td_tsqueue = queue;
678961a7b24SJohn Baldwin 	td->td_blocked = ts;
679961a7b24SJohn Baldwin 	td->td_lockname = lock->lo_name;
680551cf4e1SJohn Baldwin 	TD_SET_LOCK(td);
68119c80b26SJohn Baldwin 	critical_enter();
682b40ce416SJulian Elischer 	propagate_priority(td);
68319c80b26SJohn Baldwin 	critical_exit();
6849ed346baSBosko Milekic 
685961a7b24SJohn Baldwin 	if (LOCK_LOG_TEST(lock, 0))
686f5c157d9SJohn Baldwin 		CTR4(KTR_LOCK, "%s: td %d blocked on [%p] %s", __func__,
687f5c157d9SJohn Baldwin 		    td->td_tid, lock, lock->lo_name);
6889ed346baSBosko Milekic 
689bf0acc27SJohn Baldwin 	mi_switch(SW_VOL, NULL);
6909ed346baSBosko Milekic 
691961a7b24SJohn Baldwin 	if (LOCK_LOG_TEST(lock, 0))
692f5c157d9SJohn Baldwin 		CTR4(KTR_LOCK, "%s: td %d free from blocked on [%p] %s",
693f5c157d9SJohn Baldwin 		    __func__, td->td_tid, lock, lock->lo_name);
6949ed346baSBosko Milekic 
6959ed346baSBosko Milekic 	mtx_unlock_spin(&sched_lock);
69636412d79SJohn Baldwin }
6979ed346baSBosko Milekic 
698961a7b24SJohn Baldwin /*
699961a7b24SJohn Baldwin  * Pick the highest priority thread on this turnstile and put it on the
700961a7b24SJohn Baldwin  * pending list.  This must be called with the turnstile chain locked.
701961a7b24SJohn Baldwin  */
702961a7b24SJohn Baldwin int
7037aa4f685SJohn Baldwin turnstile_signal(struct turnstile *ts, int queue)
704961a7b24SJohn Baldwin {
705961a7b24SJohn Baldwin 	struct turnstile_chain *tc;
706961a7b24SJohn Baldwin 	struct thread *td;
707961a7b24SJohn Baldwin 	int empty;
708961a7b24SJohn Baldwin 
709961a7b24SJohn Baldwin 	MPASS(ts != NULL);
710961a7b24SJohn Baldwin 	MPASS(curthread->td_proc->p_magic == P_MAGIC);
7117aa4f685SJohn Baldwin 	MPASS(ts->ts_owner == curthread ||
7127aa4f685SJohn Baldwin 	    (queue == TS_EXCLUSIVE_QUEUE && ts->ts_owner == NULL));
713961a7b24SJohn Baldwin 	tc = TC_LOOKUP(ts->ts_lockobj);
714961a7b24SJohn Baldwin 	mtx_assert(&tc->tc_lock, MA_OWNED);
7157aa4f685SJohn Baldwin 	MPASS(queue == TS_SHARED_QUEUE || queue == TS_EXCLUSIVE_QUEUE);
7169ed346baSBosko Milekic 
7179ed346baSBosko Milekic 	/*
718961a7b24SJohn Baldwin 	 * Pick the highest priority thread blocked on this lock and
719961a7b24SJohn Baldwin 	 * move it to the pending list.
7209ed346baSBosko Milekic 	 */
7217aa4f685SJohn Baldwin 	td = TAILQ_FIRST(&ts->ts_blocked[queue]);
722b40ce416SJulian Elischer 	MPASS(td->td_proc->p_magic == P_MAGIC);
723961a7b24SJohn Baldwin 	mtx_lock_spin(&td_contested_lock);
7247aa4f685SJohn Baldwin 	TAILQ_REMOVE(&ts->ts_blocked[queue], td, td_lockq);
725961a7b24SJohn Baldwin 	mtx_unlock_spin(&td_contested_lock);
726961a7b24SJohn Baldwin 	TAILQ_INSERT_TAIL(&ts->ts_pending, td, td_lockq);
7279ed346baSBosko Milekic 
728961a7b24SJohn Baldwin 	/*
729961a7b24SJohn Baldwin 	 * If the turnstile is now empty, remove it from its chain and
730961a7b24SJohn Baldwin 	 * give it to the about-to-be-woken thread.  Otherwise take a
731961a7b24SJohn Baldwin 	 * turnstile from the free list and give it to the thread.
732961a7b24SJohn Baldwin 	 */
7337aa4f685SJohn Baldwin 	empty = TAILQ_EMPTY(&ts->ts_blocked[TS_EXCLUSIVE_QUEUE]) &&
7347aa4f685SJohn Baldwin 	    TAILQ_EMPTY(&ts->ts_blocked[TS_SHARED_QUEUE]);
735ef0ebfc3SJohn Baldwin 	if (empty) {
736961a7b24SJohn Baldwin 		MPASS(LIST_EMPTY(&ts->ts_free));
737ef0ebfc3SJohn Baldwin #ifdef TURNSTILE_PROFILING
738ef0ebfc3SJohn Baldwin 		tc->tc_depth--;
739ef0ebfc3SJohn Baldwin #endif
740ef0ebfc3SJohn Baldwin 	} else
741961a7b24SJohn Baldwin 		ts = LIST_FIRST(&ts->ts_free);
742da1d503bSJohn Baldwin 	MPASS(ts != NULL);
743961a7b24SJohn Baldwin 	LIST_REMOVE(ts, ts_hash);
744961a7b24SJohn Baldwin 	td->td_turnstile = ts;
7459ed346baSBosko Milekic 
746961a7b24SJohn Baldwin 	return (empty);
747961a7b24SJohn Baldwin }
748961a7b24SJohn Baldwin 
749961a7b24SJohn Baldwin /*
750961a7b24SJohn Baldwin  * Put all blocked threads on the pending list.  This must be called with
751961a7b24SJohn Baldwin  * the turnstile chain locked.
752961a7b24SJohn Baldwin  */
753961a7b24SJohn Baldwin void
7547aa4f685SJohn Baldwin turnstile_broadcast(struct turnstile *ts, int queue)
755961a7b24SJohn Baldwin {
756961a7b24SJohn Baldwin 	struct turnstile_chain *tc;
757961a7b24SJohn Baldwin 	struct turnstile *ts1;
758961a7b24SJohn Baldwin 	struct thread *td;
759961a7b24SJohn Baldwin 
760961a7b24SJohn Baldwin 	MPASS(ts != NULL);
761961a7b24SJohn Baldwin 	MPASS(curthread->td_proc->p_magic == P_MAGIC);
7627aa4f685SJohn Baldwin 	MPASS(ts->ts_owner == curthread ||
7637aa4f685SJohn Baldwin 	    (queue == TS_EXCLUSIVE_QUEUE && ts->ts_owner == NULL));
764961a7b24SJohn Baldwin 	tc = TC_LOOKUP(ts->ts_lockobj);
765961a7b24SJohn Baldwin 	mtx_assert(&tc->tc_lock, MA_OWNED);
7667aa4f685SJohn Baldwin 	MPASS(queue == TS_SHARED_QUEUE || queue == TS_EXCLUSIVE_QUEUE);
767961a7b24SJohn Baldwin 
768961a7b24SJohn Baldwin 	/*
769961a7b24SJohn Baldwin 	 * Transfer the blocked list to the pending list.
770961a7b24SJohn Baldwin 	 */
771961a7b24SJohn Baldwin 	mtx_lock_spin(&td_contested_lock);
7727aa4f685SJohn Baldwin 	TAILQ_CONCAT(&ts->ts_pending, &ts->ts_blocked[queue], td_lockq);
773961a7b24SJohn Baldwin 	mtx_unlock_spin(&td_contested_lock);
774961a7b24SJohn Baldwin 
775961a7b24SJohn Baldwin 	/*
776961a7b24SJohn Baldwin 	 * Give a turnstile to each thread.  The last thread gets
7777aa4f685SJohn Baldwin 	 * this turnstile if the turnstile is empty.
778961a7b24SJohn Baldwin 	 */
779961a7b24SJohn Baldwin 	TAILQ_FOREACH(td, &ts->ts_pending, td_lockq) {
780961a7b24SJohn Baldwin 		if (LIST_EMPTY(&ts->ts_free)) {
781961a7b24SJohn Baldwin 			MPASS(TAILQ_NEXT(td, td_lockq) == NULL);
782961a7b24SJohn Baldwin 			ts1 = ts;
783ef0ebfc3SJohn Baldwin #ifdef TURNSTILE_PROFILING
784ef0ebfc3SJohn Baldwin 			tc->tc_depth--;
785ef0ebfc3SJohn Baldwin #endif
78636412d79SJohn Baldwin 		} else
787961a7b24SJohn Baldwin 			ts1 = LIST_FIRST(&ts->ts_free);
788da1d503bSJohn Baldwin 		MPASS(ts1 != NULL);
789961a7b24SJohn Baldwin 		LIST_REMOVE(ts1, ts_hash);
790961a7b24SJohn Baldwin 		td->td_turnstile = ts1;
791961a7b24SJohn Baldwin 	}
792961a7b24SJohn Baldwin }
7939ed346baSBosko Milekic 
794961a7b24SJohn Baldwin /*
795961a7b24SJohn Baldwin  * Wakeup all threads on the pending list and adjust the priority of the
796961a7b24SJohn Baldwin  * current thread appropriately.  This must be called with the turnstile
797961a7b24SJohn Baldwin  * chain locked.
798961a7b24SJohn Baldwin  */
799961a7b24SJohn Baldwin void
8007aa4f685SJohn Baldwin turnstile_unpend(struct turnstile *ts, int owner_type)
801961a7b24SJohn Baldwin {
802961a7b24SJohn Baldwin 	TAILQ_HEAD( ,thread) pending_threads;
803961a7b24SJohn Baldwin 	struct turnstile_chain *tc;
804961a7b24SJohn Baldwin 	struct thread *td;
805f5c157d9SJohn Baldwin 	u_char cp, pri;
806961a7b24SJohn Baldwin 
807961a7b24SJohn Baldwin 	MPASS(ts != NULL);
8087aa4f685SJohn Baldwin 	MPASS(ts->ts_owner == curthread ||
8097aa4f685SJohn Baldwin 	    (owner_type == TS_SHARED_LOCK && ts->ts_owner == NULL));
810961a7b24SJohn Baldwin 	tc = TC_LOOKUP(ts->ts_lockobj);
811961a7b24SJohn Baldwin 	mtx_assert(&tc->tc_lock, MA_OWNED);
812961a7b24SJohn Baldwin 	MPASS(!TAILQ_EMPTY(&ts->ts_pending));
813961a7b24SJohn Baldwin 
814961a7b24SJohn Baldwin 	/*
815961a7b24SJohn Baldwin 	 * Move the list of pending threads out of the turnstile and
816961a7b24SJohn Baldwin 	 * into a local variable.
817961a7b24SJohn Baldwin 	 */
818961a7b24SJohn Baldwin 	TAILQ_INIT(&pending_threads);
819961a7b24SJohn Baldwin 	TAILQ_CONCAT(&pending_threads, &ts->ts_pending, td_lockq);
820961a7b24SJohn Baldwin #ifdef INVARIANTS
8217aa4f685SJohn Baldwin 	if (TAILQ_EMPTY(&ts->ts_blocked[TS_EXCLUSIVE_QUEUE]) &&
8227aa4f685SJohn Baldwin 	    TAILQ_EMPTY(&ts->ts_blocked[TS_SHARED_QUEUE]))
823961a7b24SJohn Baldwin 		ts->ts_lockobj = NULL;
824961a7b24SJohn Baldwin #endif
825961a7b24SJohn Baldwin 
826961a7b24SJohn Baldwin 	/*
827961a7b24SJohn Baldwin 	 * Remove the turnstile from this thread's list of contested locks
828961a7b24SJohn Baldwin 	 * since this thread doesn't own it anymore.  New threads will
829961a7b24SJohn Baldwin 	 * not be blocking on the turnstile until it is claimed by a new
8307aa4f685SJohn Baldwin 	 * owner.  There might not be a current owner if this is a shared
8317aa4f685SJohn Baldwin 	 * lock.
832961a7b24SJohn Baldwin 	 */
8337aa4f685SJohn Baldwin 	if (ts->ts_owner != NULL) {
834961a7b24SJohn Baldwin 		mtx_lock_spin(&td_contested_lock);
835961a7b24SJohn Baldwin 		ts->ts_owner = NULL;
836961a7b24SJohn Baldwin 		LIST_REMOVE(ts, ts_link);
837961a7b24SJohn Baldwin 		mtx_unlock_spin(&td_contested_lock);
8387aa4f685SJohn Baldwin 	}
839b8597527SJohn Baldwin 	critical_enter();
840961a7b24SJohn Baldwin 	mtx_unlock_spin(&tc->tc_lock);
841961a7b24SJohn Baldwin 
842961a7b24SJohn Baldwin 	/*
843961a7b24SJohn Baldwin 	 * Adjust the priority of curthread based on other contested
844961a7b24SJohn Baldwin 	 * locks it owns.  Don't lower the priority below the base
845961a7b24SJohn Baldwin 	 * priority however.
846961a7b24SJohn Baldwin 	 */
847961a7b24SJohn Baldwin 	td = curthread;
848d5a08a60SJake Burkholder 	pri = PRI_MAX;
849961a7b24SJohn Baldwin 	mtx_lock_spin(&sched_lock);
850961a7b24SJohn Baldwin 	mtx_lock_spin(&td_contested_lock);
851961a7b24SJohn Baldwin 	LIST_FOREACH(ts, &td->td_contested, ts_link) {
8527aa4f685SJohn Baldwin 		cp = turnstile_first_waiter(ts)->td_priority;
85336412d79SJohn Baldwin 		if (cp < pri)
85436412d79SJohn Baldwin 			pri = cp;
85536412d79SJohn Baldwin 	}
856961a7b24SJohn Baldwin 	mtx_unlock_spin(&td_contested_lock);
857f5c157d9SJohn Baldwin 	sched_unlend_prio(td, pri);
8589ed346baSBosko Milekic 
859961a7b24SJohn Baldwin 	/*
860961a7b24SJohn Baldwin 	 * Wake up all the pending threads.  If a thread is not blocked
861961a7b24SJohn Baldwin 	 * on a lock, then it is currently executing on another CPU in
86267ba8678SJohn Baldwin 	 * turnstile_wait() or sitting on a run queue waiting to resume
86367ba8678SJohn Baldwin 	 * in turnstile_wait().  Set a flag to force it to try to acquire
864961a7b24SJohn Baldwin 	 * the lock again instead of blocking.
865961a7b24SJohn Baldwin 	 */
866961a7b24SJohn Baldwin 	while (!TAILQ_EMPTY(&pending_threads)) {
867961a7b24SJohn Baldwin 		td = TAILQ_FIRST(&pending_threads);
868961a7b24SJohn Baldwin 		TAILQ_REMOVE(&pending_threads, td, td_lockq);
869961a7b24SJohn Baldwin 		MPASS(td->td_proc->p_magic == P_MAGIC);
870961a7b24SJohn Baldwin 		if (TD_ON_LOCK(td)) {
871961a7b24SJohn Baldwin 			td->td_blocked = NULL;
872961a7b24SJohn Baldwin 			td->td_lockname = NULL;
8737aa4f685SJohn Baldwin #ifdef INVARIANTS
8747aa4f685SJohn Baldwin 			td->td_tsqueue = 0xff;
8757aa4f685SJohn Baldwin #endif
876961a7b24SJohn Baldwin 			TD_CLR_LOCK(td);
877961a7b24SJohn Baldwin 			MPASS(TD_CAN_RUN(td));
8782630e4c9SJulian Elischer 			setrunqueue(td, SRQ_BORING);
879961a7b24SJohn Baldwin 		} else {
880961a7b24SJohn Baldwin 			td->td_flags |= TDF_TSNOBLOCK;
88167ba8678SJohn Baldwin 			MPASS(TD_IS_RUNNING(td) || TD_ON_RUNQ(td));
882961a7b24SJohn Baldwin 		}
883961a7b24SJohn Baldwin 	}
884b8597527SJohn Baldwin 	critical_exit();
885e0817317SJulian Elischer 	mtx_unlock_spin(&sched_lock);
8869ed346baSBosko Milekic }
8879ed346baSBosko Milekic 
8889ed346baSBosko Milekic /*
889f1a4b852SJohn Baldwin  * Give up ownership of a turnstile.  This must be called with the
890f1a4b852SJohn Baldwin  * turnstile chain locked.
891f1a4b852SJohn Baldwin  */
892f1a4b852SJohn Baldwin void
893f1a4b852SJohn Baldwin turnstile_disown(struct turnstile *ts)
894f1a4b852SJohn Baldwin {
895f1a4b852SJohn Baldwin 	struct turnstile_chain *tc;
896f1a4b852SJohn Baldwin 	struct thread *td;
897f1a4b852SJohn Baldwin 	u_char cp, pri;
898f1a4b852SJohn Baldwin 
899f1a4b852SJohn Baldwin 	MPASS(ts != NULL);
900f1a4b852SJohn Baldwin 	MPASS(ts->ts_owner == curthread);
901f1a4b852SJohn Baldwin 	tc = TC_LOOKUP(ts->ts_lockobj);
902f1a4b852SJohn Baldwin 	mtx_assert(&tc->tc_lock, MA_OWNED);
903f1a4b852SJohn Baldwin 	MPASS(TAILQ_EMPTY(&ts->ts_pending));
904f1a4b852SJohn Baldwin 	MPASS(!TAILQ_EMPTY(&ts->ts_blocked[TS_EXCLUSIVE_QUEUE]) ||
905f1a4b852SJohn Baldwin 	    !TAILQ_EMPTY(&ts->ts_blocked[TS_SHARED_QUEUE]));
906f1a4b852SJohn Baldwin 
907f1a4b852SJohn Baldwin 	/*
908f1a4b852SJohn Baldwin 	 * Remove the turnstile from this thread's list of contested locks
909f1a4b852SJohn Baldwin 	 * since this thread doesn't own it anymore.  New threads will
910f1a4b852SJohn Baldwin 	 * not be blocking on the turnstile until it is claimed by a new
911f1a4b852SJohn Baldwin 	 * owner.
912f1a4b852SJohn Baldwin 	 */
913f1a4b852SJohn Baldwin 	mtx_lock_spin(&td_contested_lock);
914f1a4b852SJohn Baldwin 	ts->ts_owner = NULL;
915f1a4b852SJohn Baldwin 	LIST_REMOVE(ts, ts_link);
916f1a4b852SJohn Baldwin 	mtx_unlock_spin(&td_contested_lock);
917f1a4b852SJohn Baldwin 	mtx_unlock_spin(&tc->tc_lock);
918f1a4b852SJohn Baldwin 
919f1a4b852SJohn Baldwin 	/*
920f1a4b852SJohn Baldwin 	 * Adjust the priority of curthread based on other contested
921f1a4b852SJohn Baldwin 	 * locks it owns.  Don't lower the priority below the base
922f1a4b852SJohn Baldwin 	 * priority however.
923f1a4b852SJohn Baldwin 	 */
924f1a4b852SJohn Baldwin 	td = curthread;
925f1a4b852SJohn Baldwin 	pri = PRI_MAX;
926f1a4b852SJohn Baldwin 	mtx_lock_spin(&sched_lock);
927f1a4b852SJohn Baldwin 	mtx_lock_spin(&td_contested_lock);
928f1a4b852SJohn Baldwin 	LIST_FOREACH(ts, &td->td_contested, ts_link) {
929f1a4b852SJohn Baldwin 		cp = turnstile_first_waiter(ts)->td_priority;
930f1a4b852SJohn Baldwin 		if (cp < pri)
931f1a4b852SJohn Baldwin 			pri = cp;
932f1a4b852SJohn Baldwin 	}
933f1a4b852SJohn Baldwin 	mtx_unlock_spin(&td_contested_lock);
934f1a4b852SJohn Baldwin 	sched_unlend_prio(td, pri);
935f1a4b852SJohn Baldwin 	mtx_unlock_spin(&sched_lock);
936f1a4b852SJohn Baldwin }
937f1a4b852SJohn Baldwin 
938f1a4b852SJohn Baldwin /*
939961a7b24SJohn Baldwin  * Return the first thread in a turnstile.
9409ed346baSBosko Milekic  */
941961a7b24SJohn Baldwin struct thread *
9427aa4f685SJohn Baldwin turnstile_head(struct turnstile *ts, int queue)
9430cde2e34SJason Evans {
944961a7b24SJohn Baldwin #ifdef INVARIANTS
945961a7b24SJohn Baldwin 	struct turnstile_chain *tc;
9465cb0fbe4SJohn Baldwin 
947961a7b24SJohn Baldwin 	MPASS(ts != NULL);
9487aa4f685SJohn Baldwin 	MPASS(queue == TS_SHARED_QUEUE || queue == TS_EXCLUSIVE_QUEUE);
949961a7b24SJohn Baldwin 	tc = TC_LOOKUP(ts->ts_lockobj);
950961a7b24SJohn Baldwin 	mtx_assert(&tc->tc_lock, MA_OWNED);
9510cde2e34SJason Evans #endif
9527aa4f685SJohn Baldwin 	return (TAILQ_FIRST(&ts->ts_blocked[queue]));
953961a7b24SJohn Baldwin }
9547aa4f685SJohn Baldwin 
955f1a4b852SJohn Baldwin /*
956f1a4b852SJohn Baldwin  * Returns true if a sub-queue of a turnstile is empty.
957f1a4b852SJohn Baldwin  */
958f1a4b852SJohn Baldwin int
959f1a4b852SJohn Baldwin turnstile_empty(struct turnstile *ts, int queue)
960f1a4b852SJohn Baldwin {
961f1a4b852SJohn Baldwin #ifdef INVARIANTS
962f1a4b852SJohn Baldwin 	struct turnstile_chain *tc;
963f1a4b852SJohn Baldwin 
964f1a4b852SJohn Baldwin 	MPASS(ts != NULL);
965f1a4b852SJohn Baldwin 	MPASS(queue == TS_SHARED_QUEUE || queue == TS_EXCLUSIVE_QUEUE);
966f1a4b852SJohn Baldwin 	tc = TC_LOOKUP(ts->ts_lockobj);
967f1a4b852SJohn Baldwin 	mtx_assert(&tc->tc_lock, MA_OWNED);
968f1a4b852SJohn Baldwin #endif
969f1a4b852SJohn Baldwin 	return (TAILQ_EMPTY(&ts->ts_blocked[queue]));
970f1a4b852SJohn Baldwin }
971f1a4b852SJohn Baldwin 
9727aa4f685SJohn Baldwin #ifdef DDB
9737aa4f685SJohn Baldwin static void
9747aa4f685SJohn Baldwin print_thread(struct thread *td, const char *prefix)
9757aa4f685SJohn Baldwin {
9767aa4f685SJohn Baldwin 
9777aa4f685SJohn Baldwin 	db_printf("%s%p (tid %d, pid %d, \"%s\")\n", prefix, td, td->td_tid,
978f9ab2f13SJohn Baldwin 	    td->td_proc->p_pid, td->td_name[0] != '\0' ? td->td_name :
979f9ab2f13SJohn Baldwin 	    td->td_proc->p_comm);
9807aa4f685SJohn Baldwin }
9817aa4f685SJohn Baldwin 
9827aa4f685SJohn Baldwin static void
9837aa4f685SJohn Baldwin print_queue(struct threadqueue *queue, const char *header, const char *prefix)
9847aa4f685SJohn Baldwin {
9857aa4f685SJohn Baldwin 	struct thread *td;
9867aa4f685SJohn Baldwin 
9877aa4f685SJohn Baldwin 	db_printf("%s:\n", header);
9887aa4f685SJohn Baldwin 	if (TAILQ_EMPTY(queue)) {
9897aa4f685SJohn Baldwin 		db_printf("%sempty\n", prefix);
9907aa4f685SJohn Baldwin 		return;
9917aa4f685SJohn Baldwin 	}
9927aa4f685SJohn Baldwin 	TAILQ_FOREACH(td, queue, td_lockq) {
9937aa4f685SJohn Baldwin 		print_thread(td, prefix);
9947aa4f685SJohn Baldwin 	}
9957aa4f685SJohn Baldwin }
9967aa4f685SJohn Baldwin 
9977aa4f685SJohn Baldwin DB_SHOW_COMMAND(turnstile, db_show_turnstile)
9987aa4f685SJohn Baldwin {
9997aa4f685SJohn Baldwin 	struct turnstile_chain *tc;
10007aa4f685SJohn Baldwin 	struct turnstile *ts;
10017aa4f685SJohn Baldwin 	struct lock_object *lock;
10027aa4f685SJohn Baldwin 	int i;
10037aa4f685SJohn Baldwin 
10047aa4f685SJohn Baldwin 	if (!have_addr)
10057aa4f685SJohn Baldwin 		return;
10067aa4f685SJohn Baldwin 
10077aa4f685SJohn Baldwin 	/*
10087aa4f685SJohn Baldwin 	 * First, see if there is an active turnstile for the lock indicated
10097aa4f685SJohn Baldwin 	 * by the address.
10107aa4f685SJohn Baldwin 	 */
10117aa4f685SJohn Baldwin 	lock = (struct lock_object *)addr;
10127aa4f685SJohn Baldwin 	tc = TC_LOOKUP(lock);
10137aa4f685SJohn Baldwin 	LIST_FOREACH(ts, &tc->tc_turnstiles, ts_hash)
10147aa4f685SJohn Baldwin 		if (ts->ts_lockobj == lock)
10157aa4f685SJohn Baldwin 			goto found;
10167aa4f685SJohn Baldwin 
10177aa4f685SJohn Baldwin 	/*
10187aa4f685SJohn Baldwin 	 * Second, see if there is an active turnstile at the address
10197aa4f685SJohn Baldwin 	 * indicated.
10207aa4f685SJohn Baldwin 	 */
10217aa4f685SJohn Baldwin 	for (i = 0; i < TC_TABLESIZE; i++)
10227aa4f685SJohn Baldwin 		LIST_FOREACH(ts, &turnstile_chains[i].tc_turnstiles, ts_hash) {
10237aa4f685SJohn Baldwin 			if (ts == (struct turnstile *)addr)
10247aa4f685SJohn Baldwin 				goto found;
10257aa4f685SJohn Baldwin 		}
10267aa4f685SJohn Baldwin 
10277aa4f685SJohn Baldwin 	db_printf("Unable to locate a turnstile via %p\n", (void *)addr);
10287aa4f685SJohn Baldwin 	return;
10297aa4f685SJohn Baldwin found:
10307aa4f685SJohn Baldwin 	lock = ts->ts_lockobj;
10317aa4f685SJohn Baldwin 	db_printf("Lock: %p - (%s) %s\n", lock, LOCK_CLASS(lock)->lc_name,
10327aa4f685SJohn Baldwin 	    lock->lo_name);
10337aa4f685SJohn Baldwin 	if (ts->ts_owner)
10347aa4f685SJohn Baldwin 		print_thread(ts->ts_owner, "Lock Owner: ");
10357aa4f685SJohn Baldwin 	else
10367aa4f685SJohn Baldwin 		db_printf("Lock Owner: none\n");
10377aa4f685SJohn Baldwin 	print_queue(&ts->ts_blocked[TS_SHARED_QUEUE], "Shared Waiters", "\t");
10387aa4f685SJohn Baldwin 	print_queue(&ts->ts_blocked[TS_EXCLUSIVE_QUEUE], "Exclusive Waiters",
10397aa4f685SJohn Baldwin 	    "\t");
10407aa4f685SJohn Baldwin 	print_queue(&ts->ts_pending, "Pending Threads", "\t");
10417aa4f685SJohn Baldwin 
10427aa4f685SJohn Baldwin }
1043ae110b53SJohn Baldwin 
104477e66268SJohn Baldwin /*
104577e66268SJohn Baldwin  * Show all the threads a particular thread is waiting on based on
104677e66268SJohn Baldwin  * non-sleepable and non-spin locks.
104777e66268SJohn Baldwin  */
1048ae110b53SJohn Baldwin static void
104977e66268SJohn Baldwin print_lockchain(struct thread *td, const char *prefix)
1050ae110b53SJohn Baldwin {
1051ae110b53SJohn Baldwin 	struct lock_object *lock;
1052ae110b53SJohn Baldwin 	struct lock_class *class;
1053ae110b53SJohn Baldwin 	struct turnstile *ts;
1054ae110b53SJohn Baldwin 
1055ae110b53SJohn Baldwin 	/*
1056ae110b53SJohn Baldwin 	 * Follow the chain.  We keep walking as long as the thread is
1057ae110b53SJohn Baldwin 	 * blocked on a turnstile that has an owner.
1058ae110b53SJohn Baldwin 	 */
1059fed79884SJohn Baldwin 	while (!db_pager_quit) {
1060ae110b53SJohn Baldwin 		db_printf("%sthread %d (pid %d, %s) ", prefix, td->td_tid,
1061ae110b53SJohn Baldwin 		    td->td_proc->p_pid, td->td_name[0] != '\0' ? td->td_name :
1062ae110b53SJohn Baldwin 		    td->td_proc->p_comm);
1063ae110b53SJohn Baldwin 		switch (td->td_state) {
1064ae110b53SJohn Baldwin 		case TDS_INACTIVE:
1065ae110b53SJohn Baldwin 			db_printf("is inactive\n");
1066ae110b53SJohn Baldwin 			return;
1067ae110b53SJohn Baldwin 		case TDS_CAN_RUN:
1068ae110b53SJohn Baldwin 			db_printf("can run\n");
1069ae110b53SJohn Baldwin 			return;
1070ae110b53SJohn Baldwin 		case TDS_RUNQ:
1071ae110b53SJohn Baldwin 			db_printf("is on a run queue\n");
1072ae110b53SJohn Baldwin 			return;
1073ae110b53SJohn Baldwin 		case TDS_RUNNING:
1074ae110b53SJohn Baldwin 			db_printf("running on CPU %d\n", td->td_oncpu);
1075ae110b53SJohn Baldwin 			return;
1076ae110b53SJohn Baldwin 		case TDS_INHIBITED:
1077ae110b53SJohn Baldwin 			if (TD_ON_LOCK(td)) {
1078ae110b53SJohn Baldwin 				ts = td->td_blocked;
1079ae110b53SJohn Baldwin 				lock = ts->ts_lockobj;
1080ae110b53SJohn Baldwin 				class = LOCK_CLASS(lock);
1081ae110b53SJohn Baldwin 				db_printf("blocked on lock %p (%s) \"%s\"\n",
1082ae110b53SJohn Baldwin 				    lock, class->lc_name, lock->lo_name);
1083ae110b53SJohn Baldwin 				if (ts->ts_owner == NULL)
1084ae110b53SJohn Baldwin 					return;
1085ae110b53SJohn Baldwin 				td = ts->ts_owner;
1086ae110b53SJohn Baldwin 				break;
1087ae110b53SJohn Baldwin 			}
1088ae110b53SJohn Baldwin 			db_printf("inhibited\n");
1089ae110b53SJohn Baldwin 			return;
1090ae110b53SJohn Baldwin 		default:
1091ae110b53SJohn Baldwin 			db_printf("??? (%#x)\n", td->td_state);
1092ae110b53SJohn Baldwin 			return;
1093ae110b53SJohn Baldwin 		}
1094ae110b53SJohn Baldwin 	}
1095ae110b53SJohn Baldwin }
1096ae110b53SJohn Baldwin 
109777e66268SJohn Baldwin DB_SHOW_COMMAND(lockchain, db_show_lockchain)
1098ae110b53SJohn Baldwin {
1099ae110b53SJohn Baldwin 	struct thread *td;
1100ae110b53SJohn Baldwin 
1101ae110b53SJohn Baldwin 	/* Figure out which thread to start with. */
1102ae110b53SJohn Baldwin 	if (have_addr)
1103ae110b53SJohn Baldwin 		td = db_lookup_thread(addr, TRUE);
1104ae110b53SJohn Baldwin 	else
1105ae110b53SJohn Baldwin 		td = kdb_thread;
1106ae110b53SJohn Baldwin 
110777e66268SJohn Baldwin 	print_lockchain(td, "");
1108ae110b53SJohn Baldwin }
1109ae110b53SJohn Baldwin 
1110ae110b53SJohn Baldwin DB_SHOW_COMMAND(allchains, db_show_allchains)
1111ae110b53SJohn Baldwin {
1112ae110b53SJohn Baldwin 	struct thread *td;
1113ae110b53SJohn Baldwin 	struct proc *p;
1114ae110b53SJohn Baldwin 	int i;
1115ae110b53SJohn Baldwin 
1116ae110b53SJohn Baldwin 	i = 1;
11174f506694SXin LI 	FOREACH_PROC_IN_SYSTEM(p) {
1118ae110b53SJohn Baldwin 		FOREACH_THREAD_IN_PROC(p, td) {
1119ae110b53SJohn Baldwin 			if (TD_ON_LOCK(td) && LIST_EMPTY(&td->td_contested)) {
1120ae110b53SJohn Baldwin 				db_printf("chain %d:\n", i++);
112177e66268SJohn Baldwin 				print_lockchain(td, " ");
1122ae110b53SJohn Baldwin 			}
1123fed79884SJohn Baldwin 			if (db_pager_quit)
1124fed79884SJohn Baldwin 				return;
1125ae110b53SJohn Baldwin 		}
1126ae110b53SJohn Baldwin 	}
1127ae110b53SJohn Baldwin }
1128ae110b53SJohn Baldwin 
1129462a7addSJohn Baldwin /*
1130462a7addSJohn Baldwin  * Show all the threads a particular thread is waiting on based on
1131462a7addSJohn Baldwin  * sleepable locks.
1132462a7addSJohn Baldwin  */
1133462a7addSJohn Baldwin static void
1134462a7addSJohn Baldwin print_sleepchain(struct thread *td, const char *prefix)
1135462a7addSJohn Baldwin {
1136462a7addSJohn Baldwin 	struct thread *owner;
1137462a7addSJohn Baldwin 
1138462a7addSJohn Baldwin 	/*
1139462a7addSJohn Baldwin 	 * Follow the chain.  We keep walking as long as the thread is
1140462a7addSJohn Baldwin 	 * blocked on a sleep lock that has an owner.
1141462a7addSJohn Baldwin 	 */
1142462a7addSJohn Baldwin 	while (!db_pager_quit) {
1143462a7addSJohn Baldwin 		db_printf("%sthread %d (pid %d, %s) ", prefix, td->td_tid,
1144462a7addSJohn Baldwin 		    td->td_proc->p_pid, td->td_name[0] != '\0' ? td->td_name :
1145462a7addSJohn Baldwin 		    td->td_proc->p_comm);
1146462a7addSJohn Baldwin 		switch (td->td_state) {
1147462a7addSJohn Baldwin 		case TDS_INACTIVE:
1148462a7addSJohn Baldwin 			db_printf("is inactive\n");
1149462a7addSJohn Baldwin 			return;
1150462a7addSJohn Baldwin 		case TDS_CAN_RUN:
1151462a7addSJohn Baldwin 			db_printf("can run\n");
1152462a7addSJohn Baldwin 			return;
1153462a7addSJohn Baldwin 		case TDS_RUNQ:
1154462a7addSJohn Baldwin 			db_printf("is on a run queue\n");
1155462a7addSJohn Baldwin 			return;
1156462a7addSJohn Baldwin 		case TDS_RUNNING:
1157462a7addSJohn Baldwin 			db_printf("running on CPU %d\n", td->td_oncpu);
1158462a7addSJohn Baldwin 			return;
1159462a7addSJohn Baldwin 		case TDS_INHIBITED:
1160462a7addSJohn Baldwin 			if (TD_ON_SLEEPQ(td)) {
1161462a7addSJohn Baldwin 				if (lockmgr_chain(td, &owner) ||
1162462a7addSJohn Baldwin 				    sx_chain(td, &owner)) {
1163462a7addSJohn Baldwin 					if (owner == NULL)
1164462a7addSJohn Baldwin 						return;
1165462a7addSJohn Baldwin 					td = owner;
1166462a7addSJohn Baldwin 					break;
1167462a7addSJohn Baldwin 				}
1168462a7addSJohn Baldwin 				db_printf("sleeping on %p \"%s\"\n",
1169462a7addSJohn Baldwin 				    td->td_wchan, td->td_wmesg);
1170462a7addSJohn Baldwin 				return;
1171462a7addSJohn Baldwin 			}
1172462a7addSJohn Baldwin 			db_printf("inhibited\n");
1173462a7addSJohn Baldwin 			return;
1174462a7addSJohn Baldwin 		default:
1175462a7addSJohn Baldwin 			db_printf("??? (%#x)\n", td->td_state);
1176462a7addSJohn Baldwin 			return;
1177462a7addSJohn Baldwin 		}
1178462a7addSJohn Baldwin 	}
1179462a7addSJohn Baldwin }
1180462a7addSJohn Baldwin 
1181462a7addSJohn Baldwin DB_SHOW_COMMAND(sleepchain, db_show_sleepchain)
1182462a7addSJohn Baldwin {
1183462a7addSJohn Baldwin 	struct thread *td;
1184462a7addSJohn Baldwin 
1185462a7addSJohn Baldwin 	/* Figure out which thread to start with. */
1186462a7addSJohn Baldwin 	if (have_addr)
1187462a7addSJohn Baldwin 		td = db_lookup_thread(addr, TRUE);
1188462a7addSJohn Baldwin 	else
1189462a7addSJohn Baldwin 		td = kdb_thread;
1190462a7addSJohn Baldwin 
1191462a7addSJohn Baldwin 	print_sleepchain(td, "");
1192462a7addSJohn Baldwin }
1193462a7addSJohn Baldwin 
1194ae110b53SJohn Baldwin static void	print_waiters(struct turnstile *ts, int indent);
1195ae110b53SJohn Baldwin 
1196ae110b53SJohn Baldwin static void
1197ae110b53SJohn Baldwin print_waiter(struct thread *td, int indent)
1198ae110b53SJohn Baldwin {
1199ae110b53SJohn Baldwin 	struct turnstile *ts;
1200ae110b53SJohn Baldwin 	int i;
1201ae110b53SJohn Baldwin 
1202fed79884SJohn Baldwin 	if (db_pager_quit)
1203fed79884SJohn Baldwin 		return;
1204ae110b53SJohn Baldwin 	for (i = 0; i < indent; i++)
1205ae110b53SJohn Baldwin 		db_printf(" ");
1206ae110b53SJohn Baldwin 	print_thread(td, "thread ");
1207ae110b53SJohn Baldwin 	LIST_FOREACH(ts, &td->td_contested, ts_link)
1208ae110b53SJohn Baldwin 		print_waiters(ts, indent + 1);
1209ae110b53SJohn Baldwin }
1210ae110b53SJohn Baldwin 
1211ae110b53SJohn Baldwin static void
1212ae110b53SJohn Baldwin print_waiters(struct turnstile *ts, int indent)
1213ae110b53SJohn Baldwin {
1214ae110b53SJohn Baldwin 	struct lock_object *lock;
1215ae110b53SJohn Baldwin 	struct lock_class *class;
1216ae110b53SJohn Baldwin 	struct thread *td;
1217ae110b53SJohn Baldwin 	int i;
1218ae110b53SJohn Baldwin 
1219fed79884SJohn Baldwin 	if (db_pager_quit)
1220fed79884SJohn Baldwin 		return;
1221ae110b53SJohn Baldwin 	lock = ts->ts_lockobj;
1222ae110b53SJohn Baldwin 	class = LOCK_CLASS(lock);
1223ae110b53SJohn Baldwin 	for (i = 0; i < indent; i++)
1224ae110b53SJohn Baldwin 		db_printf(" ");
1225ae110b53SJohn Baldwin 	db_printf("lock %p (%s) \"%s\"\n", lock, class->lc_name, lock->lo_name);
1226ae110b53SJohn Baldwin 	TAILQ_FOREACH(td, &ts->ts_blocked[TS_EXCLUSIVE_QUEUE], td_lockq)
1227ae110b53SJohn Baldwin 		print_waiter(td, indent + 1);
1228ae110b53SJohn Baldwin 	TAILQ_FOREACH(td, &ts->ts_blocked[TS_SHARED_QUEUE], td_lockq)
1229ae110b53SJohn Baldwin 		print_waiter(td, indent + 1);
1230ae110b53SJohn Baldwin 	TAILQ_FOREACH(td, &ts->ts_pending, td_lockq)
1231ae110b53SJohn Baldwin 		print_waiter(td, indent + 1);
1232ae110b53SJohn Baldwin }
1233ae110b53SJohn Baldwin 
123477e66268SJohn Baldwin DB_SHOW_COMMAND(locktree, db_show_locktree)
1235ae110b53SJohn Baldwin {
1236ae110b53SJohn Baldwin 	struct lock_object *lock;
1237ae110b53SJohn Baldwin 	struct lock_class *class;
1238ae110b53SJohn Baldwin 	struct turnstile_chain *tc;
1239ae110b53SJohn Baldwin 	struct turnstile *ts;
1240ae110b53SJohn Baldwin 
1241ae110b53SJohn Baldwin 	if (!have_addr)
1242ae110b53SJohn Baldwin 		return;
1243ae110b53SJohn Baldwin 	lock = (struct lock_object *)addr;
1244ae110b53SJohn Baldwin 	tc = TC_LOOKUP(lock);
1245ae110b53SJohn Baldwin 	LIST_FOREACH(ts, &tc->tc_turnstiles, ts_hash)
1246ae110b53SJohn Baldwin 		if (ts->ts_lockobj == lock)
1247ae110b53SJohn Baldwin 			break;
1248ae110b53SJohn Baldwin 	if (ts == NULL) {
1249ae110b53SJohn Baldwin 		class = LOCK_CLASS(lock);
1250ae110b53SJohn Baldwin 		db_printf("lock %p (%s) \"%s\"\n", lock, class->lc_name,
1251ae110b53SJohn Baldwin 		    lock->lo_name);
1252ae110b53SJohn Baldwin 	} else
1253ae110b53SJohn Baldwin 		print_waiters(ts, 0);
1254ae110b53SJohn Baldwin }
12557aa4f685SJohn Baldwin #endif
1256