xref: /freebsd/sys/kern/kern_switch.c (revision 1335c4df323ab5b5a85097db0c9211c4c6f7a722)
19454b2d8SWarner Losh /*-
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 
27e602ba25SJulian Elischer /***
28e602ba25SJulian Elischer Here is the logic..
29e602ba25SJulian Elischer 
30e602ba25SJulian Elischer If there are N processors, then there are at most N KSEs (kernel
31e602ba25SJulian Elischer schedulable entities) working to process threads that belong to a
3209a4a69cSRobert Watson KSEGROUP (kg). If there are X of these KSEs actually running at the
33e602ba25SJulian Elischer moment in question, then there are at most M (N-X) of these KSEs on
34e602ba25SJulian Elischer the run queue, as running KSEs are not on the queue.
35e602ba25SJulian Elischer 
36e602ba25SJulian Elischer Runnable threads are queued off the KSEGROUP in priority order.
37e602ba25SJulian Elischer If there are M or more threads runnable, the top M threads
38e602ba25SJulian Elischer (by priority) are 'preassigned' to the M KSEs not running. The KSEs take
39e602ba25SJulian Elischer their priority from those threads and are put on the run queue.
40e602ba25SJulian Elischer 
41e602ba25SJulian Elischer The last thread that had a priority high enough to have a KSE associated
42e602ba25SJulian Elischer with it, AND IS ON THE RUN QUEUE is pointed to by
43e602ba25SJulian Elischer kg->kg_last_assigned. If no threads queued off the KSEGROUP have KSEs
44e602ba25SJulian Elischer assigned as all the available KSEs are activly running, or because there
45e602ba25SJulian Elischer are no threads queued, that pointer is NULL.
46e602ba25SJulian Elischer 
47e602ba25SJulian Elischer When a KSE is removed from the run queue to become runnable, we know
48e602ba25SJulian Elischer it was associated with the highest priority thread in the queue (at the head
49e602ba25SJulian Elischer of the queue). If it is also the last assigned we know M was 1 and must
50e602ba25SJulian Elischer now be 0. Since the thread is no longer queued that pointer must be
51e602ba25SJulian Elischer removed from it. Since we know there were no more KSEs available,
52e602ba25SJulian Elischer (M was 1 and is now 0) and since we are not FREEING our KSE
53e602ba25SJulian Elischer but using it, we know there are STILL no more KSEs available, we can prove
54e602ba25SJulian Elischer that the next thread in the ksegrp list will not have a KSE to assign to
55e602ba25SJulian Elischer it, so we can show that the pointer must be made 'invalid' (NULL).
56e602ba25SJulian Elischer 
57e602ba25SJulian Elischer The pointer exists so that when a new thread is made runnable, it can
58e602ba25SJulian Elischer have its priority compared with the last assigned thread to see if
59e602ba25SJulian Elischer it should 'steal' its KSE or not.. i.e. is it 'earlier'
60e602ba25SJulian Elischer on the list than that thread or later.. If it's earlier, then the KSE is
61e602ba25SJulian Elischer removed from the last assigned (which is now not assigned a KSE)
62e602ba25SJulian Elischer and reassigned to the new thread, which is placed earlier in the list.
63e602ba25SJulian Elischer The pointer is then backed up to the previous thread (which may or may not
64e602ba25SJulian Elischer be the new thread).
65e602ba25SJulian Elischer 
66e602ba25SJulian Elischer When a thread sleeps or is removed, the KSE becomes available and if there
67e602ba25SJulian Elischer are queued threads that are not assigned KSEs, the highest priority one of
68e602ba25SJulian Elischer them is assigned the KSE, which is then placed back on the run queue at
69e602ba25SJulian Elischer the approipriate place, and the kg->kg_last_assigned pointer is adjusted down
70e602ba25SJulian Elischer to point to it.
71e602ba25SJulian Elischer 
72e602ba25SJulian Elischer The following diagram shows 2 KSEs and 3 threads from a single process.
73e602ba25SJulian Elischer 
74e602ba25SJulian Elischer  RUNQ: --->KSE---KSE--...    (KSEs queued at priorities from threads)
75e602ba25SJulian Elischer               \    \____
76e602ba25SJulian Elischer                \        \
77e602ba25SJulian Elischer     KSEGROUP---thread--thread--thread    (queued in priority order)
78e602ba25SJulian Elischer         \                 /
79e602ba25SJulian Elischer          \_______________/
80e602ba25SJulian Elischer           (last_assigned)
81e602ba25SJulian Elischer 
82e602ba25SJulian Elischer The result of this scheme is that the M available KSEs are always
83e602ba25SJulian Elischer queued at the priorities they have inherrited from the M highest priority
84e602ba25SJulian Elischer threads for that KSEGROUP. If this situation changes, the KSEs are
85e602ba25SJulian Elischer reassigned to keep this true.
86677b542eSDavid E. O'Brien ***/
87e602ba25SJulian Elischer 
88677b542eSDavid E. O'Brien #include <sys/cdefs.h>
89677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$");
90e602ba25SJulian Elischer 
916804a3abSJulian Elischer #include "opt_sched.h"
920c0b25aeSJohn Baldwin 
93ed062c8dSJulian Elischer #ifndef KERN_SWITCH_INCLUDE
94dba6c5a6SPeter Wemm #include <sys/param.h>
95dba6c5a6SPeter Wemm #include <sys/systm.h>
962d50560aSMarcel Moolenaar #include <sys/kdb.h>
97dba6c5a6SPeter Wemm #include <sys/kernel.h>
980384fff8SJason Evans #include <sys/ktr.h>
99f34fa851SJohn Baldwin #include <sys/lock.h>
10035e0e5b3SJohn Baldwin #include <sys/mutex.h>
101dba6c5a6SPeter Wemm #include <sys/proc.h>
102dba6c5a6SPeter Wemm #include <sys/queue.h>
103b43179fbSJeff Roberson #include <sys/sched.h>
104ed062c8dSJulian Elischer #else  /* KERN_SWITCH_INCLUDE */
1050d2a2989SPeter Wemm #if defined(SMP) && (defined(__i386__) || defined(__amd64__))
106cc66ebe2SPeter Wemm #include <sys/smp.h>
107cc66ebe2SPeter Wemm #endif
1086804a3abSJulian Elischer #if defined(SMP) && defined(SCHED_4BSD)
1096804a3abSJulian Elischer #include <sys/sysctl.h>
1106804a3abSJulian Elischer #endif
1116804a3abSJulian Elischer 
1121335c4dfSNate Lawson /* Uncomment this to enable logging of critical_enter/exit. */
1131335c4dfSNate Lawson #if 0
1141335c4dfSNate Lawson #define	KTR_CRITICAL	KTR_SCHED
1151335c4dfSNate Lawson #else
1161335c4dfSNate Lawson #define	KTR_CRITICAL	0
1171335c4dfSNate Lawson #endif
1181335c4dfSNate Lawson 
1199923b511SScott Long #ifdef FULL_PREEMPTION
1209923b511SScott Long #ifndef PREEMPTION
1219923b511SScott Long #error "The FULL_PREEMPTION option requires the PREEMPTION option"
1229923b511SScott Long #endif
1239923b511SScott Long #endif
124dba6c5a6SPeter Wemm 
125d2ac2316SJake Burkholder CTASSERT((RQB_BPW * RQB_LEN) == RQ_NQS);
126d2ac2316SJake Burkholder 
127ed062c8dSJulian Elischer #define td_kse td_sched
128ed062c8dSJulian Elischer 
1296220dcbaSRobert Watson /*
1306220dcbaSRobert Watson  * kern.sched.preemption allows user space to determine if preemption support
1316220dcbaSRobert Watson  * is compiled in or not.  It is not currently a boot or runtime flag that
1326220dcbaSRobert Watson  * can be changed.
1336220dcbaSRobert Watson  */
1346220dcbaSRobert Watson #ifdef PREEMPTION
1356220dcbaSRobert Watson static int kern_sched_preemption = 1;
1366220dcbaSRobert Watson #else
1376220dcbaSRobert Watson static int kern_sched_preemption = 0;
1386220dcbaSRobert Watson #endif
1396220dcbaSRobert Watson SYSCTL_INT(_kern_sched, OID_AUTO, preemption, CTLFLAG_RD,
1406220dcbaSRobert Watson     &kern_sched_preemption, 0, "Kernel preemption enabled");
1416220dcbaSRobert Watson 
142e602ba25SJulian Elischer /************************************************************************
143e602ba25SJulian Elischer  * Functions that manipulate runnability from a thread perspective.	*
144e602ba25SJulian Elischer  ************************************************************************/
145e602ba25SJulian Elischer /*
1465215b187SJeff Roberson  * Select the KSE that will be run next.  From that find the thread, and
147e602ba25SJulian Elischer  * remove it from the KSEGRP's run queue.  If there is thread clustering,
148e602ba25SJulian Elischer  * this will be what does it.
149e602ba25SJulian Elischer  */
150b40ce416SJulian Elischer struct thread *
151b40ce416SJulian Elischer choosethread(void)
152dba6c5a6SPeter Wemm {
153e602ba25SJulian Elischer 	struct kse *ke;
154e602ba25SJulian Elischer 	struct thread *td;
155e602ba25SJulian Elischer 	struct ksegrp *kg;
156e602ba25SJulian Elischer 
1570d2a2989SPeter Wemm #if defined(SMP) && (defined(__i386__) || defined(__amd64__))
158cc66ebe2SPeter Wemm 	if (smp_active == 0 && PCPU_GET(cpuid) != 0) {
159cc66ebe2SPeter Wemm 		/* Shutting down, run idlethread on AP's */
160cc66ebe2SPeter Wemm 		td = PCPU_GET(idlethread);
161cc66ebe2SPeter Wemm 		ke = td->td_kse;
162cc66ebe2SPeter Wemm 		CTR1(KTR_RUNQ, "choosethread: td=%p (idle)", td);
163cc66ebe2SPeter Wemm 		ke->ke_flags |= KEF_DIDRUN;
164cc66ebe2SPeter Wemm 		TD_SET_RUNNING(td);
165cc66ebe2SPeter Wemm 		return (td);
166cc66ebe2SPeter Wemm 	}
167cc66ebe2SPeter Wemm #endif
168cc66ebe2SPeter Wemm 
169fe799533SAndrew Gallatin retry:
170cc66ebe2SPeter Wemm 	ke = sched_choose();
171cc66ebe2SPeter Wemm 	if (ke) {
172e602ba25SJulian Elischer 		td = ke->ke_thread;
173e602ba25SJulian Elischer 		KASSERT((td->td_kse == ke), ("kse/thread mismatch"));
174e602ba25SJulian Elischer 		kg = ke->ke_ksegrp;
175ed062c8dSJulian Elischer 		if (td->td_proc->p_flag & P_HADTHREADS) {
17633c06e1dSJulian Elischer 			if (kg->kg_last_assigned == td) {
177e602ba25SJulian Elischer 				kg->kg_last_assigned = TAILQ_PREV(td,
178e602ba25SJulian Elischer 				    threadqueue, td_runq);
17933c06e1dSJulian Elischer 			}
180d03c79eeSDavid Xu 			TAILQ_REMOVE(&kg->kg_runq, td, td_runq);
1811a5cd27bSJulian Elischer 		}
182e602ba25SJulian Elischer 		CTR2(KTR_RUNQ, "choosethread: td=%p pri=%d",
183e602ba25SJulian Elischer 		    td, td->td_priority);
184e602ba25SJulian Elischer 	} else {
18540e55026SJulian Elischer 		/* Simulate runq_choose() having returned the idle thread */
186e602ba25SJulian Elischer 		td = PCPU_GET(idlethread);
187472be958SJulian Elischer 		ke = td->td_kse;
188e602ba25SJulian Elischer 		CTR1(KTR_RUNQ, "choosethread: td=%p (idle)", td);
189e602ba25SJulian Elischer 	}
190472be958SJulian Elischer 	ke->ke_flags |= KEF_DIDRUN;
19193a7aa79SJulian Elischer 
19293a7aa79SJulian Elischer 	/*
193faaa20f6SJulian Elischer 	 * If we are in panic, only allow system threads,
194faaa20f6SJulian Elischer 	 * plus the one we are running in, to be run.
19593a7aa79SJulian Elischer 	 */
196fe799533SAndrew Gallatin 	if (panicstr && ((td->td_proc->p_flag & P_SYSTEM) == 0 &&
197faaa20f6SJulian Elischer 	    (td->td_flags & TDF_INPANIC) == 0)) {
198faaa20f6SJulian Elischer 		/* note that it is no longer on the run queue */
199faaa20f6SJulian Elischer 		TD_SET_CAN_RUN(td);
200fe799533SAndrew Gallatin 		goto retry;
201faaa20f6SJulian Elischer 	}
20293a7aa79SJulian Elischer 
20371fad9fdSJulian Elischer 	TD_SET_RUNNING(td);
204e602ba25SJulian Elischer 	return (td);
205e602ba25SJulian Elischer }
206e602ba25SJulian Elischer 
207e602ba25SJulian Elischer /*
208ed062c8dSJulian Elischer  * Given a surplus system slot, try assign a new runnable thread to it.
209ed062c8dSJulian Elischer  * Called from:
210ed062c8dSJulian Elischer  *  sched_thread_exit()  (local)
211ed062c8dSJulian Elischer  *  sched_switch()  (local)
212ed062c8dSJulian Elischer  *  sched_thread_exit()  (local)
21314f0e2e9SJulian Elischer  *  remrunqueue()  (local)  (not at the moment)
214e602ba25SJulian Elischer  */
215ed062c8dSJulian Elischer static void
216ed062c8dSJulian Elischer slot_fill(struct ksegrp *kg)
217e602ba25SJulian Elischer {
218e602ba25SJulian Elischer 	struct thread *td;
219e602ba25SJulian Elischer 
22033c06e1dSJulian Elischer 	mtx_assert(&sched_lock, MA_OWNED);
221ed062c8dSJulian Elischer 	while (kg->kg_avail_opennings > 0) {
222e602ba25SJulian Elischer 		/*
2236f8132a8SJulian Elischer 		 * Find the first unassigned thread
2246f8132a8SJulian Elischer 		 */
2255215b187SJeff Roberson 		if ((td = kg->kg_last_assigned) != NULL)
2266f8132a8SJulian Elischer 			td = TAILQ_NEXT(td, td_runq);
2275215b187SJeff Roberson 		else
2286f8132a8SJulian Elischer 			td = TAILQ_FIRST(&kg->kg_runq);
2296f8132a8SJulian Elischer 
2306f8132a8SJulian Elischer 		/*
231ed062c8dSJulian Elischer 		 * If we found one, send it to the system scheduler.
232e602ba25SJulian Elischer 		 */
233e602ba25SJulian Elischer 		if (td) {
234e602ba25SJulian Elischer 			kg->kg_last_assigned = td;
23584f9d4b1SStephan Uphoff 			sched_add(td, SRQ_YIELDING);
236ed062c8dSJulian Elischer 			CTR2(KTR_RUNQ, "slot_fill: td%p -> kg%p", td, kg);
237ed062c8dSJulian Elischer 		} else {
238ed062c8dSJulian Elischer 			/* no threads to use up the slots. quit now */
239ed062c8dSJulian Elischer 			break;
24048bfcdddSJulian Elischer 		}
241ed062c8dSJulian Elischer 	}
242d5a08a60SJake Burkholder }
243d5a08a60SJake Burkholder 
244e8807f22SJulian Elischer #ifdef	SCHED_4BSD
245e602ba25SJulian Elischer /*
246e602ba25SJulian Elischer  * Remove a thread from its KSEGRP's run queue.
247e602ba25SJulian Elischer  * This in turn may remove it from a KSE if it was already assigned
248e602ba25SJulian Elischer  * to one, possibly causing a new thread to be assigned to the KSE
2495215b187SJeff Roberson  * and the KSE getting a new priority.
250e602ba25SJulian Elischer  */
2511f955e2dSJulian Elischer static void
252b40ce416SJulian Elischer remrunqueue(struct thread *td)
253d5a08a60SJake Burkholder {
25448bfcdddSJulian Elischer 	struct thread *td2, *td3;
255e602ba25SJulian Elischer 	struct ksegrp *kg;
256e602ba25SJulian Elischer 	struct kse *ke;
257e602ba25SJulian Elischer 
258e602ba25SJulian Elischer 	mtx_assert(&sched_lock, MA_OWNED);
25971fad9fdSJulian Elischer 	KASSERT((TD_ON_RUNQ(td)), ("remrunqueue: Bad state on run queue"));
260e602ba25SJulian Elischer 	kg = td->td_ksegrp;
261e602ba25SJulian Elischer 	ke = td->td_kse;
262e602ba25SJulian Elischer 	CTR1(KTR_RUNQ, "remrunqueue: td%p", td);
26371fad9fdSJulian Elischer 	TD_SET_CAN_RUN(td);
2645215b187SJeff Roberson 	/*
2655215b187SJeff Roberson 	 * If it is not a threaded process, take the shortcut.
2665215b187SJeff Roberson 	 */
267ed062c8dSJulian Elischer 	if ((td->td_proc->p_flag & P_HADTHREADS) == 0) {
2683389af30SJulian Elischer 		/* remve from sys run queue and free up a slot */
2697cf90fb3SJeff Roberson 		sched_rem(td);
270c3b98db0SJulian Elischer 		ke->ke_state = KES_THREAD;
271e602ba25SJulian Elischer 		return;
272d5a08a60SJake Burkholder 	}
27348bfcdddSJulian Elischer    	td3 = TAILQ_PREV(td, threadqueue, td_runq);
27448bfcdddSJulian Elischer 	TAILQ_REMOVE(&kg->kg_runq, td, td_runq);
275ed062c8dSJulian Elischer 	if (ke->ke_state == KES_ONRUNQ) {
276e602ba25SJulian Elischer 		/*
2773389af30SJulian Elischer 		 * This thread has been assigned to the system run queue.
278e602ba25SJulian Elischer 		 * We need to dissociate it and try assign the
279e602ba25SJulian Elischer 		 * KSE to the next available thread. Then, we should
280e602ba25SJulian Elischer 		 * see if we need to move the KSE in the run queues.
281e602ba25SJulian Elischer 		 */
2827cf90fb3SJeff Roberson 		sched_rem(td);
28393a7aa79SJulian Elischer 		ke->ke_state = KES_THREAD;
284e602ba25SJulian Elischer 		td2 = kg->kg_last_assigned;
285e602ba25SJulian Elischer 		KASSERT((td2 != NULL), ("last assigned has wrong value"));
28648bfcdddSJulian Elischer 		if (td2 == td)
287e602ba25SJulian Elischer 			kg->kg_last_assigned = td3;
2883389af30SJulian Elischer 		/* slot_fill(kg); */ /* will replace it with another */
289e602ba25SJulian Elischer 	}
290e602ba25SJulian Elischer }
291e8807f22SJulian Elischer #endif
2921f955e2dSJulian Elischer 
2931f955e2dSJulian Elischer /*
2941f955e2dSJulian Elischer  * Change the priority of a thread that is on the run queue.
2951f955e2dSJulian Elischer  */
2961f955e2dSJulian Elischer void
2971f955e2dSJulian Elischer adjustrunqueue( struct thread *td, int newpri)
2981f955e2dSJulian Elischer {
2991f955e2dSJulian Elischer 	struct ksegrp *kg;
3001f955e2dSJulian Elischer 	struct kse *ke;
3011f955e2dSJulian Elischer 
3021f955e2dSJulian Elischer 	mtx_assert(&sched_lock, MA_OWNED);
3031f955e2dSJulian Elischer 	KASSERT((TD_ON_RUNQ(td)), ("adjustrunqueue: Bad state on run queue"));
3045215b187SJeff Roberson 
3051f955e2dSJulian Elischer 	ke = td->td_kse;
3061f955e2dSJulian Elischer 	CTR1(KTR_RUNQ, "adjustrunqueue: td%p", td);
3075215b187SJeff Roberson 	/*
3085215b187SJeff Roberson 	 * If it is not a threaded process, take the shortcut.
3095215b187SJeff Roberson 	 */
310ed062c8dSJulian Elischer 	if ((td->td_proc->p_flag & P_HADTHREADS) == 0) {
3111f955e2dSJulian Elischer 		/* We only care about the kse in the run queue. */
31224c5baaeSJulian Elischer 		td->td_priority = newpri;
3131f955e2dSJulian Elischer 		if (ke->ke_rqindex != (newpri / RQ_PPQ)) {
3147cf90fb3SJeff Roberson 			sched_rem(td);
3152630e4c9SJulian Elischer 			sched_add(td, SRQ_BORING);
3161f955e2dSJulian Elischer 		}
3171f955e2dSJulian Elischer 		return;
3181f955e2dSJulian Elischer 	}
3195215b187SJeff Roberson 
3205215b187SJeff Roberson 	/* It is a threaded process */
3211f955e2dSJulian Elischer 	kg = td->td_ksegrp;
3223c424d14SDavid Xu 	if (ke->ke_state == KES_ONRUNQ
3233c424d14SDavid Xu #ifdef SCHED_ULE
3243c424d14SDavid Xu 	 || ((ke->ke_flags & KEF_ASSIGNED) != 0 &&
3253c424d14SDavid Xu 	     (ke->ke_flags & KEF_REMOVED) == 0)
3263c424d14SDavid Xu #endif
3273c424d14SDavid Xu 	   ) {
3281f955e2dSJulian Elischer 		if (kg->kg_last_assigned == td) {
3291f955e2dSJulian Elischer 			kg->kg_last_assigned =
3301f955e2dSJulian Elischer 			    TAILQ_PREV(td, threadqueue, td_runq);
3311f955e2dSJulian Elischer 		}
3327cf90fb3SJeff Roberson 		sched_rem(td);
3331f955e2dSJulian Elischer 	}
3341f955e2dSJulian Elischer 	TAILQ_REMOVE(&kg->kg_runq, td, td_runq);
33514f0e2e9SJulian Elischer 	TD_SET_CAN_RUN(td);
3361f955e2dSJulian Elischer 	td->td_priority = newpri;
3372630e4c9SJulian Elischer 	setrunqueue(td, SRQ_BORING);
3381f955e2dSJulian Elischer }
33984f9d4b1SStephan Uphoff 
34084f9d4b1SStephan Uphoff /*
34184f9d4b1SStephan Uphoff  * This function is called when a thread is about to be put on a
34284f9d4b1SStephan Uphoff  * ksegrp run queue because it has been made runnable or its
34384f9d4b1SStephan Uphoff  * priority has been adjusted and the ksegrp does not have a
34484f9d4b1SStephan Uphoff  * free kse slot.  It determines if a thread from the same ksegrp
34584f9d4b1SStephan Uphoff  * should be preempted.  If so, it tries to switch threads
34684f9d4b1SStephan Uphoff  * if the thread is on the same cpu or notifies another cpu that
34784f9d4b1SStephan Uphoff  * it should switch threads.
34884f9d4b1SStephan Uphoff  */
34984f9d4b1SStephan Uphoff 
35084f9d4b1SStephan Uphoff static void
35184f9d4b1SStephan Uphoff maybe_preempt_in_ksegrp(struct thread *td)
3527c71b645SStephan Uphoff #if  !defined(SMP)
35384f9d4b1SStephan Uphoff {
35413e7430fSPoul-Henning Kamp 	struct thread *running_thread;
3557c71b645SStephan Uphoff 
3567c71b645SStephan Uphoff 	mtx_assert(&sched_lock, MA_OWNED);
3577c71b645SStephan Uphoff 	running_thread = curthread;
3587c71b645SStephan Uphoff 
3597c71b645SStephan Uphoff 	if (running_thread->td_ksegrp != td->td_ksegrp)
3607c71b645SStephan Uphoff 		return;
3617c71b645SStephan Uphoff 
362503c2ea3SStephan Uphoff 	if (td->td_priority >= running_thread->td_priority)
3637c71b645SStephan Uphoff 		return;
3647c71b645SStephan Uphoff #ifdef PREEMPTION
365f3a0f873SStephan Uphoff #ifndef FULL_PREEMPTION
366f3a0f873SStephan Uphoff 	if (td->td_priority > PRI_MAX_ITHD) {
367f3a0f873SStephan Uphoff 		running_thread->td_flags |= TDF_NEEDRESCHED;
368f3a0f873SStephan Uphoff 		return;
369f3a0f873SStephan Uphoff 	}
370f3a0f873SStephan Uphoff #endif /* FULL_PREEMPTION */
371f3a0f873SStephan Uphoff 
3727c71b645SStephan Uphoff 	if (running_thread->td_critnest > 1)
37377918643SStephan Uphoff 		running_thread->td_owepreempt = 1;
3747c71b645SStephan Uphoff 	 else
3757c71b645SStephan Uphoff 		 mi_switch(SW_INVOL, NULL);
3767c71b645SStephan Uphoff 
377f3a0f873SStephan Uphoff #else /* PREEMPTION */
3787c71b645SStephan Uphoff 	running_thread->td_flags |= TDF_NEEDRESCHED;
379f3a0f873SStephan Uphoff #endif /* PREEMPTION */
3807c71b645SStephan Uphoff 	return;
3817c71b645SStephan Uphoff }
3827c71b645SStephan Uphoff 
3837c71b645SStephan Uphoff #else /* SMP */
3847c71b645SStephan Uphoff {
3857c71b645SStephan Uphoff 	struct thread *running_thread;
38684f9d4b1SStephan Uphoff 	int worst_pri;
38784f9d4b1SStephan Uphoff 	struct ksegrp *kg;
38884f9d4b1SStephan Uphoff 	cpumask_t cpumask,dontuse;
38984f9d4b1SStephan Uphoff 	struct pcpu *pc;
39084f9d4b1SStephan Uphoff 	struct pcpu *best_pcpu;
39184f9d4b1SStephan Uphoff 	struct thread *cputhread;
39284f9d4b1SStephan Uphoff 
39384f9d4b1SStephan Uphoff 	mtx_assert(&sched_lock, MA_OWNED);
39484f9d4b1SStephan Uphoff 
39584f9d4b1SStephan Uphoff 	running_thread = curthread;
39684f9d4b1SStephan Uphoff 
39784f9d4b1SStephan Uphoff #if !defined(KSEG_PEEMPT_BEST_CPU)
39884f9d4b1SStephan Uphoff 	if (running_thread->td_ksegrp != td->td_ksegrp) {
39984f9d4b1SStephan Uphoff #endif
40084f9d4b1SStephan Uphoff 		kg = td->td_ksegrp;
40184f9d4b1SStephan Uphoff 
40284f9d4b1SStephan Uphoff 		/* if someone is ahead of this thread, wait our turn */
40384f9d4b1SStephan Uphoff 		if (td != TAILQ_FIRST(&kg->kg_runq))
40484f9d4b1SStephan Uphoff 			return;
40584f9d4b1SStephan Uphoff 
40684f9d4b1SStephan Uphoff 		worst_pri = td->td_priority;
40784f9d4b1SStephan Uphoff 		best_pcpu = NULL;
40884f9d4b1SStephan Uphoff 		dontuse   = stopped_cpus | idle_cpus_mask;
40984f9d4b1SStephan Uphoff 
41084f9d4b1SStephan Uphoff 		/*
41184f9d4b1SStephan Uphoff 		 * Find a cpu with the worst priority that runs at thread from
41284f9d4b1SStephan Uphoff 		 * the same  ksegrp - if multiple exist give first the last run
41384f9d4b1SStephan Uphoff 		 * cpu and then the current cpu priority
41484f9d4b1SStephan Uphoff 		 */
41584f9d4b1SStephan Uphoff 
41684f9d4b1SStephan Uphoff 		SLIST_FOREACH(pc, &cpuhead, pc_allcpu) {
41784f9d4b1SStephan Uphoff 			cpumask   = pc->pc_cpumask;
41884f9d4b1SStephan Uphoff 			cputhread = pc->pc_curthread;
41984f9d4b1SStephan Uphoff 
42084f9d4b1SStephan Uphoff 			if ((cpumask & dontuse)  ||
42184f9d4b1SStephan Uphoff 			    cputhread->td_ksegrp != kg)
42284f9d4b1SStephan Uphoff 				continue;
42384f9d4b1SStephan Uphoff 
42484f9d4b1SStephan Uphoff 			if (cputhread->td_priority > worst_pri) {
42584f9d4b1SStephan Uphoff 				worst_pri = cputhread->td_priority;
42684f9d4b1SStephan Uphoff 				best_pcpu = pc;
42784f9d4b1SStephan Uphoff 				continue;
42884f9d4b1SStephan Uphoff 			}
42984f9d4b1SStephan Uphoff 
43084f9d4b1SStephan Uphoff 			if (cputhread->td_priority == worst_pri &&
43184f9d4b1SStephan Uphoff 			    best_pcpu != NULL &&
43284f9d4b1SStephan Uphoff 			    (td->td_lastcpu == pc->pc_cpuid ||
43384f9d4b1SStephan Uphoff 				(PCPU_GET(cpumask) == cpumask &&
43484f9d4b1SStephan Uphoff 				    td->td_lastcpu != best_pcpu->pc_cpuid)))
43584f9d4b1SStephan Uphoff 			    best_pcpu = pc;
43684f9d4b1SStephan Uphoff 		}
43784f9d4b1SStephan Uphoff 
43884f9d4b1SStephan Uphoff 		/* Check if we need to preempt someone */
43984f9d4b1SStephan Uphoff 		if (best_pcpu == NULL)
44084f9d4b1SStephan Uphoff 			return;
44184f9d4b1SStephan Uphoff 
442f3a0f873SStephan Uphoff #if defined(IPI_PREEMPTION) && defined(PREEMPTION)
443f3a0f873SStephan Uphoff #if !defined(FULL_PREEMPTION)
444f3a0f873SStephan Uphoff 		if (td->td_priority <= PRI_MAX_ITHD)
445f3a0f873SStephan Uphoff #endif /* ! FULL_PREEMPTION */
446f3a0f873SStephan Uphoff 			{
447f3a0f873SStephan Uphoff 				ipi_selected(best_pcpu->pc_cpumask, IPI_PREEMPT);
448f3a0f873SStephan Uphoff 				return;
449f3a0f873SStephan Uphoff 			}
450f3a0f873SStephan Uphoff #endif /* defined(IPI_PREEMPTION) && defined(PREEMPTION) */
451f3a0f873SStephan Uphoff 
45284f9d4b1SStephan Uphoff 		if (PCPU_GET(cpuid) != best_pcpu->pc_cpuid) {
45384f9d4b1SStephan Uphoff 			best_pcpu->pc_curthread->td_flags |= TDF_NEEDRESCHED;
45484f9d4b1SStephan Uphoff 			ipi_selected(best_pcpu->pc_cpumask, IPI_AST);
45584f9d4b1SStephan Uphoff 			return;
45684f9d4b1SStephan Uphoff 		}
45784f9d4b1SStephan Uphoff #if !defined(KSEG_PEEMPT_BEST_CPU)
45884f9d4b1SStephan Uphoff 	}
45984f9d4b1SStephan Uphoff #endif
46084f9d4b1SStephan Uphoff 
461503c2ea3SStephan Uphoff 	if (td->td_priority >= running_thread->td_priority)
46284f9d4b1SStephan Uphoff 		return;
46384f9d4b1SStephan Uphoff #ifdef PREEMPTION
464f3a0f873SStephan Uphoff 
465f3a0f873SStephan Uphoff #if !defined(FULL_PREEMPTION)
466f3a0f873SStephan Uphoff 	if (td->td_priority > PRI_MAX_ITHD) {
467f3a0f873SStephan Uphoff 		running_thread->td_flags |= TDF_NEEDRESCHED;
468f3a0f873SStephan Uphoff 	}
469f3a0f873SStephan Uphoff #endif /* ! FULL_PREEMPTION */
470f3a0f873SStephan Uphoff 
47184f9d4b1SStephan Uphoff 	if (running_thread->td_critnest > 1)
47277918643SStephan Uphoff 		running_thread->td_owepreempt = 1;
47384f9d4b1SStephan Uphoff 	 else
47484f9d4b1SStephan Uphoff 		 mi_switch(SW_INVOL, NULL);
47584f9d4b1SStephan Uphoff 
476f3a0f873SStephan Uphoff #else /* PREEMPTION */
47784f9d4b1SStephan Uphoff 	running_thread->td_flags |= TDF_NEEDRESCHED;
478f3a0f873SStephan Uphoff #endif /* PREEMPTION */
47984f9d4b1SStephan Uphoff 	return;
48084f9d4b1SStephan Uphoff }
4817c71b645SStephan Uphoff #endif /* !SMP */
4827c71b645SStephan Uphoff 
48384f9d4b1SStephan Uphoff 
484ed062c8dSJulian Elischer int limitcount;
485d5a08a60SJake Burkholder void
4862630e4c9SJulian Elischer setrunqueue(struct thread *td, int flags)
487d5a08a60SJake Burkholder {
488e602ba25SJulian Elischer 	struct ksegrp *kg;
489e602ba25SJulian Elischer 	struct thread *td2;
490e602ba25SJulian Elischer 	struct thread *tda;
491e602ba25SJulian Elischer 
492ed062c8dSJulian Elischer 	CTR3(KTR_RUNQ, "setrunqueue: td:%p kg:%p pid:%d",
493ed062c8dSJulian Elischer 	    td, td->td_ksegrp, td->td_proc->p_pid);
49485da7a56SJeff Roberson 	CTR5(KTR_SCHED, "setrunqueue: %p(%s) prio %d by %p(%s)",
49585da7a56SJeff Roberson             td, td->td_proc->p_comm, td->td_priority, curthread,
49685da7a56SJeff Roberson             curthread->td_proc->p_comm);
497e602ba25SJulian Elischer 	mtx_assert(&sched_lock, MA_OWNED);
498b2578c6cSJulian Elischer 	KASSERT((td->td_inhibitors == 0),
499b2578c6cSJulian Elischer 			("setrunqueue: trying to run inhibitted thread"));
50071fad9fdSJulian Elischer 	KASSERT((TD_CAN_RUN(td) || TD_IS_RUNNING(td)),
50171fad9fdSJulian Elischer 	    ("setrunqueue: bad thread state"));
50271fad9fdSJulian Elischer 	TD_SET_RUNQ(td);
503e602ba25SJulian Elischer 	kg = td->td_ksegrp;
504ed062c8dSJulian Elischer 	if ((td->td_proc->p_flag & P_HADTHREADS) == 0) {
50548bfcdddSJulian Elischer 		/*
50648bfcdddSJulian Elischer 		 * Common path optimisation: Only one of everything
50748bfcdddSJulian Elischer 		 * and the KSE is always already attached.
50848bfcdddSJulian Elischer 		 * Totally ignore the ksegrp run queue.
50948bfcdddSJulian Elischer 		 */
510ed062c8dSJulian Elischer 		if (kg->kg_avail_opennings != 1) {
51154983505SJulian Elischer 			if (limitcount < 1) {
512ed062c8dSJulian Elischer 				limitcount++;
51354983505SJulian Elischer 				printf("pid %d: corrected slot count (%d->1)\n",
514ed062c8dSJulian Elischer 				    td->td_proc->p_pid, kg->kg_avail_opennings);
515ed062c8dSJulian Elischer 
516ed062c8dSJulian Elischer 			}
517ed062c8dSJulian Elischer 			kg->kg_avail_opennings = 1;
518ed062c8dSJulian Elischer 		}
5192630e4c9SJulian Elischer 		sched_add(td, flags);
52048bfcdddSJulian Elischer 		return;
52148bfcdddSJulian Elischer 	}
52248bfcdddSJulian Elischer 
52314f0e2e9SJulian Elischer 	/*
52414f0e2e9SJulian Elischer 	 * If the concurrency has reduced, and we would go in the
52514f0e2e9SJulian Elischer 	 * assigned section, then keep removing entries from the
52614f0e2e9SJulian Elischer 	 * system run queue, until we are not in that section
52714f0e2e9SJulian Elischer 	 * or there is room for us to be put in that section.
52814f0e2e9SJulian Elischer 	 * What we MUST avoid is the case where there are threads of less
52914f0e2e9SJulian Elischer 	 * priority than the new one scheduled, but it can not
53014f0e2e9SJulian Elischer 	 * be scheduled itself. That would lead to a non contiguous set
53114f0e2e9SJulian Elischer 	 * of scheduled threads, and everything would break.
53214f0e2e9SJulian Elischer 	 */
533e602ba25SJulian Elischer 	tda = kg->kg_last_assigned;
53414f0e2e9SJulian Elischer 	while ((kg->kg_avail_opennings <= 0) &&
535ed062c8dSJulian Elischer 	    (tda && (tda->td_priority > td->td_priority))) {
536e602ba25SJulian Elischer 		/*
537e602ba25SJulian Elischer 		 * None free, but there is one we can commandeer.
538e602ba25SJulian Elischer 		 */
539ed062c8dSJulian Elischer 		CTR2(KTR_RUNQ,
540ed062c8dSJulian Elischer 		    "setrunqueue: kg:%p: take slot from td: %p", kg, tda);
54194816f6dSJeff Roberson 		sched_rem(tda);
542e602ba25SJulian Elischer 		tda = kg->kg_last_assigned =
543e602ba25SJulian Elischer 		    TAILQ_PREV(tda, threadqueue, td_runq);
544d5a08a60SJake Burkholder 	}
545d5a08a60SJake Burkholder 
546e602ba25SJulian Elischer 	/*
547e602ba25SJulian Elischer 	 * Add the thread to the ksegrp's run queue at
548e602ba25SJulian Elischer 	 * the appropriate place.
549e602ba25SJulian Elischer 	 */
550e602ba25SJulian Elischer 	TAILQ_FOREACH(td2, &kg->kg_runq, td_runq) {
551e602ba25SJulian Elischer 		if (td2->td_priority > td->td_priority) {
552e602ba25SJulian Elischer 			TAILQ_INSERT_BEFORE(td2, td, td_runq);
553e602ba25SJulian Elischer 			break;
554e602ba25SJulian Elischer 		}
555e602ba25SJulian Elischer 	}
556e602ba25SJulian Elischer 	if (td2 == NULL) {
557e602ba25SJulian Elischer 		/* We ran off the end of the TAILQ or it was empty. */
558e602ba25SJulian Elischer 		TAILQ_INSERT_TAIL(&kg->kg_runq, td, td_runq);
559e602ba25SJulian Elischer 	}
560e602ba25SJulian Elischer 
561e602ba25SJulian Elischer 	/*
562ed062c8dSJulian Elischer 	 * If we have a slot to use, then put the thread on the system
563ed062c8dSJulian Elischer 	 * run queue and if needed, readjust the last_assigned pointer.
56414f0e2e9SJulian Elischer 	 * it may be that we need to schedule something anyhow
56514f0e2e9SJulian Elischer 	 * even if the availabel slots are -ve so that
56614f0e2e9SJulian Elischer 	 * all the items < last_assigned are scheduled.
567e602ba25SJulian Elischer 	 */
568ed062c8dSJulian Elischer 	if (kg->kg_avail_opennings > 0) {
569e602ba25SJulian Elischer 		if (tda == NULL) {
570e602ba25SJulian Elischer 			/*
571e602ba25SJulian Elischer 			 * No pre-existing last assigned so whoever is first
57214f0e2e9SJulian Elischer 			 * gets the slot.. (maybe us)
573e602ba25SJulian Elischer 			 */
574e602ba25SJulian Elischer 			td2 = TAILQ_FIRST(&kg->kg_runq);
575e602ba25SJulian Elischer 			kg->kg_last_assigned = td2;
576e602ba25SJulian Elischer 		} else if (tda->td_priority > td->td_priority) {
577ed062c8dSJulian Elischer 			td2 = td;
578e602ba25SJulian Elischer 		} else {
579e602ba25SJulian Elischer 			/*
580e602ba25SJulian Elischer 			 * We are past last_assigned, so
58114f0e2e9SJulian Elischer 			 * give the next slot to whatever is next,
582e602ba25SJulian Elischer 			 * which may or may not be us.
583e602ba25SJulian Elischer 			 */
584e602ba25SJulian Elischer 			td2 = TAILQ_NEXT(tda, td_runq);
585e602ba25SJulian Elischer 			kg->kg_last_assigned = td2;
586e602ba25SJulian Elischer 		}
587ed062c8dSJulian Elischer 		sched_add(td2, flags);
588732d9528SJulian Elischer 	} else {
589732d9528SJulian Elischer 		CTR3(KTR_RUNQ, "setrunqueue: held: td%p kg%p pid%d",
590732d9528SJulian Elischer 			td, td->td_ksegrp, td->td_proc->p_pid);
59184f9d4b1SStephan Uphoff 		if ((flags & SRQ_YIELDING) == 0)
59284f9d4b1SStephan Uphoff 			maybe_preempt_in_ksegrp(td);
593e602ba25SJulian Elischer 	}
594e602ba25SJulian Elischer }
595e602ba25SJulian Elischer 
5960c0b25aeSJohn Baldwin /*
5970c0b25aeSJohn Baldwin  * Kernel thread preemption implementation.  Critical sections mark
5980c0b25aeSJohn Baldwin  * regions of code in which preemptions are not allowed.
5990c0b25aeSJohn Baldwin  */
6007e1f6dfeSJohn Baldwin void
6017e1f6dfeSJohn Baldwin critical_enter(void)
6027e1f6dfeSJohn Baldwin {
6037e1f6dfeSJohn Baldwin 	struct thread *td;
6047e1f6dfeSJohn Baldwin 
6057e1f6dfeSJohn Baldwin 	td = curthread;
6067e1f6dfeSJohn Baldwin 	td->td_critnest++;
6071335c4dfSNate Lawson 	CTR4(KTR_CRITICAL, "critical_enter by thread %p (%ld, %s) to %d", td,
608f42a43faSRobert Watson 	    (long)td->td_proc->p_pid, td->td_proc->p_comm, td->td_critnest);
6097e1f6dfeSJohn Baldwin }
6107e1f6dfeSJohn Baldwin 
6117e1f6dfeSJohn Baldwin void
6127e1f6dfeSJohn Baldwin critical_exit(void)
6137e1f6dfeSJohn Baldwin {
6147e1f6dfeSJohn Baldwin 	struct thread *td;
6157e1f6dfeSJohn Baldwin 
6167e1f6dfeSJohn Baldwin 	td = curthread;
617b209e5e3SJeff Roberson 	KASSERT(td->td_critnest != 0,
618b209e5e3SJeff Roberson 	    ("critical_exit: td_critnest == 0"));
6190c0b25aeSJohn Baldwin #ifdef PREEMPTION
620d13ec713SStephan Uphoff 	if (td->td_critnest == 1) {
621d13ec713SStephan Uphoff 		td->td_critnest = 0;
62252eb8464SJohn Baldwin 		mtx_assert(&sched_lock, MA_NOTOWNED);
62377918643SStephan Uphoff 		if (td->td_owepreempt) {
62477918643SStephan Uphoff 			td->td_critnest = 1;
6250c0b25aeSJohn Baldwin 			mtx_lock_spin(&sched_lock);
62677918643SStephan Uphoff 			td->td_critnest--;
6270c0b25aeSJohn Baldwin 			mi_switch(SW_INVOL, NULL);
6280c0b25aeSJohn Baldwin 			mtx_unlock_spin(&sched_lock);
6290c0b25aeSJohn Baldwin 		}
630d13ec713SStephan Uphoff 	} else
6310c0b25aeSJohn Baldwin #endif
6327e1f6dfeSJohn Baldwin 		td->td_critnest--;
633d13ec713SStephan Uphoff 
634d13ec713SStephan Uphoff 
6351335c4dfSNate Lawson 	CTR4(KTR_CRITICAL, "critical_exit by thread %p (%ld, %s) to %d", td,
636f42a43faSRobert Watson 	    (long)td->td_proc->p_pid, td->td_proc->p_comm, td->td_critnest);
637d74ac681SMatthew Dillon }
6387e1f6dfeSJohn Baldwin 
6390c0b25aeSJohn Baldwin /*
6400c0b25aeSJohn Baldwin  * This function is called when a thread is about to be put on run queue
6410c0b25aeSJohn Baldwin  * because it has been made runnable or its priority has been adjusted.  It
6420c0b25aeSJohn Baldwin  * determines if the new thread should be immediately preempted to.  If so,
6430c0b25aeSJohn Baldwin  * it switches to it and eventually returns true.  If not, it returns false
6440c0b25aeSJohn Baldwin  * so that the caller may place the thread on an appropriate run queue.
6450c0b25aeSJohn Baldwin  */
6460c0b25aeSJohn Baldwin int
6470c0b25aeSJohn Baldwin maybe_preempt(struct thread *td)
6480c0b25aeSJohn Baldwin {
6498b44a2e2SMarcel Moolenaar #ifdef PREEMPTION
6500c0b25aeSJohn Baldwin 	struct thread *ctd;
6510c0b25aeSJohn Baldwin 	int cpri, pri;
6528b44a2e2SMarcel Moolenaar #endif
6530c0b25aeSJohn Baldwin 
6540c0b25aeSJohn Baldwin 	mtx_assert(&sched_lock, MA_OWNED);
6550c0b25aeSJohn Baldwin #ifdef PREEMPTION
6560c0b25aeSJohn Baldwin 	/*
6570c0b25aeSJohn Baldwin 	 * The new thread should not preempt the current thread if any of the
6580c0b25aeSJohn Baldwin 	 * following conditions are true:
6590c0b25aeSJohn Baldwin 	 *
660bc608306SRobert Watson 	 *  - The kernel is in the throes of crashing (panicstr).
66152eb8464SJohn Baldwin 	 *  - The current thread has a higher (numerically lower) or
66252eb8464SJohn Baldwin 	 *    equivalent priority.  Note that this prevents curthread from
66352eb8464SJohn Baldwin 	 *    trying to preempt to itself.
6640c0b25aeSJohn Baldwin 	 *  - It is too early in the boot for context switches (cold is set).
6650c0b25aeSJohn Baldwin 	 *  - The current thread has an inhibitor set or is in the process of
6660c0b25aeSJohn Baldwin 	 *    exiting.  In this case, the current thread is about to switch
6670c0b25aeSJohn Baldwin 	 *    out anyways, so there's no point in preempting.  If we did,
6680c0b25aeSJohn Baldwin 	 *    the current thread would not be properly resumed as well, so
6690c0b25aeSJohn Baldwin 	 *    just avoid that whole landmine.
6700c0b25aeSJohn Baldwin 	 *  - If the new thread's priority is not a realtime priority and
6710c0b25aeSJohn Baldwin 	 *    the current thread's priority is not an idle priority and
6720c0b25aeSJohn Baldwin 	 *    FULL_PREEMPTION is disabled.
6730c0b25aeSJohn Baldwin 	 *
6740c0b25aeSJohn Baldwin 	 * If all of these conditions are false, but the current thread is in
6750c0b25aeSJohn Baldwin 	 * a nested critical section, then we have to defer the preemption
6760c0b25aeSJohn Baldwin 	 * until we exit the critical section.  Otherwise, switch immediately
6770c0b25aeSJohn Baldwin 	 * to the new thread.
6780c0b25aeSJohn Baldwin 	 */
6790c0b25aeSJohn Baldwin 	ctd = curthread;
6806a574b2aSJulian Elischer 	KASSERT ((ctd->td_kse != NULL && ctd->td_kse->ke_thread == ctd),
6816a574b2aSJulian Elischer 	  ("thread has no (or wrong) sched-private part."));
682b2578c6cSJulian Elischer 	KASSERT((td->td_inhibitors == 0),
683b2578c6cSJulian Elischer 			("maybe_preempt: trying to run inhibitted thread"));
6840c0b25aeSJohn Baldwin 	pri = td->td_priority;
6850c0b25aeSJohn Baldwin 	cpri = ctd->td_priority;
686bc608306SRobert Watson 	if (panicstr != NULL || pri >= cpri || cold /* || dumping */ ||
687bc608306SRobert Watson 	    TD_IS_INHIBITED(ctd) || td->td_kse->ke_state != KES_THREAD)
6880c0b25aeSJohn Baldwin 		return (0);
6890c0b25aeSJohn Baldwin #ifndef FULL_PREEMPTION
6903ea6bbc5SStephan Uphoff 	if (pri > PRI_MAX_ITHD && cpri < PRI_MIN_IDLE)
6910c0b25aeSJohn Baldwin 		return (0);
6920c0b25aeSJohn Baldwin #endif
693a3f2d842SStephan Uphoff 
6940c0b25aeSJohn Baldwin 	if (ctd->td_critnest > 1) {
6950c0b25aeSJohn Baldwin 		CTR1(KTR_PROC, "maybe_preempt: in critical section %d",
6960c0b25aeSJohn Baldwin 		    ctd->td_critnest);
69777918643SStephan Uphoff 		ctd->td_owepreempt = 1;
6980c0b25aeSJohn Baldwin 		return (0);
6990c0b25aeSJohn Baldwin 	}
7000c0b25aeSJohn Baldwin 
7010c0b25aeSJohn Baldwin 	/*
702c20c691bSJulian Elischer 	 * Thread is runnable but not yet put on system run queue.
7030c0b25aeSJohn Baldwin 	 */
7040c0b25aeSJohn Baldwin 	MPASS(TD_ON_RUNQ(td));
7051f9f5df6SJulian Elischer 	MPASS(td->td_sched->ke_state != KES_ONRUNQ);
7061f9f5df6SJulian Elischer 	if (td->td_proc->p_flag & P_HADTHREADS) {
7071f9f5df6SJulian Elischer 		/*
7081f9f5df6SJulian Elischer 		 * If this is a threaded process we actually ARE on the
7091f9f5df6SJulian Elischer 		 * ksegrp run queue so take it off that first.
7109da3e923SJulian Elischer 		 * Also undo any damage done to the last_assigned pointer.
7119da3e923SJulian Elischer 		 * XXX Fix setrunqueue so this isn't needed
7121f9f5df6SJulian Elischer 		 */
7139da3e923SJulian Elischer 		struct ksegrp *kg;
7149da3e923SJulian Elischer 
7159da3e923SJulian Elischer 		kg = td->td_ksegrp;
7169da3e923SJulian Elischer 		if (kg->kg_last_assigned == td)
7179da3e923SJulian Elischer 			kg->kg_last_assigned =
7189da3e923SJulian Elischer 			    TAILQ_PREV(td, threadqueue, td_runq);
7199da3e923SJulian Elischer 		TAILQ_REMOVE(&kg->kg_runq, td, td_runq);
7201f9f5df6SJulian Elischer 	}
7211f9f5df6SJulian Elischer 
7220c0b25aeSJohn Baldwin 	TD_SET_RUNNING(td);
7230c0b25aeSJohn Baldwin 	CTR3(KTR_PROC, "preempting to thread %p (pid %d, %s)\n", td,
7240c0b25aeSJohn Baldwin 	    td->td_proc->p_pid, td->td_proc->p_comm);
725c20c691bSJulian Elischer 	mi_switch(SW_INVOL|SW_PREEMPT, td);
7260c0b25aeSJohn Baldwin 	return (1);
7270c0b25aeSJohn Baldwin #else
7280c0b25aeSJohn Baldwin 	return (0);
7290c0b25aeSJohn Baldwin #endif
7300c0b25aeSJohn Baldwin }
7310c0b25aeSJohn Baldwin 
73244fe3c1fSJohn Baldwin #if 0
7330c0b25aeSJohn Baldwin #ifndef PREEMPTION
7340c0b25aeSJohn Baldwin /* XXX: There should be a non-static version of this. */
7350c0b25aeSJohn Baldwin static void
7360c0b25aeSJohn Baldwin printf_caddr_t(void *data)
7370c0b25aeSJohn Baldwin {
7380c0b25aeSJohn Baldwin 	printf("%s", (char *)data);
7390c0b25aeSJohn Baldwin }
7400c0b25aeSJohn Baldwin static char preempt_warning[] =
7410c0b25aeSJohn Baldwin     "WARNING: Kernel preemption is disabled, expect reduced performance.\n";
7420c0b25aeSJohn Baldwin SYSINIT(preempt_warning, SI_SUB_COPYRIGHT, SI_ORDER_ANY, printf_caddr_t,
7430c0b25aeSJohn Baldwin     preempt_warning)
7440c0b25aeSJohn Baldwin #endif
74544fe3c1fSJohn Baldwin #endif
746e602ba25SJulian Elischer 
747e602ba25SJulian Elischer /************************************************************************
748e602ba25SJulian Elischer  * SYSTEM RUN QUEUE manipulations and tests				*
749e602ba25SJulian Elischer  ************************************************************************/
750e602ba25SJulian Elischer /*
751e602ba25SJulian Elischer  * Initialize a run structure.
752e602ba25SJulian Elischer  */
753e602ba25SJulian Elischer void
754e602ba25SJulian Elischer runq_init(struct runq *rq)
755e602ba25SJulian Elischer {
756e602ba25SJulian Elischer 	int i;
757e602ba25SJulian Elischer 
758e602ba25SJulian Elischer 	bzero(rq, sizeof *rq);
759e602ba25SJulian Elischer 	for (i = 0; i < RQ_NQS; i++)
760e602ba25SJulian Elischer 		TAILQ_INIT(&rq->rq_queues[i]);
761e602ba25SJulian Elischer }
762e602ba25SJulian Elischer 
763d5a08a60SJake Burkholder /*
764d5a08a60SJake Burkholder  * Clear the status bit of the queue corresponding to priority level pri,
765d5a08a60SJake Burkholder  * indicating that it is empty.
766d5a08a60SJake Burkholder  */
767d5a08a60SJake Burkholder static __inline void
768d5a08a60SJake Burkholder runq_clrbit(struct runq *rq, int pri)
769d5a08a60SJake Burkholder {
770d5a08a60SJake Burkholder 	struct rqbits *rqb;
771d5a08a60SJake Burkholder 
772d5a08a60SJake Burkholder 	rqb = &rq->rq_status;
773d5a08a60SJake Burkholder 	CTR4(KTR_RUNQ, "runq_clrbit: bits=%#x %#x bit=%#x word=%d",
774d5a08a60SJake Burkholder 	    rqb->rqb_bits[RQB_WORD(pri)],
775d5a08a60SJake Burkholder 	    rqb->rqb_bits[RQB_WORD(pri)] & ~RQB_BIT(pri),
776d5a08a60SJake Burkholder 	    RQB_BIT(pri), RQB_WORD(pri));
777d5a08a60SJake Burkholder 	rqb->rqb_bits[RQB_WORD(pri)] &= ~RQB_BIT(pri);
778d5a08a60SJake Burkholder }
779d5a08a60SJake Burkholder 
780d5a08a60SJake Burkholder /*
781d5a08a60SJake Burkholder  * Find the index of the first non-empty run queue.  This is done by
782d5a08a60SJake Burkholder  * scanning the status bits, a set bit indicates a non-empty queue.
783d5a08a60SJake Burkholder  */
784d5a08a60SJake Burkholder static __inline int
785d5a08a60SJake Burkholder runq_findbit(struct runq *rq)
786d5a08a60SJake Burkholder {
787d5a08a60SJake Burkholder 	struct rqbits *rqb;
788d5a08a60SJake Burkholder 	int pri;
789d5a08a60SJake Burkholder 	int i;
790d5a08a60SJake Burkholder 
791d5a08a60SJake Burkholder 	rqb = &rq->rq_status;
792d5a08a60SJake Burkholder 	for (i = 0; i < RQB_LEN; i++)
793d5a08a60SJake Burkholder 		if (rqb->rqb_bits[i]) {
7942f9267ecSPeter Wemm 			pri = RQB_FFS(rqb->rqb_bits[i]) + (i << RQB_L2BPW);
795d5a08a60SJake Burkholder 			CTR3(KTR_RUNQ, "runq_findbit: bits=%#x i=%d pri=%d",
796d5a08a60SJake Burkholder 			    rqb->rqb_bits[i], i, pri);
797d5a08a60SJake Burkholder 			return (pri);
798d5a08a60SJake Burkholder 		}
799d5a08a60SJake Burkholder 
800d5a08a60SJake Burkholder 	return (-1);
801d5a08a60SJake Burkholder }
802d5a08a60SJake Burkholder 
803d5a08a60SJake Burkholder /*
804d5a08a60SJake Burkholder  * Set the status bit of the queue corresponding to priority level pri,
805d5a08a60SJake Burkholder  * indicating that it is non-empty.
806d5a08a60SJake Burkholder  */
807d5a08a60SJake Burkholder static __inline void
808d5a08a60SJake Burkholder runq_setbit(struct runq *rq, int pri)
809d5a08a60SJake Burkholder {
810d5a08a60SJake Burkholder 	struct rqbits *rqb;
811d5a08a60SJake Burkholder 
812d5a08a60SJake Burkholder 	rqb = &rq->rq_status;
813d5a08a60SJake Burkholder 	CTR4(KTR_RUNQ, "runq_setbit: bits=%#x %#x bit=%#x word=%d",
814d5a08a60SJake Burkholder 	    rqb->rqb_bits[RQB_WORD(pri)],
815d5a08a60SJake Burkholder 	    rqb->rqb_bits[RQB_WORD(pri)] | RQB_BIT(pri),
816d5a08a60SJake Burkholder 	    RQB_BIT(pri), RQB_WORD(pri));
817d5a08a60SJake Burkholder 	rqb->rqb_bits[RQB_WORD(pri)] |= RQB_BIT(pri);
818d5a08a60SJake Burkholder }
819d5a08a60SJake Burkholder 
820d5a08a60SJake Burkholder /*
821e602ba25SJulian Elischer  * Add the KSE to the queue specified by its priority, and set the
822d5a08a60SJake Burkholder  * corresponding status bit.
823d5a08a60SJake Burkholder  */
824d5a08a60SJake Burkholder void
825c20c691bSJulian Elischer runq_add(struct runq *rq, struct kse *ke, int flags)
826d5a08a60SJake Burkholder {
827d5a08a60SJake Burkholder 	struct rqhead *rqh;
828d5a08a60SJake Burkholder 	int pri;
829dba6c5a6SPeter Wemm 
8302c100766SJulian Elischer 	pri = ke->ke_thread->td_priority / RQ_PPQ;
831b40ce416SJulian Elischer 	ke->ke_rqindex = pri;
832d5a08a60SJake Burkholder 	runq_setbit(rq, pri);
833d5a08a60SJake Burkholder 	rqh = &rq->rq_queues[pri];
834732d9528SJulian Elischer 	CTR5(KTR_RUNQ, "runq_add: td=%p ke=%p pri=%d %d rqh=%p",
835732d9528SJulian Elischer 	    ke->ke_thread, ke, ke->ke_thread->td_priority, pri, rqh);
836c20c691bSJulian Elischer 	if (flags & SRQ_PREEMPTED) {
837c20c691bSJulian Elischer 		TAILQ_INSERT_HEAD(rqh, ke, ke_procq);
838c20c691bSJulian Elischer 	} else {
839b40ce416SJulian Elischer 		TAILQ_INSERT_TAIL(rqh, ke, ke_procq);
840dba6c5a6SPeter Wemm 	}
841c20c691bSJulian Elischer }
842d5a08a60SJake Burkholder 
843d5a08a60SJake Burkholder /*
844d5a08a60SJake Burkholder  * Return true if there are runnable processes of any priority on the run
845d5a08a60SJake Burkholder  * queue, false otherwise.  Has no side effects, does not modify the run
846d5a08a60SJake Burkholder  * queue structure.
847d5a08a60SJake Burkholder  */
848d5a08a60SJake Burkholder int
849d5a08a60SJake Burkholder runq_check(struct runq *rq)
850d5a08a60SJake Burkholder {
851d5a08a60SJake Burkholder 	struct rqbits *rqb;
852d5a08a60SJake Burkholder 	int i;
853d5a08a60SJake Burkholder 
854d5a08a60SJake Burkholder 	rqb = &rq->rq_status;
855d5a08a60SJake Burkholder 	for (i = 0; i < RQB_LEN; i++)
856d5a08a60SJake Burkholder 		if (rqb->rqb_bits[i]) {
857d5a08a60SJake Burkholder 			CTR2(KTR_RUNQ, "runq_check: bits=%#x i=%d",
858d5a08a60SJake Burkholder 			    rqb->rqb_bits[i], i);
859d5a08a60SJake Burkholder 			return (1);
860dba6c5a6SPeter Wemm 		}
861d5a08a60SJake Burkholder 	CTR0(KTR_RUNQ, "runq_check: empty");
862d5a08a60SJake Burkholder 
863d5a08a60SJake Burkholder 	return (0);
864dba6c5a6SPeter Wemm }
865d5a08a60SJake Burkholder 
8666804a3abSJulian Elischer #if defined(SMP) && defined(SCHED_4BSD)
8676804a3abSJulian Elischer int runq_fuzz = 1;
8686804a3abSJulian Elischer SYSCTL_INT(_kern_sched, OID_AUTO, runq_fuzz, CTLFLAG_RW, &runq_fuzz, 0, "");
8696804a3abSJulian Elischer #endif
8706804a3abSJulian Elischer 
871d5a08a60SJake Burkholder /*
872b43179fbSJeff Roberson  * Find the highest priority process on the run queue.
873d5a08a60SJake Burkholder  */
874b40ce416SJulian Elischer struct kse *
875d5a08a60SJake Burkholder runq_choose(struct runq *rq)
876d5a08a60SJake Burkholder {
877d5a08a60SJake Burkholder 	struct rqhead *rqh;
878b40ce416SJulian Elischer 	struct kse *ke;
879d5a08a60SJake Burkholder 	int pri;
880d5a08a60SJake Burkholder 
881d5a08a60SJake Burkholder 	mtx_assert(&sched_lock, MA_OWNED);
882e602ba25SJulian Elischer 	while ((pri = runq_findbit(rq)) != -1) {
883d5a08a60SJake Burkholder 		rqh = &rq->rq_queues[pri];
8846804a3abSJulian Elischer #if defined(SMP) && defined(SCHED_4BSD)
8856804a3abSJulian Elischer 		/* fuzz == 1 is normal.. 0 or less are ignored */
8866804a3abSJulian Elischer 		if (runq_fuzz > 1) {
8876804a3abSJulian Elischer 			/*
8886804a3abSJulian Elischer 			 * In the first couple of entries, check if
8896804a3abSJulian Elischer 			 * there is one for our CPU as a preference.
8906804a3abSJulian Elischer 			 */
8916804a3abSJulian Elischer 			int count = runq_fuzz;
8926804a3abSJulian Elischer 			int cpu = PCPU_GET(cpuid);
8936804a3abSJulian Elischer 			struct kse *ke2;
8946804a3abSJulian Elischer 			ke2 = ke = TAILQ_FIRST(rqh);
8956804a3abSJulian Elischer 
8966804a3abSJulian Elischer 			while (count-- && ke2) {
8976804a3abSJulian Elischer 				if (ke->ke_thread->td_lastcpu == cpu) {
8986804a3abSJulian Elischer 					ke = ke2;
8996804a3abSJulian Elischer 					break;
9006804a3abSJulian Elischer 				}
9016804a3abSJulian Elischer 				ke2 = TAILQ_NEXT(ke2, ke_procq);
9026804a3abSJulian Elischer 			}
9036804a3abSJulian Elischer 		} else
9046804a3abSJulian Elischer #endif
905b40ce416SJulian Elischer 			ke = TAILQ_FIRST(rqh);
906b40ce416SJulian Elischer 		KASSERT(ke != NULL, ("runq_choose: no proc on busy queue"));
907e602ba25SJulian Elischer 		CTR3(KTR_RUNQ,
908e602ba25SJulian Elischer 		    "runq_choose: pri=%d kse=%p rqh=%p", pri, ke, rqh);
909b40ce416SJulian Elischer 		return (ke);
910d5a08a60SJake Burkholder 	}
911d5a08a60SJake Burkholder 	CTR1(KTR_RUNQ, "runq_choose: idleproc pri=%d", pri);
912d5a08a60SJake Burkholder 
913e602ba25SJulian Elischer 	return (NULL);
914d5a08a60SJake Burkholder }
915d5a08a60SJake Burkholder 
916d5a08a60SJake Burkholder /*
917e602ba25SJulian Elischer  * Remove the KSE from the queue specified by its priority, and clear the
918d5a08a60SJake Burkholder  * corresponding status bit if the queue becomes empty.
919e602ba25SJulian Elischer  * Caller must set ke->ke_state afterwards.
920d5a08a60SJake Burkholder  */
921d5a08a60SJake Burkholder void
922b40ce416SJulian Elischer runq_remove(struct runq *rq, struct kse *ke)
923d5a08a60SJake Burkholder {
924d5a08a60SJake Burkholder 	struct rqhead *rqh;
925d5a08a60SJake Burkholder 	int pri;
926d5a08a60SJake Burkholder 
9279eb881f8SSeigo Tanimura 	KASSERT(ke->ke_proc->p_sflag & PS_INMEM,
9289eb881f8SSeigo Tanimura 		("runq_remove: process swapped out"));
929b40ce416SJulian Elischer 	pri = ke->ke_rqindex;
930d5a08a60SJake Burkholder 	rqh = &rq->rq_queues[pri];
931732d9528SJulian Elischer 	CTR5(KTR_RUNQ, "runq_remove: td=%p, ke=%p pri=%d %d rqh=%p",
932732d9528SJulian Elischer 	    ke->ke_thread, ke, ke->ke_thread->td_priority, pri, rqh);
933b40ce416SJulian Elischer 	KASSERT(ke != NULL, ("runq_remove: no proc on busy queue"));
934b40ce416SJulian Elischer 	TAILQ_REMOVE(rqh, ke, ke_procq);
935d5a08a60SJake Burkholder 	if (TAILQ_EMPTY(rqh)) {
936d5a08a60SJake Burkholder 		CTR0(KTR_RUNQ, "runq_remove: empty");
937d5a08a60SJake Burkholder 		runq_clrbit(rq, pri);
938d5a08a60SJake Burkholder 	}
939dba6c5a6SPeter Wemm }
940e602ba25SJulian Elischer 
941ed062c8dSJulian Elischer /****** functions that are temporarily here ***********/
942ed062c8dSJulian Elischer #include <vm/uma.h>
943ed062c8dSJulian Elischer extern struct mtx kse_zombie_lock;
944ed062c8dSJulian Elischer 
945ed062c8dSJulian Elischer /*
946ed062c8dSJulian Elischer  *  Allocate scheduler specific per-process resources.
947ed062c8dSJulian Elischer  * The thread and ksegrp have already been linked in.
948ed062c8dSJulian Elischer  * In this case just set the default concurrency value.
949ed062c8dSJulian Elischer  *
950ed062c8dSJulian Elischer  * Called from:
951ed062c8dSJulian Elischer  *  proc_init() (UMA init method)
952ed062c8dSJulian Elischer  */
953ed062c8dSJulian Elischer void
954ed062c8dSJulian Elischer sched_newproc(struct proc *p, struct ksegrp *kg, struct thread *td)
955ed062c8dSJulian Elischer {
956ed062c8dSJulian Elischer 
957ed062c8dSJulian Elischer 	/* This can go in sched_fork */
958ed062c8dSJulian Elischer 	sched_init_concurrency(kg);
959ed062c8dSJulian Elischer }
960ed062c8dSJulian Elischer 
961ed062c8dSJulian Elischer /*
962ed062c8dSJulian Elischer  * thread is being either created or recycled.
963ed062c8dSJulian Elischer  * Fix up the per-scheduler resources associated with it.
964ed062c8dSJulian Elischer  * Called from:
965ed062c8dSJulian Elischer  *  sched_fork_thread()
966ed062c8dSJulian Elischer  *  thread_dtor()  (*may go away)
967ed062c8dSJulian Elischer  *  thread_init()  (*may go away)
968ed062c8dSJulian Elischer  */
969ed062c8dSJulian Elischer void
970ed062c8dSJulian Elischer sched_newthread(struct thread *td)
971ed062c8dSJulian Elischer {
972ed062c8dSJulian Elischer 	struct td_sched *ke;
973ed062c8dSJulian Elischer 
974ed062c8dSJulian Elischer 	ke = (struct td_sched *) (td + 1);
975ed062c8dSJulian Elischer 	bzero(ke, sizeof(*ke));
976ed062c8dSJulian Elischer 	td->td_sched     = ke;
977ed062c8dSJulian Elischer 	ke->ke_thread	= td;
978ed062c8dSJulian Elischer 	ke->ke_state	= KES_THREAD;
979ed062c8dSJulian Elischer }
980ed062c8dSJulian Elischer 
981ed062c8dSJulian Elischer /*
982ed062c8dSJulian Elischer  * Set up an initial concurrency of 1
983ed062c8dSJulian Elischer  * and set the given thread (if given) to be using that
984ed062c8dSJulian Elischer  * concurrency slot.
985ed062c8dSJulian Elischer  * May be used "offline"..before the ksegrp is attached to the world
986ed062c8dSJulian Elischer  * and thus wouldn't need schedlock in that case.
987ed062c8dSJulian Elischer  * Called from:
988ed062c8dSJulian Elischer  *  thr_create()
989ed062c8dSJulian Elischer  *  proc_init() (UMA) via sched_newproc()
990ed062c8dSJulian Elischer  */
991ed062c8dSJulian Elischer void
992ed062c8dSJulian Elischer sched_init_concurrency(struct ksegrp *kg)
993ed062c8dSJulian Elischer {
994ed062c8dSJulian Elischer 
995d39063f2SJulian Elischer 	CTR1(KTR_RUNQ,"kg %p init slots and concurrency to 1", kg);
996ed062c8dSJulian Elischer 	kg->kg_concurrency = 1;
997ed062c8dSJulian Elischer 	kg->kg_avail_opennings = 1;
998ed062c8dSJulian Elischer }
999ed062c8dSJulian Elischer 
1000ed062c8dSJulian Elischer /*
1001ed062c8dSJulian Elischer  * Change the concurrency of an existing ksegrp to N
1002ed062c8dSJulian Elischer  * Called from:
1003ed062c8dSJulian Elischer  *  kse_create()
1004ed062c8dSJulian Elischer  *  kse_exit()
1005ed062c8dSJulian Elischer  *  thread_exit()
1006ed062c8dSJulian Elischer  *  thread_single()
1007ed062c8dSJulian Elischer  */
1008ed062c8dSJulian Elischer void
1009ed062c8dSJulian Elischer sched_set_concurrency(struct ksegrp *kg, int concurrency)
1010ed062c8dSJulian Elischer {
1011ed062c8dSJulian Elischer 
1012d39063f2SJulian Elischer 	CTR4(KTR_RUNQ,"kg %p set concurrency to %d, slots %d -> %d",
1013d39063f2SJulian Elischer 	    kg,
1014d39063f2SJulian Elischer 	    concurrency,
1015d39063f2SJulian Elischer 	    kg->kg_avail_opennings,
1016d39063f2SJulian Elischer 	    kg->kg_avail_opennings + (concurrency - kg->kg_concurrency));
1017ed062c8dSJulian Elischer 	kg->kg_avail_opennings += (concurrency - kg->kg_concurrency);
1018ed062c8dSJulian Elischer 	kg->kg_concurrency = concurrency;
1019ed062c8dSJulian Elischer }
1020ed062c8dSJulian Elischer 
1021ed062c8dSJulian Elischer /*
1022ed062c8dSJulian Elischer  * Called from thread_exit() for all exiting thread
1023ed062c8dSJulian Elischer  *
1024ed062c8dSJulian Elischer  * Not to be confused with sched_exit_thread()
1025ed062c8dSJulian Elischer  * that is only called from thread_exit() for threads exiting
1026ed062c8dSJulian Elischer  * without the rest of the process exiting because it is also called from
1027ed062c8dSJulian Elischer  * sched_exit() and we wouldn't want to call it twice.
1028ed062c8dSJulian Elischer  * XXX This can probably be fixed.
1029ed062c8dSJulian Elischer  */
1030ed062c8dSJulian Elischer void
1031ed062c8dSJulian Elischer sched_thread_exit(struct thread *td)
1032ed062c8dSJulian Elischer {
1033ed062c8dSJulian Elischer 
1034d39063f2SJulian Elischer 	SLOT_RELEASE(td->td_ksegrp);
1035ed062c8dSJulian Elischer 	slot_fill(td->td_ksegrp);
1036ed062c8dSJulian Elischer }
1037ed062c8dSJulian Elischer 
1038ed062c8dSJulian Elischer #endif /* KERN_SWITCH_INCLUDE */
1039