xref: /freebsd/sys/kern/kern_switch.c (revision cc66ebe2a9c6a435e7bb694ab47f2c98e6ee7eb2)
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>
101cc66ebe2SPeter Wemm #if defined(SMP) && defined(__i386__)
102cc66ebe2SPeter Wemm #include <sys/smp.h>
103cc66ebe2SPeter Wemm #endif
104182da820SMatthew Dillon #include <machine/critical.h>
105dba6c5a6SPeter Wemm 
106d2ac2316SJake Burkholder CTASSERT((RQB_BPW * RQB_LEN) == RQ_NQS);
107d2ac2316SJake Burkholder 
10848bfcdddSJulian Elischer void panc(char *string1, char *string2);
10948bfcdddSJulian Elischer 
11048bfcdddSJulian Elischer #if 0
111e602ba25SJulian Elischer static void runq_readjust(struct runq *rq, struct kse *ke);
11248bfcdddSJulian Elischer #endif
113e602ba25SJulian Elischer /************************************************************************
114e602ba25SJulian Elischer  * Functions that manipulate runnability from a thread perspective.	*
115e602ba25SJulian Elischer  ************************************************************************/
116e602ba25SJulian Elischer /*
1175215b187SJeff Roberson  * Select the KSE that will be run next.  From that find the thread, and
118e602ba25SJulian Elischer  * remove it from the KSEGRP's run queue.  If there is thread clustering,
119e602ba25SJulian Elischer  * this will be what does it.
120e602ba25SJulian Elischer  */
121b40ce416SJulian Elischer struct thread *
122b40ce416SJulian Elischer choosethread(void)
123dba6c5a6SPeter Wemm {
124e602ba25SJulian Elischer 	struct kse *ke;
125e602ba25SJulian Elischer 	struct thread *td;
126e602ba25SJulian Elischer 	struct ksegrp *kg;
127e602ba25SJulian Elischer 
128cc66ebe2SPeter Wemm #if defined(SMP) && defined(__i386__)
129cc66ebe2SPeter Wemm 	if (smp_active == 0 && PCPU_GET(cpuid) != 0) {
130cc66ebe2SPeter Wemm 		/* Shutting down, run idlethread on AP's */
131cc66ebe2SPeter Wemm 		td = PCPU_GET(idlethread);
132cc66ebe2SPeter Wemm 		ke = td->td_kse;
133cc66ebe2SPeter Wemm 		CTR1(KTR_RUNQ, "choosethread: td=%p (idle)", td);
134cc66ebe2SPeter Wemm 		ke->ke_flags |= KEF_DIDRUN;
135cc66ebe2SPeter Wemm 		TD_SET_RUNNING(td);
136cc66ebe2SPeter Wemm 		return (td);
137cc66ebe2SPeter Wemm 	}
138cc66ebe2SPeter Wemm #endif
139cc66ebe2SPeter Wemm 
140fe799533SAndrew Gallatin retry:
141cc66ebe2SPeter Wemm 	ke = sched_choose();
142cc66ebe2SPeter Wemm 	if (ke) {
143e602ba25SJulian Elischer 		td = ke->ke_thread;
144e602ba25SJulian Elischer 		KASSERT((td->td_kse == ke), ("kse/thread mismatch"));
145e602ba25SJulian Elischer 		kg = ke->ke_ksegrp;
146ac2e4153SJulian Elischer 		if (td->td_proc->p_flag & P_THREADED) {
14733c06e1dSJulian Elischer 			if (kg->kg_last_assigned == td) {
148e602ba25SJulian Elischer 				kg->kg_last_assigned = TAILQ_PREV(td,
149e602ba25SJulian Elischer 				    threadqueue, td_runq);
15033c06e1dSJulian Elischer 			}
151d03c79eeSDavid Xu 			TAILQ_REMOVE(&kg->kg_runq, td, td_runq);
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;
16393a7aa79SJulian Elischer 
16493a7aa79SJulian Elischer 	/*
16593a7aa79SJulian Elischer 	 * Only allow non system threads to run in panic
16693a7aa79SJulian Elischer 	 * if they are the one we are tracing.  (I think.. [JRE])
16793a7aa79SJulian Elischer 	 */
168fe799533SAndrew Gallatin 	if (panicstr && ((td->td_proc->p_flag & P_SYSTEM) == 0 &&
169fe799533SAndrew Gallatin 	    (td->td_flags & TDF_INPANIC) == 0))
170fe799533SAndrew Gallatin 		goto retry;
17193a7aa79SJulian Elischer 
17271fad9fdSJulian Elischer 	TD_SET_RUNNING(td);
173e602ba25SJulian Elischer 	return (td);
174e602ba25SJulian Elischer }
175e602ba25SJulian Elischer 
176e602ba25SJulian Elischer /*
1775215b187SJeff Roberson  * Given a surplus KSE, either assign a new runable thread to it
1785215b187SJeff Roberson  * (and put it in the run queue) or put it in the ksegrp's idle KSE list.
1794f6cfa45SDavid Xu  * Assumes that the original thread is not runnable.
180e602ba25SJulian Elischer  */
181e602ba25SJulian Elischer void
182e602ba25SJulian Elischer kse_reassign(struct kse *ke)
183e602ba25SJulian Elischer {
184e602ba25SJulian Elischer 	struct ksegrp *kg;
185e602ba25SJulian Elischer 	struct thread *td;
18648bfcdddSJulian Elischer 	struct thread *original;
187e602ba25SJulian Elischer 
18833c06e1dSJulian Elischer 	mtx_assert(&sched_lock, MA_OWNED);
1896f8132a8SJulian Elischer 	original = ke->ke_thread;
1905215b187SJeff Roberson 	KASSERT(original == NULL || TD_IS_INHIBITED(original),
1915215b187SJeff Roberson     	    ("reassigning KSE with runnable thread"));
1925215b187SJeff Roberson 	kg = ke->ke_ksegrp;
1936ce75196SDavid Xu 	if (original)
1945215b187SJeff Roberson 		original->td_kse = NULL;
195e602ba25SJulian Elischer 
196e602ba25SJulian Elischer 	/*
1976f8132a8SJulian Elischer 	 * Find the first unassigned thread
1986f8132a8SJulian Elischer 	 */
1995215b187SJeff Roberson 	if ((td = kg->kg_last_assigned) != NULL)
2006f8132a8SJulian Elischer 		td = TAILQ_NEXT(td, td_runq);
2015215b187SJeff Roberson 	else
2026f8132a8SJulian Elischer 		td = TAILQ_FIRST(&kg->kg_runq);
2036f8132a8SJulian Elischer 
2046f8132a8SJulian Elischer 	/*
2055215b187SJeff Roberson 	 * If we found one, assign it the kse, otherwise idle the kse.
206e602ba25SJulian Elischer 	 */
207e602ba25SJulian Elischer 	if (td) {
208e602ba25SJulian Elischer 		kg->kg_last_assigned = td;
209e602ba25SJulian Elischer 		td->td_kse = ke;
210e602ba25SJulian Elischer 		ke->ke_thread = td;
211b43179fbSJeff Roberson 		sched_add(ke);
212e602ba25SJulian Elischer 		CTR2(KTR_RUNQ, "kse_reassign: ke%p -> td%p", ke, td);
21348bfcdddSJulian Elischer 		return;
21448bfcdddSJulian Elischer 	}
21548bfcdddSJulian Elischer 
2165215b187SJeff Roberson 	ke->ke_state = KES_IDLE;
21793a7aa79SJulian Elischer 	ke->ke_thread = NULL;
2185215b187SJeff Roberson 	TAILQ_INSERT_TAIL(&kg->kg_iq, ke, ke_kgrlist);
2195215b187SJeff Roberson 	kg->kg_idle_kses++;
2205215b187SJeff Roberson 	CTR1(KTR_RUNQ, "kse_reassign: ke%p on idle queue", ke);
22148bfcdddSJulian Elischer 	return;
222d5a08a60SJake Burkholder }
223d5a08a60SJake Burkholder 
2241f955e2dSJulian Elischer #if 0
225e602ba25SJulian Elischer /*
226e602ba25SJulian Elischer  * Remove a thread from its KSEGRP's run queue.
227e602ba25SJulian Elischer  * This in turn may remove it from a KSE if it was already assigned
228e602ba25SJulian Elischer  * to one, possibly causing a new thread to be assigned to the KSE
2295215b187SJeff Roberson  * and the KSE getting a new priority.
230e602ba25SJulian Elischer  */
2311f955e2dSJulian Elischer static void
232b40ce416SJulian Elischer remrunqueue(struct thread *td)
233d5a08a60SJake Burkholder {
23448bfcdddSJulian Elischer 	struct thread *td2, *td3;
235e602ba25SJulian Elischer 	struct ksegrp *kg;
236e602ba25SJulian Elischer 	struct kse *ke;
237e602ba25SJulian Elischer 
238e602ba25SJulian Elischer 	mtx_assert(&sched_lock, MA_OWNED);
23971fad9fdSJulian Elischer 	KASSERT((TD_ON_RUNQ(td)), ("remrunqueue: Bad state on run queue"));
240e602ba25SJulian Elischer 	kg = td->td_ksegrp;
241e602ba25SJulian Elischer 	ke = td->td_kse;
242e602ba25SJulian Elischer 	CTR1(KTR_RUNQ, "remrunqueue: td%p", td);
243e602ba25SJulian Elischer 	kg->kg_runnable--;
24471fad9fdSJulian Elischer 	TD_SET_CAN_RUN(td);
2455215b187SJeff Roberson 	/*
2465215b187SJeff Roberson 	 * If it is not a threaded process, take the shortcut.
2475215b187SJeff Roberson 	 */
248ac2e4153SJulian Elischer 	if ((td->td_proc->p_flag & P_THREADED) == 0) {
249e602ba25SJulian Elischer 		/* Bring its kse with it, leave the thread attached */
250b43179fbSJeff Roberson 		sched_rem(ke);
251c3b98db0SJulian Elischer 		ke->ke_state = KES_THREAD;
252e602ba25SJulian Elischer 		return;
253d5a08a60SJake Burkholder 	}
25448bfcdddSJulian Elischer    	td3 = TAILQ_PREV(td, threadqueue, td_runq);
25548bfcdddSJulian Elischer 	TAILQ_REMOVE(&kg->kg_runq, td, td_runq);
256e602ba25SJulian Elischer 	if (ke) {
257e602ba25SJulian Elischer 		/*
258e602ba25SJulian Elischer 		 * This thread has been assigned to a KSE.
259e602ba25SJulian Elischer 		 * We need to dissociate it and try assign the
260e602ba25SJulian Elischer 		 * KSE to the next available thread. Then, we should
261e602ba25SJulian Elischer 		 * see if we need to move the KSE in the run queues.
262e602ba25SJulian Elischer 		 */
26393a7aa79SJulian Elischer 		sched_rem(ke);
26493a7aa79SJulian Elischer 		ke->ke_state = KES_THREAD;
265e602ba25SJulian Elischer 		td2 = kg->kg_last_assigned;
266e602ba25SJulian Elischer 		KASSERT((td2 != NULL), ("last assigned has wrong value"));
26748bfcdddSJulian Elischer 		if (td2 == td)
268e602ba25SJulian Elischer 			kg->kg_last_assigned = td3;
26948bfcdddSJulian Elischer 		kse_reassign(ke);
270e602ba25SJulian Elischer 	}
271e602ba25SJulian Elischer }
2721f955e2dSJulian Elischer #endif
2731f955e2dSJulian Elischer 
2741f955e2dSJulian Elischer /*
2751f955e2dSJulian Elischer  * Change the priority of a thread that is on the run queue.
2761f955e2dSJulian Elischer  */
2771f955e2dSJulian Elischer void
2781f955e2dSJulian Elischer adjustrunqueue( struct thread *td, int newpri)
2791f955e2dSJulian Elischer {
2801f955e2dSJulian Elischer 	struct ksegrp *kg;
2811f955e2dSJulian Elischer 	struct kse *ke;
2821f955e2dSJulian Elischer 
2831f955e2dSJulian Elischer 	mtx_assert(&sched_lock, MA_OWNED);
2841f955e2dSJulian Elischer 	KASSERT((TD_ON_RUNQ(td)), ("adjustrunqueue: Bad state on run queue"));
2855215b187SJeff Roberson 
2861f955e2dSJulian Elischer 	ke = td->td_kse;
2871f955e2dSJulian Elischer 	CTR1(KTR_RUNQ, "adjustrunqueue: td%p", td);
2885215b187SJeff Roberson 	/*
2895215b187SJeff Roberson 	 * If it is not a threaded process, take the shortcut.
2905215b187SJeff Roberson 	 */
291ac2e4153SJulian Elischer 	if ((td->td_proc->p_flag & P_THREADED) == 0) {
2921f955e2dSJulian Elischer 		/* We only care about the kse in the run queue. */
29324c5baaeSJulian Elischer 		td->td_priority = newpri;
2941f955e2dSJulian Elischer 		if (ke->ke_rqindex != (newpri / RQ_PPQ)) {
2951f955e2dSJulian Elischer 			sched_rem(ke);
2961f955e2dSJulian Elischer 			sched_add(ke);
2971f955e2dSJulian Elischer 		}
2981f955e2dSJulian Elischer 		return;
2991f955e2dSJulian Elischer 	}
3005215b187SJeff Roberson 
3015215b187SJeff Roberson 	/* It is a threaded process */
3021f955e2dSJulian Elischer 	kg = td->td_ksegrp;
3031f955e2dSJulian Elischer 	kg->kg_runnable--;
3041f955e2dSJulian Elischer 	TD_SET_CAN_RUN(td);
3051f955e2dSJulian Elischer 	if (ke) {
3061f955e2dSJulian Elischer 		if (kg->kg_last_assigned == td) {
3071f955e2dSJulian Elischer 			kg->kg_last_assigned =
3081f955e2dSJulian Elischer 			    TAILQ_PREV(td, threadqueue, td_runq);
3091f955e2dSJulian Elischer 		}
3101f955e2dSJulian Elischer 		sched_rem(ke);
3111f955e2dSJulian Elischer 	}
3121f955e2dSJulian Elischer 	TAILQ_REMOVE(&kg->kg_runq, td, td_runq);
3131f955e2dSJulian Elischer 	td->td_priority = newpri;
3141f955e2dSJulian Elischer 	setrunqueue(td);
3151f955e2dSJulian Elischer }
316e602ba25SJulian Elischer 
317d5a08a60SJake Burkholder void
318b40ce416SJulian Elischer setrunqueue(struct thread *td)
319d5a08a60SJake Burkholder {
320e602ba25SJulian Elischer 	struct kse *ke;
321e602ba25SJulian Elischer 	struct ksegrp *kg;
322e602ba25SJulian Elischer 	struct thread *td2;
323e602ba25SJulian Elischer 	struct thread *tda;
324e602ba25SJulian Elischer 
325e602ba25SJulian Elischer 	CTR1(KTR_RUNQ, "setrunqueue: td%p", td);
326e602ba25SJulian Elischer 	mtx_assert(&sched_lock, MA_OWNED);
32771fad9fdSJulian Elischer 	KASSERT((TD_CAN_RUN(td) || TD_IS_RUNNING(td)),
32871fad9fdSJulian Elischer 	    ("setrunqueue: bad thread state"));
32971fad9fdSJulian Elischer 	TD_SET_RUNQ(td);
330e602ba25SJulian Elischer 	kg = td->td_ksegrp;
331e602ba25SJulian Elischer 	kg->kg_runnable++;
332ac2e4153SJulian Elischer 	if ((td->td_proc->p_flag & P_THREADED) == 0) {
33348bfcdddSJulian Elischer 		/*
33448bfcdddSJulian Elischer 		 * Common path optimisation: Only one of everything
33548bfcdddSJulian Elischer 		 * and the KSE is always already attached.
33648bfcdddSJulian Elischer 		 * Totally ignore the ksegrp run queue.
33748bfcdddSJulian Elischer 		 */
338b43179fbSJeff Roberson 		sched_add(td->td_kse);
33948bfcdddSJulian Elischer 		return;
34048bfcdddSJulian Elischer 	}
34148bfcdddSJulian Elischer 
342e602ba25SJulian Elischer 	tda = kg->kg_last_assigned;
343e602ba25SJulian Elischer 	if ((ke = td->td_kse) == NULL) {
3445215b187SJeff Roberson 		if (kg->kg_idle_kses) {
345e602ba25SJulian Elischer 			/*
3465215b187SJeff Roberson 			 * There is a free one so it's ours for the asking..
347e602ba25SJulian Elischer 			 */
3485215b187SJeff Roberson 			ke = TAILQ_FIRST(&kg->kg_iq);
3495215b187SJeff Roberson 			TAILQ_REMOVE(&kg->kg_iq, ke, ke_kgrlist);
3509eb1fdeaSJulian Elischer 			ke->ke_state = KES_THREAD;
3515215b187SJeff Roberson 			kg->kg_idle_kses--;
352e602ba25SJulian Elischer 		} else if (tda && (tda->td_priority > td->td_priority)) {
353e602ba25SJulian Elischer 			/*
354e602ba25SJulian Elischer 			 * None free, but there is one we can commandeer.
355e602ba25SJulian Elischer 			 */
356e602ba25SJulian Elischer 			ke = tda->td_kse;
357e602ba25SJulian Elischer 			tda->td_kse = NULL;
358e602ba25SJulian Elischer 			ke->ke_thread = NULL;
359e602ba25SJulian Elischer 			tda = kg->kg_last_assigned =
360e602ba25SJulian Elischer 		    	    TAILQ_PREV(tda, threadqueue, td_runq);
361b43179fbSJeff Roberson 			sched_rem(ke);
362e602ba25SJulian Elischer 		}
363e602ba25SJulian Elischer 	} else {
364c3b98db0SJulian Elischer 		/*
365c3b98db0SJulian Elischer 		 * Temporarily disassociate so it looks like the other cases.
366c3b98db0SJulian Elischer 		 */
367e602ba25SJulian Elischer 		ke->ke_thread = NULL;
368e602ba25SJulian Elischer 		td->td_kse = NULL;
369d5a08a60SJake Burkholder 	}
370d5a08a60SJake Burkholder 
371e602ba25SJulian Elischer 	/*
372e602ba25SJulian Elischer 	 * Add the thread to the ksegrp's run queue at
373e602ba25SJulian Elischer 	 * the appropriate place.
374e602ba25SJulian Elischer 	 */
375e602ba25SJulian Elischer 	TAILQ_FOREACH(td2, &kg->kg_runq, td_runq) {
376e602ba25SJulian Elischer 		if (td2->td_priority > td->td_priority) {
377e602ba25SJulian Elischer 			TAILQ_INSERT_BEFORE(td2, td, td_runq);
378e602ba25SJulian Elischer 			break;
379e602ba25SJulian Elischer 		}
380e602ba25SJulian Elischer 	}
381e602ba25SJulian Elischer 	if (td2 == NULL) {
382e602ba25SJulian Elischer 		/* We ran off the end of the TAILQ or it was empty. */
383e602ba25SJulian Elischer 		TAILQ_INSERT_TAIL(&kg->kg_runq, td, td_runq);
384e602ba25SJulian Elischer 	}
385e602ba25SJulian Elischer 
386e602ba25SJulian Elischer 	/*
387e602ba25SJulian Elischer 	 * If we have a ke to use, then put it on the run queue and
388e602ba25SJulian Elischer 	 * If needed, readjust the last_assigned pointer.
389e602ba25SJulian Elischer 	 */
390e602ba25SJulian Elischer 	if (ke) {
391e602ba25SJulian Elischer 		if (tda == NULL) {
392e602ba25SJulian Elischer 			/*
393e602ba25SJulian Elischer 			 * No pre-existing last assigned so whoever is first
394c3b98db0SJulian Elischer 			 * gets the KSE we brought in.. (maybe us)
395e602ba25SJulian Elischer 			 */
396e602ba25SJulian Elischer 			td2 = TAILQ_FIRST(&kg->kg_runq);
397e602ba25SJulian Elischer 			KASSERT((td2->td_kse == NULL),
398e602ba25SJulian Elischer 			    ("unexpected ke present"));
399e602ba25SJulian Elischer 			td2->td_kse = ke;
400e602ba25SJulian Elischer 			ke->ke_thread = td2;
401e602ba25SJulian Elischer 			kg->kg_last_assigned = td2;
402e602ba25SJulian Elischer 		} else if (tda->td_priority > td->td_priority) {
403e602ba25SJulian Elischer 			/*
404e602ba25SJulian Elischer 			 * It's ours, grab it, but last_assigned is past us
405e602ba25SJulian Elischer 			 * so don't change it.
406e602ba25SJulian Elischer 			 */
407e602ba25SJulian Elischer 			td->td_kse = ke;
408e602ba25SJulian Elischer 			ke->ke_thread = td;
409e602ba25SJulian Elischer 		} else {
410e602ba25SJulian Elischer 			/*
411e602ba25SJulian Elischer 			 * We are past last_assigned, so
412e602ba25SJulian Elischer 			 * put the new kse on whatever is next,
413e602ba25SJulian Elischer 			 * which may or may not be us.
414e602ba25SJulian Elischer 			 */
415e602ba25SJulian Elischer 			td2 = TAILQ_NEXT(tda, td_runq);
416e602ba25SJulian Elischer 			kg->kg_last_assigned = td2;
417e602ba25SJulian Elischer 			td2->td_kse = ke;
418e602ba25SJulian Elischer 			ke->ke_thread = td2;
419e602ba25SJulian Elischer 		}
420b43179fbSJeff Roberson 		sched_add(ke);
421e602ba25SJulian Elischer 	}
422e602ba25SJulian Elischer }
423e602ba25SJulian Elischer 
424e602ba25SJulian Elischer /************************************************************************
425e602ba25SJulian Elischer  * Critical section marker functions					*
426e602ba25SJulian Elischer  ************************************************************************/
4277e1f6dfeSJohn Baldwin /* Critical sections that prevent preemption. */
4287e1f6dfeSJohn Baldwin void
4297e1f6dfeSJohn Baldwin critical_enter(void)
4307e1f6dfeSJohn Baldwin {
4317e1f6dfeSJohn Baldwin 	struct thread *td;
4327e1f6dfeSJohn Baldwin 
4337e1f6dfeSJohn Baldwin 	td = curthread;
4347e1f6dfeSJohn Baldwin 	if (td->td_critnest == 0)
435d74ac681SMatthew Dillon 		cpu_critical_enter();
4367e1f6dfeSJohn Baldwin 	td->td_critnest++;
4377e1f6dfeSJohn Baldwin }
4387e1f6dfeSJohn Baldwin 
4397e1f6dfeSJohn Baldwin void
4407e1f6dfeSJohn Baldwin critical_exit(void)
4417e1f6dfeSJohn Baldwin {
4427e1f6dfeSJohn Baldwin 	struct thread *td;
4437e1f6dfeSJohn Baldwin 
4447e1f6dfeSJohn Baldwin 	td = curthread;
4457e1f6dfeSJohn Baldwin 	if (td->td_critnest == 1) {
4467e1f6dfeSJohn Baldwin 		td->td_critnest = 0;
447d74ac681SMatthew Dillon 		cpu_critical_exit();
448d74ac681SMatthew Dillon 	} else {
4497e1f6dfeSJohn Baldwin 		td->td_critnest--;
4507e1f6dfeSJohn Baldwin 	}
451d74ac681SMatthew Dillon }
4527e1f6dfeSJohn Baldwin 
453e602ba25SJulian Elischer 
454e602ba25SJulian Elischer /************************************************************************
455e602ba25SJulian Elischer  * SYSTEM RUN QUEUE manipulations and tests				*
456e602ba25SJulian Elischer  ************************************************************************/
457e602ba25SJulian Elischer /*
458e602ba25SJulian Elischer  * Initialize a run structure.
459e602ba25SJulian Elischer  */
460e602ba25SJulian Elischer void
461e602ba25SJulian Elischer runq_init(struct runq *rq)
462e602ba25SJulian Elischer {
463e602ba25SJulian Elischer 	int i;
464e602ba25SJulian Elischer 
465e602ba25SJulian Elischer 	bzero(rq, sizeof *rq);
466e602ba25SJulian Elischer 	for (i = 0; i < RQ_NQS; i++)
467e602ba25SJulian Elischer 		TAILQ_INIT(&rq->rq_queues[i]);
468e602ba25SJulian Elischer }
469e602ba25SJulian Elischer 
470d5a08a60SJake Burkholder /*
471d5a08a60SJake Burkholder  * Clear the status bit of the queue corresponding to priority level pri,
472d5a08a60SJake Burkholder  * indicating that it is empty.
473d5a08a60SJake Burkholder  */
474d5a08a60SJake Burkholder static __inline void
475d5a08a60SJake Burkholder runq_clrbit(struct runq *rq, int pri)
476d5a08a60SJake Burkholder {
477d5a08a60SJake Burkholder 	struct rqbits *rqb;
478d5a08a60SJake Burkholder 
479d5a08a60SJake Burkholder 	rqb = &rq->rq_status;
480d5a08a60SJake Burkholder 	CTR4(KTR_RUNQ, "runq_clrbit: bits=%#x %#x bit=%#x word=%d",
481d5a08a60SJake Burkholder 	    rqb->rqb_bits[RQB_WORD(pri)],
482d5a08a60SJake Burkholder 	    rqb->rqb_bits[RQB_WORD(pri)] & ~RQB_BIT(pri),
483d5a08a60SJake Burkholder 	    RQB_BIT(pri), RQB_WORD(pri));
484d5a08a60SJake Burkholder 	rqb->rqb_bits[RQB_WORD(pri)] &= ~RQB_BIT(pri);
485d5a08a60SJake Burkholder }
486d5a08a60SJake Burkholder 
487d5a08a60SJake Burkholder /*
488d5a08a60SJake Burkholder  * Find the index of the first non-empty run queue.  This is done by
489d5a08a60SJake Burkholder  * scanning the status bits, a set bit indicates a non-empty queue.
490d5a08a60SJake Burkholder  */
491d5a08a60SJake Burkholder static __inline int
492d5a08a60SJake Burkholder runq_findbit(struct runq *rq)
493d5a08a60SJake Burkholder {
494d5a08a60SJake Burkholder 	struct rqbits *rqb;
495d5a08a60SJake Burkholder 	int pri;
496d5a08a60SJake Burkholder 	int i;
497d5a08a60SJake Burkholder 
498d5a08a60SJake Burkholder 	rqb = &rq->rq_status;
499d5a08a60SJake Burkholder 	for (i = 0; i < RQB_LEN; i++)
500d5a08a60SJake Burkholder 		if (rqb->rqb_bits[i]) {
5012f9267ecSPeter Wemm 			pri = RQB_FFS(rqb->rqb_bits[i]) + (i << RQB_L2BPW);
502d5a08a60SJake Burkholder 			CTR3(KTR_RUNQ, "runq_findbit: bits=%#x i=%d pri=%d",
503d5a08a60SJake Burkholder 			    rqb->rqb_bits[i], i, pri);
504d5a08a60SJake Burkholder 			return (pri);
505d5a08a60SJake Burkholder 		}
506d5a08a60SJake Burkholder 
507d5a08a60SJake Burkholder 	return (-1);
508d5a08a60SJake Burkholder }
509d5a08a60SJake Burkholder 
510d5a08a60SJake Burkholder /*
511d5a08a60SJake Burkholder  * Set the status bit of the queue corresponding to priority level pri,
512d5a08a60SJake Burkholder  * indicating that it is non-empty.
513d5a08a60SJake Burkholder  */
514d5a08a60SJake Burkholder static __inline void
515d5a08a60SJake Burkholder runq_setbit(struct runq *rq, int pri)
516d5a08a60SJake Burkholder {
517d5a08a60SJake Burkholder 	struct rqbits *rqb;
518d5a08a60SJake Burkholder 
519d5a08a60SJake Burkholder 	rqb = &rq->rq_status;
520d5a08a60SJake Burkholder 	CTR4(KTR_RUNQ, "runq_setbit: bits=%#x %#x bit=%#x word=%d",
521d5a08a60SJake Burkholder 	    rqb->rqb_bits[RQB_WORD(pri)],
522d5a08a60SJake Burkholder 	    rqb->rqb_bits[RQB_WORD(pri)] | RQB_BIT(pri),
523d5a08a60SJake Burkholder 	    RQB_BIT(pri), RQB_WORD(pri));
524d5a08a60SJake Burkholder 	rqb->rqb_bits[RQB_WORD(pri)] |= RQB_BIT(pri);
525d5a08a60SJake Burkholder }
526d5a08a60SJake Burkholder 
527d5a08a60SJake Burkholder /*
528e602ba25SJulian Elischer  * Add the KSE to the queue specified by its priority, and set the
529d5a08a60SJake Burkholder  * corresponding status bit.
530d5a08a60SJake Burkholder  */
531d5a08a60SJake Burkholder void
532b40ce416SJulian Elischer runq_add(struct runq *rq, struct kse *ke)
533d5a08a60SJake Burkholder {
534d5a08a60SJake Burkholder 	struct rqhead *rqh;
535d5a08a60SJake Burkholder 	int pri;
536dba6c5a6SPeter Wemm 
5372c100766SJulian Elischer 	pri = ke->ke_thread->td_priority / RQ_PPQ;
538b40ce416SJulian Elischer 	ke->ke_rqindex = pri;
539d5a08a60SJake Burkholder 	runq_setbit(rq, pri);
540d5a08a60SJake Burkholder 	rqh = &rq->rq_queues[pri];
541d5a08a60SJake Burkholder 	CTR4(KTR_RUNQ, "runq_add: p=%p pri=%d %d rqh=%p",
5422c100766SJulian Elischer 	    ke->ke_proc, ke->ke_thread->td_priority, pri, rqh);
543b40ce416SJulian Elischer 	TAILQ_INSERT_TAIL(rqh, ke, ke_procq);
544dba6c5a6SPeter Wemm }
545d5a08a60SJake Burkholder 
546d5a08a60SJake Burkholder /*
547d5a08a60SJake Burkholder  * Return true if there are runnable processes of any priority on the run
548d5a08a60SJake Burkholder  * queue, false otherwise.  Has no side effects, does not modify the run
549d5a08a60SJake Burkholder  * queue structure.
550d5a08a60SJake Burkholder  */
551d5a08a60SJake Burkholder int
552d5a08a60SJake Burkholder runq_check(struct runq *rq)
553d5a08a60SJake Burkholder {
554d5a08a60SJake Burkholder 	struct rqbits *rqb;
555d5a08a60SJake Burkholder 	int i;
556d5a08a60SJake Burkholder 
557d5a08a60SJake Burkholder 	rqb = &rq->rq_status;
558d5a08a60SJake Burkholder 	for (i = 0; i < RQB_LEN; i++)
559d5a08a60SJake Burkholder 		if (rqb->rqb_bits[i]) {
560d5a08a60SJake Burkholder 			CTR2(KTR_RUNQ, "runq_check: bits=%#x i=%d",
561d5a08a60SJake Burkholder 			    rqb->rqb_bits[i], i);
562d5a08a60SJake Burkholder 			return (1);
563dba6c5a6SPeter Wemm 		}
564d5a08a60SJake Burkholder 	CTR0(KTR_RUNQ, "runq_check: empty");
565d5a08a60SJake Burkholder 
566d5a08a60SJake Burkholder 	return (0);
567dba6c5a6SPeter Wemm }
568d5a08a60SJake Burkholder 
569d5a08a60SJake Burkholder /*
570b43179fbSJeff Roberson  * Find the highest priority process on the run queue.
571d5a08a60SJake Burkholder  */
572b40ce416SJulian Elischer struct kse *
573d5a08a60SJake Burkholder runq_choose(struct runq *rq)
574d5a08a60SJake Burkholder {
575d5a08a60SJake Burkholder 	struct rqhead *rqh;
576b40ce416SJulian Elischer 	struct kse *ke;
577d5a08a60SJake Burkholder 	int pri;
578d5a08a60SJake Burkholder 
579d5a08a60SJake Burkholder 	mtx_assert(&sched_lock, MA_OWNED);
580e602ba25SJulian Elischer 	while ((pri = runq_findbit(rq)) != -1) {
581d5a08a60SJake Burkholder 		rqh = &rq->rq_queues[pri];
582b40ce416SJulian Elischer 		ke = TAILQ_FIRST(rqh);
583b40ce416SJulian Elischer 		KASSERT(ke != NULL, ("runq_choose: no proc on busy queue"));
584e602ba25SJulian Elischer 		CTR3(KTR_RUNQ,
585e602ba25SJulian Elischer 		    "runq_choose: pri=%d kse=%p rqh=%p", pri, ke, rqh);
586b40ce416SJulian Elischer 		return (ke);
587d5a08a60SJake Burkholder 	}
588d5a08a60SJake Burkholder 	CTR1(KTR_RUNQ, "runq_choose: idleproc pri=%d", pri);
589d5a08a60SJake Burkholder 
590e602ba25SJulian Elischer 	return (NULL);
591d5a08a60SJake Burkholder }
592d5a08a60SJake Burkholder 
593d5a08a60SJake Burkholder /*
594e602ba25SJulian Elischer  * Remove the KSE from the queue specified by its priority, and clear the
595d5a08a60SJake Burkholder  * corresponding status bit if the queue becomes empty.
596e602ba25SJulian Elischer  * Caller must set ke->ke_state afterwards.
597d5a08a60SJake Burkholder  */
598d5a08a60SJake Burkholder void
599b40ce416SJulian Elischer runq_remove(struct runq *rq, struct kse *ke)
600d5a08a60SJake Burkholder {
601d5a08a60SJake Burkholder 	struct rqhead *rqh;
602d5a08a60SJake Burkholder 	int pri;
603d5a08a60SJake Burkholder 
6049eb881f8SSeigo Tanimura 	KASSERT(ke->ke_proc->p_sflag & PS_INMEM,
6059eb881f8SSeigo Tanimura 		("runq_remove: process swapped out"));
606b40ce416SJulian Elischer 	pri = ke->ke_rqindex;
607d5a08a60SJake Burkholder 	rqh = &rq->rq_queues[pri];
608d5a08a60SJake Burkholder 	CTR4(KTR_RUNQ, "runq_remove: p=%p pri=%d %d rqh=%p",
6092c100766SJulian Elischer 	    ke, ke->ke_thread->td_priority, pri, rqh);
610b40ce416SJulian Elischer 	KASSERT(ke != NULL, ("runq_remove: no proc on busy queue"));
611b40ce416SJulian Elischer 	TAILQ_REMOVE(rqh, ke, ke_procq);
612d5a08a60SJake Burkholder 	if (TAILQ_EMPTY(rqh)) {
613d5a08a60SJake Burkholder 		CTR0(KTR_RUNQ, "runq_remove: empty");
614d5a08a60SJake Burkholder 		runq_clrbit(rq, pri);
615d5a08a60SJake Burkholder 	}
616dba6c5a6SPeter Wemm }
617e602ba25SJulian Elischer 
61848bfcdddSJulian Elischer #if 0
619e602ba25SJulian Elischer void
62048bfcdddSJulian Elischer panc(char *string1, char *string2)
62148bfcdddSJulian Elischer {
62248bfcdddSJulian Elischer 	printf("%s", string1);
62348bfcdddSJulian Elischer 	Debugger(string2);
62448bfcdddSJulian Elischer }
62548bfcdddSJulian Elischer 
62648bfcdddSJulian Elischer void
62748bfcdddSJulian Elischer thread_sanity_check(struct thread *td, char *string)
628e602ba25SJulian Elischer {
629e602ba25SJulian Elischer 	struct proc *p;
630e602ba25SJulian Elischer 	struct ksegrp *kg;
631e602ba25SJulian Elischer 	struct kse *ke;
63248bfcdddSJulian Elischer 	struct thread *td2 = NULL;
633e602ba25SJulian Elischer 	unsigned int prevpri;
63448bfcdddSJulian Elischer 	int	saw_lastassigned = 0;
63548bfcdddSJulian Elischer 	int unassigned = 0;
63648bfcdddSJulian Elischer 	int assigned = 0;
637e602ba25SJulian Elischer 
638e602ba25SJulian Elischer 	p = td->td_proc;
639e602ba25SJulian Elischer 	kg = td->td_ksegrp;
640e602ba25SJulian Elischer 	ke = td->td_kse;
641e602ba25SJulian Elischer 
642e602ba25SJulian Elischer 
643e602ba25SJulian Elischer 	if (ke) {
6444f0db5e0SJulian Elischer 		if (p != ke->ke_proc) {
64548bfcdddSJulian Elischer 			panc(string, "wrong proc");
646e602ba25SJulian Elischer 		}
647e602ba25SJulian Elischer 		if (ke->ke_thread != td) {
64848bfcdddSJulian Elischer 			panc(string, "wrong thread");
649e602ba25SJulian Elischer 		}
650e602ba25SJulian Elischer 	}
651e602ba25SJulian Elischer 
652ac2e4153SJulian Elischer 	if ((p->p_flag & P_THREADED) == 0) {
653e602ba25SJulian Elischer 		if (ke == NULL) {
65448bfcdddSJulian Elischer 			panc(string, "non KSE thread lost kse");
655e602ba25SJulian Elischer 		}
656e602ba25SJulian Elischer 	} else {
657e602ba25SJulian Elischer 		prevpri = 0;
658e602ba25SJulian Elischer 		saw_lastassigned = 0;
659e602ba25SJulian Elischer 		unassigned = 0;
660e602ba25SJulian Elischer 		assigned = 0;
661e602ba25SJulian Elischer 		TAILQ_FOREACH(td2, &kg->kg_runq, td_runq) {
662e602ba25SJulian Elischer 			if (td2->td_priority < prevpri) {
66348bfcdddSJulian Elischer 				panc(string, "thread runqueue unosorted");
66448bfcdddSJulian Elischer 			}
66548bfcdddSJulian Elischer 			if ((td2->td_state == TDS_RUNQ) &&
66648bfcdddSJulian Elischer 			    td2->td_kse &&
66748bfcdddSJulian Elischer 			    (td2->td_kse->ke_state != KES_ONRUNQ)) {
66848bfcdddSJulian Elischer 				panc(string, "KSE wrong state");
669e602ba25SJulian Elischer 			}
670e602ba25SJulian Elischer 			prevpri = td2->td_priority;
671e602ba25SJulian Elischer 			if (td2->td_kse) {
672e602ba25SJulian Elischer 				assigned++;
673e602ba25SJulian Elischer 				if (unassigned) {
67448bfcdddSJulian Elischer 					panc(string, "unassigned before assigned");
675e602ba25SJulian Elischer 				}
676e602ba25SJulian Elischer  				if  (kg->kg_last_assigned == NULL) {
67748bfcdddSJulian Elischer 					panc(string, "lastassigned corrupt");
678e602ba25SJulian Elischer 				}
679e602ba25SJulian Elischer 				if (saw_lastassigned) {
68048bfcdddSJulian Elischer 					panc(string, "last assigned not last");
681e602ba25SJulian Elischer 				}
682e602ba25SJulian Elischer 				if (td2->td_kse->ke_thread != td2) {
68348bfcdddSJulian Elischer 					panc(string, "mismatched kse/thread");
684e602ba25SJulian Elischer 				}
685e602ba25SJulian Elischer 			} else {
686e602ba25SJulian Elischer 				unassigned++;
687e602ba25SJulian Elischer 			}
688e602ba25SJulian Elischer 			if (td2 == kg->kg_last_assigned) {
689e602ba25SJulian Elischer 				saw_lastassigned = 1;
690e602ba25SJulian Elischer 				if (td2->td_kse == NULL) {
69148bfcdddSJulian Elischer 					panc(string, "last assigned not assigned");
692e602ba25SJulian Elischer 				}
693e602ba25SJulian Elischer 			}
694e602ba25SJulian Elischer 		}
695e602ba25SJulian Elischer 		if (kg->kg_last_assigned && (saw_lastassigned == 0)) {
69648bfcdddSJulian Elischer 			panc(string, "where on earth does lastassigned point?");
697e602ba25SJulian Elischer 		}
6985215b187SJeff Roberson #if 0
699e602ba25SJulian Elischer 		FOREACH_THREAD_IN_GROUP(kg, td2) {
700e602ba25SJulian Elischer 			if (((td2->td_flags & TDF_UNBOUND) == 0) &&
70171fad9fdSJulian Elischer 			    (TD_ON_RUNQ(td2))) {
702e602ba25SJulian Elischer 				assigned++;
703e602ba25SJulian Elischer 				if (td2->td_kse == NULL) {
70448bfcdddSJulian Elischer 					panc(string, "BOUND thread with no KSE");
705e602ba25SJulian Elischer 				}
706e602ba25SJulian Elischer 			}
707e602ba25SJulian Elischer 		}
7085215b187SJeff Roberson #endif
709e602ba25SJulian Elischer #if 0
710e602ba25SJulian Elischer 		if ((unassigned + assigned) != kg->kg_runnable) {
71148bfcdddSJulian Elischer 			panc(string, "wrong number in runnable");
712e602ba25SJulian Elischer 		}
713e602ba25SJulian Elischer #endif
714e602ba25SJulian Elischer 	}
71548bfcdddSJulian Elischer 	if (assigned == 12345) {
71648bfcdddSJulian Elischer 		printf("%p %p %p %p %p %d, %d",
71748bfcdddSJulian Elischer 		    td, td2, ke, kg, p, assigned, saw_lastassigned);
71848bfcdddSJulian Elischer 	}
719e602ba25SJulian Elischer }
7205e3da64eSJulian Elischer #endif
721e602ba25SJulian Elischer 
722