xref: /freebsd/sys/kern/kern_switch.c (revision b43179fbe815b81e2d6bb729ffcb08e8f0a143da)
1dba6c5a6SPeter Wemm /*
2d5a08a60SJake Burkholder  * Copyright (c) 2001 Jake Burkholder <jake@FreeBSD.org>
3d5a08a60SJake Burkholder  * All rights reserved.
4dba6c5a6SPeter Wemm  *
5dba6c5a6SPeter Wemm  * Redistribution and use in source and binary forms, with or without
6dba6c5a6SPeter Wemm  * modification, are permitted provided that the following conditions
7dba6c5a6SPeter Wemm  * are met:
8dba6c5a6SPeter Wemm  * 1. Redistributions of source code must retain the above copyright
9dba6c5a6SPeter Wemm  *    notice, this list of conditions and the following disclaimer.
10dba6c5a6SPeter Wemm  * 2. Redistributions in binary form must reproduce the above copyright
11dba6c5a6SPeter Wemm  *    notice, this list of conditions and the following disclaimer in the
12dba6c5a6SPeter Wemm  *    documentation and/or other materials provided with the distribution.
13dba6c5a6SPeter Wemm  *
14dba6c5a6SPeter Wemm  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15dba6c5a6SPeter Wemm  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16dba6c5a6SPeter Wemm  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17dba6c5a6SPeter Wemm  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18dba6c5a6SPeter Wemm  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19dba6c5a6SPeter Wemm  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20dba6c5a6SPeter Wemm  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21dba6c5a6SPeter Wemm  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22dba6c5a6SPeter Wemm  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23dba6c5a6SPeter Wemm  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24dba6c5a6SPeter Wemm  * SUCH DAMAGE.
25dba6c5a6SPeter Wemm  *
26dba6c5a6SPeter Wemm  * $FreeBSD$
27dba6c5a6SPeter Wemm  */
28dba6c5a6SPeter Wemm 
29e602ba25SJulian Elischer /***
30e602ba25SJulian Elischer 
31e602ba25SJulian Elischer Here is the logic..
32e602ba25SJulian Elischer 
33e602ba25SJulian Elischer If there are N processors, then there are at most N KSEs (kernel
34e602ba25SJulian Elischer schedulable entities) working to process threads that belong to a
35e602ba25SJulian Elischer KSEGOUP (kg). If there are X of these KSEs actually running at the
36e602ba25SJulian Elischer moment in question, then there are at most M (N-X) of these KSEs on
37e602ba25SJulian Elischer the run queue, as running KSEs are not on the queue.
38e602ba25SJulian Elischer 
39e602ba25SJulian Elischer Runnable threads are queued off the KSEGROUP in priority order.
40e602ba25SJulian Elischer If there are M or more threads runnable, the top M threads
41e602ba25SJulian Elischer (by priority) are 'preassigned' to the M KSEs not running. The KSEs take
42e602ba25SJulian Elischer their priority from those threads and are put on the run queue.
43e602ba25SJulian Elischer 
44e602ba25SJulian Elischer The last thread that had a priority high enough to have a KSE associated
45e602ba25SJulian Elischer with it, AND IS ON THE RUN QUEUE is pointed to by
46e602ba25SJulian Elischer kg->kg_last_assigned. If no threads queued off the KSEGROUP have KSEs
47e602ba25SJulian Elischer assigned as all the available KSEs are activly running, or because there
48e602ba25SJulian Elischer are no threads queued, that pointer is NULL.
49e602ba25SJulian Elischer 
50e602ba25SJulian Elischer When a KSE is removed from the run queue to become runnable, we know
51e602ba25SJulian Elischer it was associated with the highest priority thread in the queue (at the head
52e602ba25SJulian Elischer of the queue). If it is also the last assigned we know M was 1 and must
53e602ba25SJulian Elischer now be 0. Since the thread is no longer queued that pointer must be
54e602ba25SJulian Elischer removed from it. Since we know there were no more KSEs available,
55e602ba25SJulian Elischer (M was 1 and is now 0) and since we are not FREEING our KSE
56e602ba25SJulian Elischer but using it, we know there are STILL no more KSEs available, we can prove
57e602ba25SJulian Elischer that the next thread in the ksegrp list will not have a KSE to assign to
58e602ba25SJulian Elischer it, so we can show that the pointer must be made 'invalid' (NULL).
59e602ba25SJulian Elischer 
60e602ba25SJulian Elischer The pointer exists so that when a new thread is made runnable, it can
61e602ba25SJulian Elischer have its priority compared with the last assigned thread to see if
62e602ba25SJulian Elischer it should 'steal' its KSE or not.. i.e. is it 'earlier'
63e602ba25SJulian Elischer on the list than that thread or later.. If it's earlier, then the KSE is
64e602ba25SJulian Elischer removed from the last assigned (which is now not assigned a KSE)
65e602ba25SJulian Elischer and reassigned to the new thread, which is placed earlier in the list.
66e602ba25SJulian Elischer The pointer is then backed up to the previous thread (which may or may not
67e602ba25SJulian Elischer be the new thread).
68e602ba25SJulian Elischer 
69e602ba25SJulian Elischer When a thread sleeps or is removed, the KSE becomes available and if there
70e602ba25SJulian Elischer are queued threads that are not assigned KSEs, the highest priority one of
71e602ba25SJulian Elischer them is assigned the KSE, which is then placed back on the run queue at
72e602ba25SJulian Elischer the approipriate place, and the kg->kg_last_assigned pointer is adjusted down
73e602ba25SJulian Elischer to point to it.
74e602ba25SJulian Elischer 
75e602ba25SJulian Elischer The following diagram shows 2 KSEs and 3 threads from a single process.
76e602ba25SJulian Elischer 
77e602ba25SJulian Elischer  RUNQ: --->KSE---KSE--...    (KSEs queued at priorities from threads)
78e602ba25SJulian Elischer               \    \____
79e602ba25SJulian Elischer                \        \
80e602ba25SJulian Elischer     KSEGROUP---thread--thread--thread    (queued in priority order)
81e602ba25SJulian Elischer         \                 /
82e602ba25SJulian Elischer          \_______________/
83e602ba25SJulian Elischer           (last_assigned)
84e602ba25SJulian Elischer 
85e602ba25SJulian Elischer The result of this scheme is that the M available KSEs are always
86e602ba25SJulian Elischer queued at the priorities they have inherrited from the M highest priority
87e602ba25SJulian Elischer threads for that KSEGROUP. If this situation changes, the KSEs are
88e602ba25SJulian Elischer reassigned to keep this true.
89e602ba25SJulian Elischer 
90e602ba25SJulian Elischer */
91e602ba25SJulian Elischer 
92dba6c5a6SPeter Wemm #include <sys/param.h>
93dba6c5a6SPeter Wemm #include <sys/systm.h>
94dba6c5a6SPeter Wemm #include <sys/kernel.h>
950384fff8SJason Evans #include <sys/ktr.h>
96f34fa851SJohn Baldwin #include <sys/lock.h>
9735e0e5b3SJohn Baldwin #include <sys/mutex.h>
98dba6c5a6SPeter Wemm #include <sys/proc.h>
99dba6c5a6SPeter Wemm #include <sys/queue.h>
100b43179fbSJeff Roberson #include <sys/sched.h>
101182da820SMatthew Dillon #include <machine/critical.h>
102dba6c5a6SPeter Wemm 
103d2ac2316SJake Burkholder CTASSERT((RQB_BPW * RQB_LEN) == RQ_NQS);
104d2ac2316SJake Burkholder 
10548bfcdddSJulian Elischer void panc(char *string1, char *string2);
10648bfcdddSJulian Elischer 
10748bfcdddSJulian Elischer #if 0
108e602ba25SJulian Elischer static void runq_readjust(struct runq *rq, struct kse *ke);
10948bfcdddSJulian Elischer #endif
110e602ba25SJulian Elischer /************************************************************************
111e602ba25SJulian Elischer  * Functions that manipulate runnability from a thread perspective.	*
112e602ba25SJulian Elischer  ************************************************************************/
113dba6c5a6SPeter Wemm 
114e602ba25SJulian Elischer /*
115e602ba25SJulian Elischer  * Select the KSE that will be run next.  From that find the thread, and x
116e602ba25SJulian Elischer  * remove it from the KSEGRP's run queue.  If there is thread clustering,
117e602ba25SJulian Elischer  * this will be what does it.
118e602ba25SJulian Elischer  */
119b40ce416SJulian Elischer struct thread *
120b40ce416SJulian Elischer choosethread(void)
121dba6c5a6SPeter Wemm {
122e602ba25SJulian Elischer 	struct kse *ke;
123e602ba25SJulian Elischer 	struct thread *td;
124e602ba25SJulian Elischer 	struct ksegrp *kg;
125e602ba25SJulian Elischer 
126fe799533SAndrew Gallatin retry:
127b43179fbSJeff Roberson 	if ((ke = sched_choose())) {
128e602ba25SJulian Elischer 		td = ke->ke_thread;
129e602ba25SJulian Elischer 		KASSERT((td->td_kse == ke), ("kse/thread mismatch"));
130e602ba25SJulian Elischer 		kg = ke->ke_ksegrp;
131e602ba25SJulian Elischer 		if (td->td_flags & TDF_UNBOUND) {
132e602ba25SJulian Elischer 			TAILQ_REMOVE(&kg->kg_runq, td, td_runq);
13333c06e1dSJulian Elischer 			if (kg->kg_last_assigned == td) {
134e602ba25SJulian Elischer 				if (TAILQ_PREV(td, threadqueue, td_runq)
135e602ba25SJulian Elischer 				    != NULL)
136e602ba25SJulian Elischer 					printf("Yo MAMA!\n");
137e602ba25SJulian Elischer 				kg->kg_last_assigned = TAILQ_PREV(td,
138e602ba25SJulian Elischer 				    threadqueue, td_runq);
13933c06e1dSJulian Elischer 			}
140e602ba25SJulian Elischer 			/*
141e602ba25SJulian Elischer 			 *  If we have started running an upcall,
142e602ba25SJulian Elischer 			 * Then TDF_UNBOUND WAS set because the thread was
143e602ba25SJulian Elischer 			 * created without a KSE. Now that we have one,
144e602ba25SJulian Elischer 			 * and it is our time to run, we make sure
145e602ba25SJulian Elischer 			 * that BOUND semantics apply for the rest of
146e602ba25SJulian Elischer 			 * the journey to userland, and into the UTS.
147e602ba25SJulian Elischer 			 */
148e602ba25SJulian Elischer #ifdef	NOTYET
149e602ba25SJulian Elischer 			if (td->td_flags & TDF_UPCALLING)
150e602ba25SJulian Elischer 				tdf->td_flags &= ~TDF_UNBOUND;
151e602ba25SJulian Elischer #endif
152e602ba25SJulian Elischer 		}
153e602ba25SJulian Elischer 		kg->kg_runnable--;
154e602ba25SJulian Elischer 		CTR2(KTR_RUNQ, "choosethread: td=%p pri=%d",
155e602ba25SJulian Elischer 		    td, td->td_priority);
156e602ba25SJulian Elischer 	} else {
15740e55026SJulian Elischer 		/* Simulate runq_choose() having returned the idle thread */
158e602ba25SJulian Elischer 		td = PCPU_GET(idlethread);
159472be958SJulian Elischer 		ke = td->td_kse;
160e602ba25SJulian Elischer 		CTR1(KTR_RUNQ, "choosethread: td=%p (idle)", td);
161e602ba25SJulian Elischer 	}
162472be958SJulian Elischer 	ke->ke_flags |= KEF_DIDRUN;
163fe799533SAndrew Gallatin 	if (panicstr && ((td->td_proc->p_flag & P_SYSTEM) == 0 &&
164fe799533SAndrew Gallatin 	    (td->td_flags & TDF_INPANIC) == 0))
165fe799533SAndrew Gallatin 		goto retry;
16671fad9fdSJulian Elischer 	TD_SET_RUNNING(td);
167e602ba25SJulian Elischer 	return (td);
168e602ba25SJulian Elischer }
169e602ba25SJulian Elischer 
170e602ba25SJulian Elischer /*
17148bfcdddSJulian Elischer  * Given a KSE (now surplus or at least loanable), either assign a new
17248bfcdddSJulian Elischer  * runable thread to it
173e602ba25SJulian Elischer  * (and put it in the run queue) or put it in the ksegrp's idle KSE list.
17448bfcdddSJulian Elischer  * Or aybe give it back to its owner if it's been loaned.
175e602ba25SJulian Elischer  */
176e602ba25SJulian Elischer void
177e602ba25SJulian Elischer kse_reassign(struct kse *ke)
178e602ba25SJulian Elischer {
179e602ba25SJulian Elischer 	struct ksegrp *kg;
180e602ba25SJulian Elischer 	struct thread *td;
1819eb1fdeaSJulian Elischer 	struct thread *owner;
18248bfcdddSJulian Elischer 	struct thread *original;
183e602ba25SJulian Elischer 
18433c06e1dSJulian Elischer 	mtx_assert(&sched_lock, MA_OWNED);
185e602ba25SJulian Elischer 	kg = ke->ke_ksegrp;
1869eb1fdeaSJulian Elischer 	owner = ke->ke_bound;
18748bfcdddSJulian Elischer 	original = ke->ke_thread;
1889eb1fdeaSJulian Elischer 	KASSERT(!(owner && ((owner->td_kse != ke) ||
1899eb1fdeaSJulian Elischer 		    (owner->td_flags & TDF_UNBOUND))),
1909eb1fdeaSJulian Elischer 		("kse_reassign: bad thread bound state"));
191e602ba25SJulian Elischer 
192e602ba25SJulian Elischer 	/*
193e602ba25SJulian Elischer 	 * Find the first unassigned thread
194e602ba25SJulian Elischer 	 * If there is a 'last assigned' then see what's next.
195e602ba25SJulian Elischer 	 * otherwise look at what is first.
196e602ba25SJulian Elischer 	 */
197e602ba25SJulian Elischer 	if ((td = kg->kg_last_assigned)) {
198e602ba25SJulian Elischer 		td = TAILQ_NEXT(td, td_runq);
199e602ba25SJulian Elischer 	} else {
200e602ba25SJulian Elischer 		td = TAILQ_FIRST(&kg->kg_runq);
201e602ba25SJulian Elischer 	}
202e602ba25SJulian Elischer 
203e602ba25SJulian Elischer 	/*
204e602ba25SJulian Elischer 	 * If we found one assign it the kse, otherwise idle the kse.
205e602ba25SJulian Elischer 	 */
206e602ba25SJulian Elischer 	if (td) {
20748bfcdddSJulian Elischer 		/*
20848bfcdddSJulian Elischer 		 * If the original is bound to us we can only be lent out so
20948bfcdddSJulian Elischer 		 * make a loan, otherwise we just drop the
21048bfcdddSJulian Elischer 		 * original thread.
21148bfcdddSJulian Elischer 		 */
21248bfcdddSJulian Elischer 		if (original) {
21348bfcdddSJulian Elischer 			if (((original->td_flags & TDF_UNBOUND) == 0)) {
21448bfcdddSJulian Elischer 				/*
21548bfcdddSJulian Elischer 				 * Put the owner on the side
21648bfcdddSJulian Elischer 				 */
21748bfcdddSJulian Elischer 				ke->ke_bound = original;
21848bfcdddSJulian Elischer 				TD_SET_LOAN(original);
21948bfcdddSJulian Elischer 			} else {
22048bfcdddSJulian Elischer 				original->td_kse = NULL;
22148bfcdddSJulian Elischer 			}
22248bfcdddSJulian Elischer 		}
223e602ba25SJulian Elischer 		kg->kg_last_assigned = td;
224e602ba25SJulian Elischer 		td->td_kse = ke;
225e602ba25SJulian Elischer 		ke->ke_thread = td;
226b43179fbSJeff Roberson 		sched_add(ke);
22748bfcdddSJulian Elischer 		/*
22848bfcdddSJulian Elischer 		 * if we have already borrowed this,
22948bfcdddSJulian Elischer 		 * just pass it to the new thread,
23048bfcdddSJulian Elischer 		 * otherwise, enact the loan.
23148bfcdddSJulian Elischer 		 */
232e602ba25SJulian Elischer 		CTR2(KTR_RUNQ, "kse_reassign: ke%p -> td%p", ke, td);
23348bfcdddSJulian Elischer 		return;
23448bfcdddSJulian Elischer 	}
23548bfcdddSJulian Elischer 	if (owner) { /* already loaned out */
23648bfcdddSJulian Elischer 		/* effectivly unloan it */
23748bfcdddSJulian Elischer 		TD_CLR_LOAN(owner);
23848bfcdddSJulian Elischer 		ke->ke_thread = owner;
23948bfcdddSJulian Elischer 		ke->ke_bound = NULL;
24048bfcdddSJulian Elischer 		if (original)
24148bfcdddSJulian Elischer 			original->td_kse = NULL;
24248bfcdddSJulian Elischer 		original = owner;
24348bfcdddSJulian Elischer 
24448bfcdddSJulian Elischer 		if (TD_CAN_RUN(owner)) {
24548bfcdddSJulian Elischer 			/*
24648bfcdddSJulian Elischer 			 * If the owner thread is now runnable,  run it..
24748bfcdddSJulian Elischer 			 * Let it have its KSE back.
24848bfcdddSJulian Elischer 			 */
24948bfcdddSJulian Elischer 			setrunqueue(owner);
25048bfcdddSJulian Elischer 			CTR2(KTR_RUNQ, "kse_reassign: ke%p -> td%p (give back)",
25148bfcdddSJulian Elischer 			    ke, owner);
25248bfcdddSJulian Elischer 			return;
25348bfcdddSJulian Elischer 		}
25448bfcdddSJulian Elischer 	}
25548bfcdddSJulian Elischer 	/*
25648bfcdddSJulian Elischer 	 * Presetly NOT loaned out.
25748bfcdddSJulian Elischer 	 * If we are bound, we go on the loanable queue
25848bfcdddSJulian Elischer 	 * otherwise onto the free queue.
25948bfcdddSJulian Elischer 	 */
26048bfcdddSJulian Elischer 	if (original) {
26148bfcdddSJulian Elischer 		if (((original->td_flags & TDF_UNBOUND) == 0)) {
26248bfcdddSJulian Elischer 			ke->ke_state = KES_THREAD;
26348bfcdddSJulian Elischer 			ke->ke_flags |= KEF_ONLOANQ;
26448bfcdddSJulian Elischer 			ke->ke_bound = NULL;
26548bfcdddSJulian Elischer 			TAILQ_INSERT_HEAD(&kg->kg_lq, ke, ke_kgrlist);
26648bfcdddSJulian Elischer 			kg->kg_loan_kses++;
26748bfcdddSJulian Elischer 			CTR1(KTR_RUNQ, "kse_reassign: ke%p on loan queue", ke);
26848bfcdddSJulian Elischer 			return;
26948bfcdddSJulian Elischer 		} else {
27048bfcdddSJulian Elischer 			original->td_kse = NULL;
27148bfcdddSJulian Elischer 		}
27248bfcdddSJulian Elischer 	}
273e602ba25SJulian Elischer 	ke->ke_state = KES_IDLE;
274e602ba25SJulian Elischer 	ke->ke_thread = NULL;
275e602ba25SJulian Elischer 	TAILQ_INSERT_HEAD(&kg->kg_iq, ke, ke_kgrlist);
276e602ba25SJulian Elischer 	kg->kg_idle_kses++;
277e602ba25SJulian Elischer 	CTR1(KTR_RUNQ, "kse_reassign: ke%p idled", ke);
278d5a08a60SJake Burkholder }
279d5a08a60SJake Burkholder 
280e602ba25SJulian Elischer /*
281e602ba25SJulian Elischer  * Remove a thread from its KSEGRP's run queue.
282e602ba25SJulian Elischer  * This in turn may remove it from a KSE if it was already assigned
283e602ba25SJulian Elischer  * to one, possibly causing a new thread to be assigned to the KSE
284e602ba25SJulian Elischer  * and the KSE getting a new priority (unless it's a BOUND thread/KSE pair).
285e602ba25SJulian Elischer  */
286d5a08a60SJake Burkholder void
287b40ce416SJulian Elischer remrunqueue(struct thread *td)
288d5a08a60SJake Burkholder {
28948bfcdddSJulian Elischer 	struct thread *td2, *td3;
290e602ba25SJulian Elischer 	struct ksegrp *kg;
291e602ba25SJulian Elischer 	struct kse *ke;
292e602ba25SJulian Elischer 
293e602ba25SJulian Elischer 	mtx_assert(&sched_lock, MA_OWNED);
29471fad9fdSJulian Elischer 	KASSERT ((TD_ON_RUNQ(td)), ("remrunqueue: Bad state on run queue"));
295e602ba25SJulian Elischer 	kg = td->td_ksegrp;
296e602ba25SJulian Elischer 	ke = td->td_kse;
297e602ba25SJulian Elischer 	/*
298e602ba25SJulian Elischer 	 * If it's a bound thread/KSE pair, take the shortcut. All non-KSE
299e602ba25SJulian Elischer 	 * threads are BOUND.
300e602ba25SJulian Elischer 	 */
301e602ba25SJulian Elischer 	CTR1(KTR_RUNQ, "remrunqueue: td%p", td);
302e602ba25SJulian Elischer 	kg->kg_runnable--;
30371fad9fdSJulian Elischer 	TD_SET_CAN_RUN(td);
304e602ba25SJulian Elischer 	if ((td->td_flags & TDF_UNBOUND) == 0)  {
305e602ba25SJulian Elischer 		/* Bring its kse with it, leave the thread attached */
306b43179fbSJeff Roberson 		sched_rem(ke);
307c3b98db0SJulian Elischer 		ke->ke_state = KES_THREAD;
308e602ba25SJulian Elischer 		return;
309d5a08a60SJake Burkholder 	}
31048bfcdddSJulian Elischer    	td3 = TAILQ_PREV(td, threadqueue, td_runq);
31148bfcdddSJulian Elischer 	TAILQ_REMOVE(&kg->kg_runq, td, td_runq);
312e602ba25SJulian Elischer 	if (ke) {
313e602ba25SJulian Elischer 		/*
314e602ba25SJulian Elischer 		 * This thread has been assigned to a KSE.
315e602ba25SJulian Elischer 		 * We need to dissociate it and try assign the
316e602ba25SJulian Elischer 		 * KSE to the next available thread. Then, we should
317e602ba25SJulian Elischer 		 * see if we need to move the KSE in the run queues.
318e602ba25SJulian Elischer 		 */
319e602ba25SJulian Elischer 		td2 = kg->kg_last_assigned;
320e602ba25SJulian Elischer 		KASSERT((td2 != NULL), ("last assigned has wrong value "));
32148bfcdddSJulian Elischer 		if (td2 == td)
322e602ba25SJulian Elischer 			kg->kg_last_assigned = td3;
32348bfcdddSJulian Elischer 		td->td_kse = NULL;
324e602ba25SJulian Elischer 		ke->ke_thread = NULL;
32548bfcdddSJulian Elischer 		kse_reassign(ke);
326e602ba25SJulian Elischer 	}
327e602ba25SJulian Elischer }
328e602ba25SJulian Elischer 
329d5a08a60SJake Burkholder void
330b40ce416SJulian Elischer setrunqueue(struct thread *td)
331d5a08a60SJake Burkholder {
332e602ba25SJulian Elischer 	struct kse *ke;
333e602ba25SJulian Elischer 	struct ksegrp *kg;
334e602ba25SJulian Elischer 	struct thread *td2;
335e602ba25SJulian Elischer 	struct thread *tda;
336e602ba25SJulian Elischer 
337e602ba25SJulian Elischer 	CTR1(KTR_RUNQ, "setrunqueue: td%p", td);
338e602ba25SJulian Elischer 	mtx_assert(&sched_lock, MA_OWNED);
33971fad9fdSJulian Elischer 	KASSERT((TD_CAN_RUN(td) || TD_IS_RUNNING(td)),
34071fad9fdSJulian Elischer 	    ("setrunqueue: bad thread state"));
34171fad9fdSJulian Elischer 	TD_SET_RUNQ(td);
342e602ba25SJulian Elischer 	kg = td->td_ksegrp;
343e602ba25SJulian Elischer 	kg->kg_runnable++;
34448bfcdddSJulian Elischer 	if ((td->td_proc->p_flag & P_KSES) == 0) {
34548bfcdddSJulian Elischer 		/*
34648bfcdddSJulian Elischer 		 * Common path optimisation: Only one of everything
34748bfcdddSJulian Elischer 		 * and the KSE is always already attached.
34848bfcdddSJulian Elischer 		 * Totally ignore the ksegrp run queue.
34948bfcdddSJulian Elischer 		 */
350b43179fbSJeff Roberson 		sched_add(td->td_kse);
35148bfcdddSJulian Elischer 		return;
35248bfcdddSJulian Elischer 	}
353e602ba25SJulian Elischer 	if ((td->td_flags & TDF_UNBOUND) == 0) {
354e602ba25SJulian Elischer 		KASSERT((td->td_kse != NULL),
355e602ba25SJulian Elischer 		    ("queueing BAD thread to run queue"));
3569eb1fdeaSJulian Elischer 		ke = td->td_kse;
3575da2b58aSDavid Xu 		ke->ke_bound = NULL;
3589eb1fdeaSJulian Elischer 		if (ke->ke_flags & KEF_ONLOANQ) {
3599eb1fdeaSJulian Elischer 			ke->ke_flags &= ~KEF_ONLOANQ;
3609eb1fdeaSJulian Elischer 			TAILQ_REMOVE(&kg->kg_lq, ke, ke_kgrlist);
3619eb1fdeaSJulian Elischer 			kg->kg_loan_kses--;
3629eb1fdeaSJulian Elischer 		}
363b43179fbSJeff Roberson 		sched_add(td->td_kse);
364e602ba25SJulian Elischer 		return;
365e602ba25SJulian Elischer 	}
36648bfcdddSJulian Elischer 
367e602ba25SJulian Elischer 	/*
368e602ba25SJulian Elischer 	 * Ok, so we are threading with this thread.
369e602ba25SJulian Elischer 	 * We don't have a KSE, see if we can get one..
370e602ba25SJulian Elischer 	 */
371e602ba25SJulian Elischer 	tda = kg->kg_last_assigned;
372e602ba25SJulian Elischer 	if ((ke = td->td_kse) == NULL) {
373e602ba25SJulian Elischer 		/*
374e602ba25SJulian Elischer 		 * We will need a KSE, see if there is one..
375e602ba25SJulian Elischer 		 * First look for a free one, before getting desperate.
376e602ba25SJulian Elischer 		 * If we can't get one, our priority is not high enough..
377e602ba25SJulian Elischer 		 * that's ok..
378e602ba25SJulian Elischer 		 */
379e602ba25SJulian Elischer 		if (kg->kg_idle_kses) {
380e602ba25SJulian Elischer 			/*
381e602ba25SJulian Elischer 			 * There is a free one so it's ours for the asking..
382e602ba25SJulian Elischer 			 */
383e602ba25SJulian Elischer 			ke = TAILQ_FIRST(&kg->kg_iq);
384e602ba25SJulian Elischer 			TAILQ_REMOVE(&kg->kg_iq, ke, ke_kgrlist);
385c3b98db0SJulian Elischer 			ke->ke_state = KES_THREAD;
386e602ba25SJulian Elischer 			kg->kg_idle_kses--;
3879eb1fdeaSJulian Elischer 		} else if (kg->kg_loan_kses) {
38848bfcdddSJulian Elischer 			/*
38948bfcdddSJulian Elischer 			 * Failing that see if we can borrow one.
39048bfcdddSJulian Elischer 			 */
3919eb1fdeaSJulian Elischer 			ke = TAILQ_FIRST(&kg->kg_lq);
3929eb1fdeaSJulian Elischer 			TAILQ_REMOVE(&kg->kg_lq, ke, ke_kgrlist);
3939eb1fdeaSJulian Elischer 			ke->ke_flags &= ~KEF_ONLOANQ;
3949eb1fdeaSJulian Elischer 			ke->ke_state = KES_THREAD;
39548bfcdddSJulian Elischer 			TD_SET_LOAN(ke->ke_thread);
39648bfcdddSJulian Elischer 			ke->ke_bound = ke->ke_thread;
39748bfcdddSJulian Elischer 			ke->ke_thread  = NULL;
3989eb1fdeaSJulian Elischer 			kg->kg_loan_kses--;
399e602ba25SJulian Elischer 		} else if (tda && (tda->td_priority > td->td_priority)) {
400e602ba25SJulian Elischer 			/*
401e602ba25SJulian Elischer 			 * None free, but there is one we can commandeer.
402e602ba25SJulian Elischer 			 */
403e602ba25SJulian Elischer 			ke = tda->td_kse;
404e602ba25SJulian Elischer 			tda->td_kse = NULL;
405e602ba25SJulian Elischer 			ke->ke_thread = NULL;
406e602ba25SJulian Elischer 			tda = kg->kg_last_assigned =
407e602ba25SJulian Elischer 		    	    TAILQ_PREV(tda, threadqueue, td_runq);
408b43179fbSJeff Roberson 			sched_rem(ke);
409e602ba25SJulian Elischer 		}
410e602ba25SJulian Elischer 	} else {
411c3b98db0SJulian Elischer 		/*
412c3b98db0SJulian Elischer 		 * Temporarily disassociate so it looks like the other cases.
413c3b98db0SJulian Elischer 		 */
414e602ba25SJulian Elischer 		ke->ke_thread = NULL;
415e602ba25SJulian Elischer 		td->td_kse = NULL;
416d5a08a60SJake Burkholder 	}
417d5a08a60SJake Burkholder 
418e602ba25SJulian Elischer 	/*
419e602ba25SJulian Elischer 	 * Add the thread to the ksegrp's run queue at
420e602ba25SJulian Elischer 	 * the appropriate place.
421e602ba25SJulian Elischer 	 */
422e602ba25SJulian Elischer 	TAILQ_FOREACH(td2, &kg->kg_runq, td_runq) {
423e602ba25SJulian Elischer 		if (td2->td_priority > td->td_priority) {
424e602ba25SJulian Elischer 			TAILQ_INSERT_BEFORE(td2, td, td_runq);
425e602ba25SJulian Elischer 			break;
426e602ba25SJulian Elischer 		}
427e602ba25SJulian Elischer 	}
428e602ba25SJulian Elischer 	if (td2 == NULL) {
429e602ba25SJulian Elischer 		/* We ran off the end of the TAILQ or it was empty. */
430e602ba25SJulian Elischer 		TAILQ_INSERT_TAIL(&kg->kg_runq, td, td_runq);
431e602ba25SJulian Elischer 	}
432e602ba25SJulian Elischer 
433e602ba25SJulian Elischer 	/*
434e602ba25SJulian Elischer 	 * If we have a ke to use, then put it on the run queue and
435e602ba25SJulian Elischer 	 * If needed, readjust the last_assigned pointer.
436e602ba25SJulian Elischer 	 */
437e602ba25SJulian Elischer 	if (ke) {
438e602ba25SJulian Elischer 		if (tda == NULL) {
439e602ba25SJulian Elischer 			/*
440e602ba25SJulian Elischer 			 * No pre-existing last assigned so whoever is first
441c3b98db0SJulian Elischer 			 * gets the KSE we brought in.. (maybe us)
442e602ba25SJulian Elischer 			 */
443e602ba25SJulian Elischer 			td2 = TAILQ_FIRST(&kg->kg_runq);
444e602ba25SJulian Elischer 			KASSERT((td2->td_kse == NULL),
445e602ba25SJulian Elischer 			    ("unexpected ke present"));
446e602ba25SJulian Elischer 			td2->td_kse = ke;
447e602ba25SJulian Elischer 			ke->ke_thread = td2;
448e602ba25SJulian Elischer 			kg->kg_last_assigned = td2;
449e602ba25SJulian Elischer 		} else if (tda->td_priority > td->td_priority) {
450e602ba25SJulian Elischer 			/*
451e602ba25SJulian Elischer 			 * It's ours, grab it, but last_assigned is past us
452e602ba25SJulian Elischer 			 * so don't change it.
453e602ba25SJulian Elischer 			 */
454e602ba25SJulian Elischer 			td->td_kse = ke;
455e602ba25SJulian Elischer 			ke->ke_thread = td;
456e602ba25SJulian Elischer 		} else {
457e602ba25SJulian Elischer 			/*
458e602ba25SJulian Elischer 			 * We are past last_assigned, so
459e602ba25SJulian Elischer 			 * put the new kse on whatever is next,
460e602ba25SJulian Elischer 			 * which may or may not be us.
461e602ba25SJulian Elischer 			 */
462e602ba25SJulian Elischer 			td2 = TAILQ_NEXT(tda, td_runq);
463e602ba25SJulian Elischer 			kg->kg_last_assigned = td2;
464e602ba25SJulian Elischer 			td2->td_kse = ke;
465e602ba25SJulian Elischer 			ke->ke_thread = td2;
466e602ba25SJulian Elischer 		}
467b43179fbSJeff Roberson 		sched_add(ke);
468e602ba25SJulian Elischer 	}
469e602ba25SJulian Elischer }
470e602ba25SJulian Elischer 
471e602ba25SJulian Elischer /************************************************************************
472e602ba25SJulian Elischer  * Critical section marker functions					*
473e602ba25SJulian Elischer  ************************************************************************/
4747e1f6dfeSJohn Baldwin /* Critical sections that prevent preemption. */
4757e1f6dfeSJohn Baldwin void
4767e1f6dfeSJohn Baldwin critical_enter(void)
4777e1f6dfeSJohn Baldwin {
4787e1f6dfeSJohn Baldwin 	struct thread *td;
4797e1f6dfeSJohn Baldwin 
4807e1f6dfeSJohn Baldwin 	td = curthread;
4817e1f6dfeSJohn Baldwin 	if (td->td_critnest == 0)
482d74ac681SMatthew Dillon 		cpu_critical_enter();
4837e1f6dfeSJohn Baldwin 	td->td_critnest++;
4847e1f6dfeSJohn Baldwin }
4857e1f6dfeSJohn Baldwin 
4867e1f6dfeSJohn Baldwin void
4877e1f6dfeSJohn Baldwin critical_exit(void)
4887e1f6dfeSJohn Baldwin {
4897e1f6dfeSJohn Baldwin 	struct thread *td;
4907e1f6dfeSJohn Baldwin 
4917e1f6dfeSJohn Baldwin 	td = curthread;
4927e1f6dfeSJohn Baldwin 	if (td->td_critnest == 1) {
4937e1f6dfeSJohn Baldwin 		td->td_critnest = 0;
494d74ac681SMatthew Dillon 		cpu_critical_exit();
495d74ac681SMatthew Dillon 	} else {
4967e1f6dfeSJohn Baldwin 		td->td_critnest--;
4977e1f6dfeSJohn Baldwin 	}
498d74ac681SMatthew Dillon }
4997e1f6dfeSJohn Baldwin 
500e602ba25SJulian Elischer 
501e602ba25SJulian Elischer /************************************************************************
502e602ba25SJulian Elischer  * SYSTEM RUN QUEUE manipulations and tests				*
503e602ba25SJulian Elischer  ************************************************************************/
504e602ba25SJulian Elischer /*
505e602ba25SJulian Elischer  * Initialize a run structure.
506e602ba25SJulian Elischer  */
507e602ba25SJulian Elischer void
508e602ba25SJulian Elischer runq_init(struct runq *rq)
509e602ba25SJulian Elischer {
510e602ba25SJulian Elischer 	int i;
511e602ba25SJulian Elischer 
512e602ba25SJulian Elischer 	bzero(rq, sizeof *rq);
513e602ba25SJulian Elischer 	for (i = 0; i < RQ_NQS; i++)
514e602ba25SJulian Elischer 		TAILQ_INIT(&rq->rq_queues[i]);
515e602ba25SJulian Elischer }
516e602ba25SJulian Elischer 
517d5a08a60SJake Burkholder /*
518d5a08a60SJake Burkholder  * Clear the status bit of the queue corresponding to priority level pri,
519d5a08a60SJake Burkholder  * indicating that it is empty.
520d5a08a60SJake Burkholder  */
521d5a08a60SJake Burkholder static __inline void
522d5a08a60SJake Burkholder runq_clrbit(struct runq *rq, int pri)
523d5a08a60SJake Burkholder {
524d5a08a60SJake Burkholder 	struct rqbits *rqb;
525d5a08a60SJake Burkholder 
526d5a08a60SJake Burkholder 	rqb = &rq->rq_status;
527d5a08a60SJake Burkholder 	CTR4(KTR_RUNQ, "runq_clrbit: bits=%#x %#x bit=%#x word=%d",
528d5a08a60SJake Burkholder 	    rqb->rqb_bits[RQB_WORD(pri)],
529d5a08a60SJake Burkholder 	    rqb->rqb_bits[RQB_WORD(pri)] & ~RQB_BIT(pri),
530d5a08a60SJake Burkholder 	    RQB_BIT(pri), RQB_WORD(pri));
531d5a08a60SJake Burkholder 	rqb->rqb_bits[RQB_WORD(pri)] &= ~RQB_BIT(pri);
532d5a08a60SJake Burkholder }
533d5a08a60SJake Burkholder 
534d5a08a60SJake Burkholder /*
535d5a08a60SJake Burkholder  * Find the index of the first non-empty run queue.  This is done by
536d5a08a60SJake Burkholder  * scanning the status bits, a set bit indicates a non-empty queue.
537d5a08a60SJake Burkholder  */
538d5a08a60SJake Burkholder static __inline int
539d5a08a60SJake Burkholder runq_findbit(struct runq *rq)
540d5a08a60SJake Burkholder {
541d5a08a60SJake Burkholder 	struct rqbits *rqb;
542d5a08a60SJake Burkholder 	int pri;
543d5a08a60SJake Burkholder 	int i;
544d5a08a60SJake Burkholder 
545d5a08a60SJake Burkholder 	rqb = &rq->rq_status;
546d5a08a60SJake Burkholder 	for (i = 0; i < RQB_LEN; i++)
547d5a08a60SJake Burkholder 		if (rqb->rqb_bits[i]) {
5482f9267ecSPeter Wemm 			pri = RQB_FFS(rqb->rqb_bits[i]) + (i << RQB_L2BPW);
549d5a08a60SJake Burkholder 			CTR3(KTR_RUNQ, "runq_findbit: bits=%#x i=%d pri=%d",
550d5a08a60SJake Burkholder 			    rqb->rqb_bits[i], i, pri);
551d5a08a60SJake Burkholder 			return (pri);
552d5a08a60SJake Burkholder 		}
553d5a08a60SJake Burkholder 
554d5a08a60SJake Burkholder 	return (-1);
555d5a08a60SJake Burkholder }
556d5a08a60SJake Burkholder 
557d5a08a60SJake Burkholder /*
558d5a08a60SJake Burkholder  * Set the status bit of the queue corresponding to priority level pri,
559d5a08a60SJake Burkholder  * indicating that it is non-empty.
560d5a08a60SJake Burkholder  */
561d5a08a60SJake Burkholder static __inline void
562d5a08a60SJake Burkholder runq_setbit(struct runq *rq, int pri)
563d5a08a60SJake Burkholder {
564d5a08a60SJake Burkholder 	struct rqbits *rqb;
565d5a08a60SJake Burkholder 
566d5a08a60SJake Burkholder 	rqb = &rq->rq_status;
567d5a08a60SJake Burkholder 	CTR4(KTR_RUNQ, "runq_setbit: bits=%#x %#x bit=%#x word=%d",
568d5a08a60SJake Burkholder 	    rqb->rqb_bits[RQB_WORD(pri)],
569d5a08a60SJake Burkholder 	    rqb->rqb_bits[RQB_WORD(pri)] | RQB_BIT(pri),
570d5a08a60SJake Burkholder 	    RQB_BIT(pri), RQB_WORD(pri));
571d5a08a60SJake Burkholder 	rqb->rqb_bits[RQB_WORD(pri)] |= RQB_BIT(pri);
572d5a08a60SJake Burkholder }
573d5a08a60SJake Burkholder 
574d5a08a60SJake Burkholder /*
575e602ba25SJulian Elischer  * Add the KSE to the queue specified by its priority, and set the
576d5a08a60SJake Burkholder  * corresponding status bit.
577d5a08a60SJake Burkholder  */
578d5a08a60SJake Burkholder void
579b40ce416SJulian Elischer runq_add(struct runq *rq, struct kse *ke)
580d5a08a60SJake Burkholder {
581d5a08a60SJake Burkholder 	struct rqhead *rqh;
582d5a08a60SJake Burkholder 	int pri;
583dba6c5a6SPeter Wemm 
5842c100766SJulian Elischer 	pri = ke->ke_thread->td_priority / RQ_PPQ;
585b40ce416SJulian Elischer 	ke->ke_rqindex = pri;
586d5a08a60SJake Burkholder 	runq_setbit(rq, pri);
587d5a08a60SJake Burkholder 	rqh = &rq->rq_queues[pri];
588d5a08a60SJake Burkholder 	CTR4(KTR_RUNQ, "runq_add: p=%p pri=%d %d rqh=%p",
5892c100766SJulian Elischer 	    ke->ke_proc, ke->ke_thread->td_priority, pri, rqh);
590b40ce416SJulian Elischer 	TAILQ_INSERT_TAIL(rqh, ke, ke_procq);
591dba6c5a6SPeter Wemm }
592d5a08a60SJake Burkholder 
593d5a08a60SJake Burkholder /*
594d5a08a60SJake Burkholder  * Return true if there are runnable processes of any priority on the run
595d5a08a60SJake Burkholder  * queue, false otherwise.  Has no side effects, does not modify the run
596d5a08a60SJake Burkholder  * queue structure.
597d5a08a60SJake Burkholder  */
598d5a08a60SJake Burkholder int
599d5a08a60SJake Burkholder runq_check(struct runq *rq)
600d5a08a60SJake Burkholder {
601d5a08a60SJake Burkholder 	struct rqbits *rqb;
602d5a08a60SJake Burkholder 	int i;
603d5a08a60SJake Burkholder 
604d5a08a60SJake Burkholder 	rqb = &rq->rq_status;
605d5a08a60SJake Burkholder 	for (i = 0; i < RQB_LEN; i++)
606d5a08a60SJake Burkholder 		if (rqb->rqb_bits[i]) {
607d5a08a60SJake Burkholder 			CTR2(KTR_RUNQ, "runq_check: bits=%#x i=%d",
608d5a08a60SJake Burkholder 			    rqb->rqb_bits[i], i);
609d5a08a60SJake Burkholder 			return (1);
610dba6c5a6SPeter Wemm 		}
611d5a08a60SJake Burkholder 	CTR0(KTR_RUNQ, "runq_check: empty");
612d5a08a60SJake Burkholder 
613d5a08a60SJake Burkholder 	return (0);
614dba6c5a6SPeter Wemm }
615d5a08a60SJake Burkholder 
616d5a08a60SJake Burkholder /*
617b43179fbSJeff Roberson  * Find the highest priority process on the run queue.
618d5a08a60SJake Burkholder  */
619b40ce416SJulian Elischer struct kse *
620d5a08a60SJake Burkholder runq_choose(struct runq *rq)
621d5a08a60SJake Burkholder {
622d5a08a60SJake Burkholder 	struct rqhead *rqh;
623b40ce416SJulian Elischer 	struct kse *ke;
624d5a08a60SJake Burkholder 	int pri;
625d5a08a60SJake Burkholder 
626d5a08a60SJake Burkholder 	mtx_assert(&sched_lock, MA_OWNED);
627e602ba25SJulian Elischer 	while ((pri = runq_findbit(rq)) != -1) {
628d5a08a60SJake Burkholder 		rqh = &rq->rq_queues[pri];
629b40ce416SJulian Elischer 		ke = TAILQ_FIRST(rqh);
630b40ce416SJulian Elischer 		KASSERT(ke != NULL, ("runq_choose: no proc on busy queue"));
631e602ba25SJulian Elischer 		CTR3(KTR_RUNQ,
632e602ba25SJulian Elischer 		    "runq_choose: pri=%d kse=%p rqh=%p", pri, ke, rqh);
633b40ce416SJulian Elischer 		return (ke);
634d5a08a60SJake Burkholder 	}
635d5a08a60SJake Burkholder 	CTR1(KTR_RUNQ, "runq_choose: idleproc pri=%d", pri);
636d5a08a60SJake Burkholder 
637e602ba25SJulian Elischer 	return (NULL);
638d5a08a60SJake Burkholder }
639d5a08a60SJake Burkholder 
640d5a08a60SJake Burkholder /*
641e602ba25SJulian Elischer  * Remove the KSE from the queue specified by its priority, and clear the
642d5a08a60SJake Burkholder  * corresponding status bit if the queue becomes empty.
643e602ba25SJulian Elischer  * Caller must set ke->ke_state afterwards.
644d5a08a60SJake Burkholder  */
645d5a08a60SJake Burkholder void
646b40ce416SJulian Elischer runq_remove(struct runq *rq, struct kse *ke)
647d5a08a60SJake Burkholder {
648d5a08a60SJake Burkholder 	struct rqhead *rqh;
649d5a08a60SJake Burkholder 	int pri;
650d5a08a60SJake Burkholder 
6519eb881f8SSeigo Tanimura 	KASSERT(ke->ke_proc->p_sflag & PS_INMEM,
6529eb881f8SSeigo Tanimura 		("runq_remove: process swapped out"));
653b40ce416SJulian Elischer 	pri = ke->ke_rqindex;
654d5a08a60SJake Burkholder 	rqh = &rq->rq_queues[pri];
655d5a08a60SJake Burkholder 	CTR4(KTR_RUNQ, "runq_remove: p=%p pri=%d %d rqh=%p",
6562c100766SJulian Elischer 	    ke, ke->ke_thread->td_priority, pri, rqh);
657b40ce416SJulian Elischer 	KASSERT(ke != NULL, ("runq_remove: no proc on busy queue"));
658b40ce416SJulian Elischer 	TAILQ_REMOVE(rqh, ke, ke_procq);
659d5a08a60SJake Burkholder 	if (TAILQ_EMPTY(rqh)) {
660d5a08a60SJake Burkholder 		CTR0(KTR_RUNQ, "runq_remove: empty");
661d5a08a60SJake Burkholder 		runq_clrbit(rq, pri);
662d5a08a60SJake Burkholder 	}
663dba6c5a6SPeter Wemm }
664e602ba25SJulian Elischer 
66548bfcdddSJulian Elischer #if 0
666e602ba25SJulian Elischer static void
667e602ba25SJulian Elischer runq_readjust(struct runq *rq, struct kse *ke)
668e602ba25SJulian Elischer {
669e602ba25SJulian Elischer 
670e602ba25SJulian Elischer 	if (ke->ke_rqindex != (ke->ke_thread->td_priority / RQ_PPQ)) {
671e602ba25SJulian Elischer 		runq_remove(rq, ke);
672e602ba25SJulian Elischer 		runq_add(rq, ke);
673e602ba25SJulian Elischer 	}
674e602ba25SJulian Elischer }
67548bfcdddSJulian Elischer #endif
676e602ba25SJulian Elischer 
6775e3da64eSJulian Elischer #if 0
678e602ba25SJulian Elischer void
67948bfcdddSJulian Elischer panc(char *string1, char *string2)
68048bfcdddSJulian Elischer {
68148bfcdddSJulian Elischer 	printf("%s", string1);
68248bfcdddSJulian Elischer 	Debugger(string2);
68348bfcdddSJulian Elischer }
68448bfcdddSJulian Elischer 
68548bfcdddSJulian Elischer void
68648bfcdddSJulian Elischer thread_sanity_check(struct thread *td, char *string)
687e602ba25SJulian Elischer {
688e602ba25SJulian Elischer 	struct proc *p;
689e602ba25SJulian Elischer 	struct ksegrp *kg;
690e602ba25SJulian Elischer 	struct kse *ke;
69148bfcdddSJulian Elischer 	struct thread *td2 = NULL;
692e602ba25SJulian Elischer 	unsigned int prevpri;
69348bfcdddSJulian Elischer 	int	saw_lastassigned = 0;
69448bfcdddSJulian Elischer 	int unassigned = 0;
69548bfcdddSJulian Elischer 	int assigned = 0;
696e602ba25SJulian Elischer 
697e602ba25SJulian Elischer 	p = td->td_proc;
698e602ba25SJulian Elischer 	kg = td->td_ksegrp;
699e602ba25SJulian Elischer 	ke = td->td_kse;
700e602ba25SJulian Elischer 
701e602ba25SJulian Elischer 
702e602ba25SJulian Elischer 	if (ke) {
7034f0db5e0SJulian Elischer 		if (p != ke->ke_proc) {
70448bfcdddSJulian Elischer 			panc(string, "wrong proc");
705e602ba25SJulian Elischer 		}
706e602ba25SJulian Elischer 		if (ke->ke_thread != td) {
70748bfcdddSJulian Elischer 			panc(string, "wrong thread");
708e602ba25SJulian Elischer 		}
709e602ba25SJulian Elischer 	}
710e602ba25SJulian Elischer 
711e602ba25SJulian Elischer 	if ((p->p_flag & P_KSES) == 0) {
712e602ba25SJulian Elischer 		if (ke == NULL) {
71348bfcdddSJulian Elischer 			panc(string, "non KSE thread lost kse");
714e602ba25SJulian Elischer 		}
715e602ba25SJulian Elischer 	} else {
716e602ba25SJulian Elischer 		prevpri = 0;
717e602ba25SJulian Elischer 		saw_lastassigned = 0;
718e602ba25SJulian Elischer 		unassigned = 0;
719e602ba25SJulian Elischer 		assigned = 0;
720e602ba25SJulian Elischer 		TAILQ_FOREACH(td2, &kg->kg_runq, td_runq) {
721e602ba25SJulian Elischer 			if (td2->td_priority < prevpri) {
72248bfcdddSJulian Elischer 				panc(string, "thread runqueue unosorted");
72348bfcdddSJulian Elischer 			}
72448bfcdddSJulian Elischer 			if ((td2->td_state == TDS_RUNQ) &&
72548bfcdddSJulian Elischer 			    td2->td_kse &&
72648bfcdddSJulian Elischer 			    (td2->td_kse->ke_state != KES_ONRUNQ)) {
72748bfcdddSJulian Elischer 				panc(string, "KSE wrong state");
728e602ba25SJulian Elischer 			}
729e602ba25SJulian Elischer 			prevpri = td2->td_priority;
730e602ba25SJulian Elischer 			if (td2->td_kse) {
731e602ba25SJulian Elischer 				assigned++;
732e602ba25SJulian Elischer 				if (unassigned) {
73348bfcdddSJulian Elischer 					panc(string, "unassigned before assigned");
734e602ba25SJulian Elischer 				}
735e602ba25SJulian Elischer  				if  (kg->kg_last_assigned == NULL) {
73648bfcdddSJulian Elischer 					panc(string, "lastassigned corrupt");
737e602ba25SJulian Elischer 				}
738e602ba25SJulian Elischer 				if (saw_lastassigned) {
73948bfcdddSJulian Elischer 					panc(string, "last assigned not last");
740e602ba25SJulian Elischer 				}
741e602ba25SJulian Elischer 				if (td2->td_kse->ke_thread != td2) {
74248bfcdddSJulian Elischer 					panc(string, "mismatched kse/thread");
743e602ba25SJulian Elischer 				}
744e602ba25SJulian Elischer 			} else {
745e602ba25SJulian Elischer 				unassigned++;
746e602ba25SJulian Elischer 			}
747e602ba25SJulian Elischer 			if (td2 == kg->kg_last_assigned) {
748e602ba25SJulian Elischer 				saw_lastassigned = 1;
749e602ba25SJulian Elischer 				if (td2->td_kse == NULL) {
75048bfcdddSJulian Elischer 					panc(string, "last assigned not assigned");
751e602ba25SJulian Elischer 				}
752e602ba25SJulian Elischer 			}
753e602ba25SJulian Elischer 		}
754e602ba25SJulian Elischer 		if (kg->kg_last_assigned && (saw_lastassigned == 0)) {
75548bfcdddSJulian Elischer 			panc(string, "where on earth does lastassigned point?");
756e602ba25SJulian Elischer 		}
757e602ba25SJulian Elischer 		FOREACH_THREAD_IN_GROUP(kg, td2) {
758e602ba25SJulian Elischer 			if (((td2->td_flags & TDF_UNBOUND) == 0) &&
75971fad9fdSJulian Elischer 			    (TD_ON_RUNQ(td2))) {
760e602ba25SJulian Elischer 				assigned++;
761e602ba25SJulian Elischer 				if (td2->td_kse == NULL) {
76248bfcdddSJulian Elischer 					panc(string, "BOUND thread with no KSE");
763e602ba25SJulian Elischer 				}
764e602ba25SJulian Elischer 			}
765e602ba25SJulian Elischer 		}
766e602ba25SJulian Elischer #if 0
767e602ba25SJulian Elischer 		if ((unassigned + assigned) != kg->kg_runnable) {
76848bfcdddSJulian Elischer 			panc(string, "wrong number in runnable");
769e602ba25SJulian Elischer 		}
770e602ba25SJulian Elischer #endif
771e602ba25SJulian Elischer 	}
77248bfcdddSJulian Elischer 	if (assigned == 12345) {
77348bfcdddSJulian Elischer 		printf("%p %p %p %p %p %d, %d",
77448bfcdddSJulian Elischer 		    td, td2, ke, kg, p, assigned, saw_lastassigned);
77548bfcdddSJulian Elischer 	}
776e602ba25SJulian Elischer }
7775e3da64eSJulian Elischer #endif
778e602ba25SJulian Elischer 
779