xref: /freebsd/sys/kern/kern_switch.c (revision 2d50560abcbeb1907b640e5658d2ef0fd050397c)
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 
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 
910c0b25aeSJohn Baldwin #include "opt_full_preemption.h"
920c0b25aeSJohn Baldwin 
93dba6c5a6SPeter Wemm #include <sys/param.h>
94dba6c5a6SPeter Wemm #include <sys/systm.h>
952d50560aSMarcel Moolenaar #include <sys/kdb.h>
96dba6c5a6SPeter Wemm #include <sys/kernel.h>
970384fff8SJason Evans #include <sys/ktr.h>
98f34fa851SJohn Baldwin #include <sys/lock.h>
9935e0e5b3SJohn Baldwin #include <sys/mutex.h>
100dba6c5a6SPeter Wemm #include <sys/proc.h>
101dba6c5a6SPeter Wemm #include <sys/queue.h>
102b43179fbSJeff Roberson #include <sys/sched.h>
1030d2a2989SPeter Wemm #if defined(SMP) && (defined(__i386__) || defined(__amd64__))
104cc66ebe2SPeter Wemm #include <sys/smp.h>
105cc66ebe2SPeter Wemm #endif
106182da820SMatthew Dillon #include <machine/critical.h>
107dba6c5a6SPeter Wemm 
108d2ac2316SJake Burkholder CTASSERT((RQB_BPW * RQB_LEN) == RQ_NQS);
109d2ac2316SJake Burkholder 
11048bfcdddSJulian Elischer void panc(char *string1, char *string2);
11148bfcdddSJulian Elischer 
11248bfcdddSJulian Elischer #if 0
113e602ba25SJulian Elischer static void runq_readjust(struct runq *rq, struct kse *ke);
11448bfcdddSJulian Elischer #endif
115e602ba25SJulian Elischer /************************************************************************
116e602ba25SJulian Elischer  * Functions that manipulate runnability from a thread perspective.	*
117e602ba25SJulian Elischer  ************************************************************************/
118e602ba25SJulian Elischer /*
1195215b187SJeff Roberson  * Select the KSE that will be run next.  From that find the thread, and
120e602ba25SJulian Elischer  * remove it from the KSEGRP's run queue.  If there is thread clustering,
121e602ba25SJulian Elischer  * this will be what does it.
122e602ba25SJulian Elischer  */
123b40ce416SJulian Elischer struct thread *
124b40ce416SJulian Elischer choosethread(void)
125dba6c5a6SPeter Wemm {
126e602ba25SJulian Elischer 	struct kse *ke;
127e602ba25SJulian Elischer 	struct thread *td;
128e602ba25SJulian Elischer 	struct ksegrp *kg;
129e602ba25SJulian Elischer 
1300d2a2989SPeter Wemm #if defined(SMP) && (defined(__i386__) || defined(__amd64__))
131cc66ebe2SPeter Wemm 	if (smp_active == 0 && PCPU_GET(cpuid) != 0) {
132cc66ebe2SPeter Wemm 		/* Shutting down, run idlethread on AP's */
133cc66ebe2SPeter Wemm 		td = PCPU_GET(idlethread);
134cc66ebe2SPeter Wemm 		ke = td->td_kse;
135cc66ebe2SPeter Wemm 		CTR1(KTR_RUNQ, "choosethread: td=%p (idle)", td);
136cc66ebe2SPeter Wemm 		ke->ke_flags |= KEF_DIDRUN;
137cc66ebe2SPeter Wemm 		TD_SET_RUNNING(td);
138cc66ebe2SPeter Wemm 		return (td);
139cc66ebe2SPeter Wemm 	}
140cc66ebe2SPeter Wemm #endif
141cc66ebe2SPeter Wemm 
142fe799533SAndrew Gallatin retry:
143cc66ebe2SPeter Wemm 	ke = sched_choose();
144cc66ebe2SPeter Wemm 	if (ke) {
145e602ba25SJulian Elischer 		td = ke->ke_thread;
146e602ba25SJulian Elischer 		KASSERT((td->td_kse == ke), ("kse/thread mismatch"));
147e602ba25SJulian Elischer 		kg = ke->ke_ksegrp;
1480e2a4d3aSDavid Xu 		if (td->td_proc->p_flag & P_SA) {
14933c06e1dSJulian Elischer 			if (kg->kg_last_assigned == td) {
150e602ba25SJulian Elischer 				kg->kg_last_assigned = TAILQ_PREV(td,
151e602ba25SJulian Elischer 				    threadqueue, td_runq);
15233c06e1dSJulian Elischer 			}
153d03c79eeSDavid Xu 			TAILQ_REMOVE(&kg->kg_runq, td, td_runq);
154e602ba25SJulian Elischer 		}
155e602ba25SJulian Elischer 		kg->kg_runnable--;
156e602ba25SJulian Elischer 		CTR2(KTR_RUNQ, "choosethread: td=%p pri=%d",
157e602ba25SJulian Elischer 		    td, td->td_priority);
158e602ba25SJulian Elischer 	} else {
15940e55026SJulian Elischer 		/* Simulate runq_choose() having returned the idle thread */
160e602ba25SJulian Elischer 		td = PCPU_GET(idlethread);
161472be958SJulian Elischer 		ke = td->td_kse;
162e602ba25SJulian Elischer 		CTR1(KTR_RUNQ, "choosethread: td=%p (idle)", td);
163e602ba25SJulian Elischer 	}
164472be958SJulian Elischer 	ke->ke_flags |= KEF_DIDRUN;
16593a7aa79SJulian Elischer 
16693a7aa79SJulian Elischer 	/*
167faaa20f6SJulian Elischer 	 * If we are in panic, only allow system threads,
168faaa20f6SJulian Elischer 	 * plus the one we are running in, to be run.
16993a7aa79SJulian Elischer 	 */
170fe799533SAndrew Gallatin 	if (panicstr && ((td->td_proc->p_flag & P_SYSTEM) == 0 &&
171faaa20f6SJulian Elischer 	    (td->td_flags & TDF_INPANIC) == 0)) {
172faaa20f6SJulian Elischer 		/* note that it is no longer on the run queue */
173faaa20f6SJulian Elischer 		TD_SET_CAN_RUN(td);
174fe799533SAndrew Gallatin 		goto retry;
175faaa20f6SJulian Elischer 	}
17693a7aa79SJulian Elischer 
17771fad9fdSJulian Elischer 	TD_SET_RUNNING(td);
178e602ba25SJulian Elischer 	return (td);
179e602ba25SJulian Elischer }
180e602ba25SJulian Elischer 
181e602ba25SJulian Elischer /*
1825215b187SJeff Roberson  * Given a surplus KSE, either assign a new runable thread to it
1835215b187SJeff Roberson  * (and put it in the run queue) or put it in the ksegrp's idle KSE list.
1844f6cfa45SDavid Xu  * Assumes that the original thread is not runnable.
185e602ba25SJulian Elischer  */
186e602ba25SJulian Elischer void
187e602ba25SJulian Elischer kse_reassign(struct kse *ke)
188e602ba25SJulian Elischer {
189e602ba25SJulian Elischer 	struct ksegrp *kg;
190e602ba25SJulian Elischer 	struct thread *td;
19148bfcdddSJulian Elischer 	struct thread *original;
192e602ba25SJulian Elischer 
19333c06e1dSJulian Elischer 	mtx_assert(&sched_lock, MA_OWNED);
1946f8132a8SJulian Elischer 	original = ke->ke_thread;
1955215b187SJeff Roberson 	KASSERT(original == NULL || TD_IS_INHIBITED(original),
1965215b187SJeff Roberson     	    ("reassigning KSE with runnable thread"));
1975215b187SJeff Roberson 	kg = ke->ke_ksegrp;
1986ce75196SDavid Xu 	if (original)
1995215b187SJeff Roberson 		original->td_kse = NULL;
200e602ba25SJulian Elischer 
201e602ba25SJulian Elischer 	/*
2026f8132a8SJulian Elischer 	 * Find the first unassigned thread
2036f8132a8SJulian Elischer 	 */
2045215b187SJeff Roberson 	if ((td = kg->kg_last_assigned) != NULL)
2056f8132a8SJulian Elischer 		td = TAILQ_NEXT(td, td_runq);
2065215b187SJeff Roberson 	else
2076f8132a8SJulian Elischer 		td = TAILQ_FIRST(&kg->kg_runq);
2086f8132a8SJulian Elischer 
2096f8132a8SJulian Elischer 	/*
2105215b187SJeff Roberson 	 * If we found one, assign it the kse, otherwise idle the kse.
211e602ba25SJulian Elischer 	 */
212e602ba25SJulian Elischer 	if (td) {
213e602ba25SJulian Elischer 		kg->kg_last_assigned = td;
214e602ba25SJulian Elischer 		td->td_kse = ke;
215e602ba25SJulian Elischer 		ke->ke_thread = td;
2167cf90fb3SJeff Roberson 		sched_add(td);
217e602ba25SJulian Elischer 		CTR2(KTR_RUNQ, "kse_reassign: ke%p -> td%p", ke, td);
21848bfcdddSJulian Elischer 		return;
21948bfcdddSJulian Elischer 	}
22048bfcdddSJulian Elischer 
2215215b187SJeff Roberson 	ke->ke_state = KES_IDLE;
22293a7aa79SJulian Elischer 	ke->ke_thread = NULL;
2235215b187SJeff Roberson 	TAILQ_INSERT_TAIL(&kg->kg_iq, ke, ke_kgrlist);
2245215b187SJeff Roberson 	kg->kg_idle_kses++;
2255215b187SJeff Roberson 	CTR1(KTR_RUNQ, "kse_reassign: ke%p on idle queue", ke);
22648bfcdddSJulian Elischer 	return;
227d5a08a60SJake Burkholder }
228d5a08a60SJake Burkholder 
2291f955e2dSJulian Elischer #if 0
230e602ba25SJulian Elischer /*
231e602ba25SJulian Elischer  * Remove a thread from its KSEGRP's run queue.
232e602ba25SJulian Elischer  * This in turn may remove it from a KSE if it was already assigned
233e602ba25SJulian Elischer  * to one, possibly causing a new thread to be assigned to the KSE
2345215b187SJeff Roberson  * and the KSE getting a new priority.
235e602ba25SJulian Elischer  */
2361f955e2dSJulian Elischer static void
237b40ce416SJulian Elischer remrunqueue(struct thread *td)
238d5a08a60SJake Burkholder {
23948bfcdddSJulian Elischer 	struct thread *td2, *td3;
240e602ba25SJulian Elischer 	struct ksegrp *kg;
241e602ba25SJulian Elischer 	struct kse *ke;
242e602ba25SJulian Elischer 
243e602ba25SJulian Elischer 	mtx_assert(&sched_lock, MA_OWNED);
24471fad9fdSJulian Elischer 	KASSERT((TD_ON_RUNQ(td)), ("remrunqueue: Bad state on run queue"));
245e602ba25SJulian Elischer 	kg = td->td_ksegrp;
246e602ba25SJulian Elischer 	ke = td->td_kse;
247e602ba25SJulian Elischer 	CTR1(KTR_RUNQ, "remrunqueue: td%p", td);
248e602ba25SJulian Elischer 	kg->kg_runnable--;
24971fad9fdSJulian Elischer 	TD_SET_CAN_RUN(td);
2505215b187SJeff Roberson 	/*
2515215b187SJeff Roberson 	 * If it is not a threaded process, take the shortcut.
2525215b187SJeff Roberson 	 */
2530e2a4d3aSDavid Xu 	if ((td->td_proc->p_flag & P_SA) == 0) {
254e602ba25SJulian Elischer 		/* Bring its kse with it, leave the thread attached */
2557cf90fb3SJeff Roberson 		sched_rem(td);
256c3b98db0SJulian Elischer 		ke->ke_state = KES_THREAD;
257e602ba25SJulian Elischer 		return;
258d5a08a60SJake Burkholder 	}
25948bfcdddSJulian Elischer    	td3 = TAILQ_PREV(td, threadqueue, td_runq);
26048bfcdddSJulian Elischer 	TAILQ_REMOVE(&kg->kg_runq, td, td_runq);
261e602ba25SJulian Elischer 	if (ke) {
262e602ba25SJulian Elischer 		/*
263e602ba25SJulian Elischer 		 * This thread has been assigned to a KSE.
264e602ba25SJulian Elischer 		 * We need to dissociate it and try assign the
265e602ba25SJulian Elischer 		 * KSE to the next available thread. Then, we should
266e602ba25SJulian Elischer 		 * see if we need to move the KSE in the run queues.
267e602ba25SJulian Elischer 		 */
2687cf90fb3SJeff Roberson 		sched_rem(td);
26993a7aa79SJulian Elischer 		ke->ke_state = KES_THREAD;
270e602ba25SJulian Elischer 		td2 = kg->kg_last_assigned;
271e602ba25SJulian Elischer 		KASSERT((td2 != NULL), ("last assigned has wrong value"));
27248bfcdddSJulian Elischer 		if (td2 == td)
273e602ba25SJulian Elischer 			kg->kg_last_assigned = td3;
27448bfcdddSJulian Elischer 		kse_reassign(ke);
275e602ba25SJulian Elischer 	}
276e602ba25SJulian Elischer }
2771f955e2dSJulian Elischer #endif
2781f955e2dSJulian Elischer 
2791f955e2dSJulian Elischer /*
2801f955e2dSJulian Elischer  * Change the priority of a thread that is on the run queue.
2811f955e2dSJulian Elischer  */
2821f955e2dSJulian Elischer void
2831f955e2dSJulian Elischer adjustrunqueue( struct thread *td, int newpri)
2841f955e2dSJulian Elischer {
2851f955e2dSJulian Elischer 	struct ksegrp *kg;
2861f955e2dSJulian Elischer 	struct kse *ke;
2871f955e2dSJulian Elischer 
2881f955e2dSJulian Elischer 	mtx_assert(&sched_lock, MA_OWNED);
2891f955e2dSJulian Elischer 	KASSERT((TD_ON_RUNQ(td)), ("adjustrunqueue: Bad state on run queue"));
2905215b187SJeff Roberson 
2911f955e2dSJulian Elischer 	ke = td->td_kse;
2921f955e2dSJulian Elischer 	CTR1(KTR_RUNQ, "adjustrunqueue: td%p", td);
2935215b187SJeff Roberson 	/*
2945215b187SJeff Roberson 	 * If it is not a threaded process, take the shortcut.
2955215b187SJeff Roberson 	 */
2960e2a4d3aSDavid Xu 	if ((td->td_proc->p_flag & P_SA) == 0) {
2971f955e2dSJulian Elischer 		/* We only care about the kse in the run queue. */
29824c5baaeSJulian Elischer 		td->td_priority = newpri;
2991f955e2dSJulian Elischer 		if (ke->ke_rqindex != (newpri / RQ_PPQ)) {
3007cf90fb3SJeff Roberson 			sched_rem(td);
3017cf90fb3SJeff Roberson 			sched_add(td);
3021f955e2dSJulian Elischer 		}
3031f955e2dSJulian Elischer 		return;
3041f955e2dSJulian Elischer 	}
3055215b187SJeff Roberson 
3065215b187SJeff Roberson 	/* It is a threaded process */
3071f955e2dSJulian Elischer 	kg = td->td_ksegrp;
3081f955e2dSJulian Elischer 	kg->kg_runnable--;
3091f955e2dSJulian Elischer 	TD_SET_CAN_RUN(td);
3101f955e2dSJulian Elischer 	if (ke) {
3111f955e2dSJulian Elischer 		if (kg->kg_last_assigned == td) {
3121f955e2dSJulian Elischer 			kg->kg_last_assigned =
3131f955e2dSJulian Elischer 			    TAILQ_PREV(td, threadqueue, td_runq);
3141f955e2dSJulian Elischer 		}
3157cf90fb3SJeff Roberson 		sched_rem(td);
3161f955e2dSJulian Elischer 	}
3171f955e2dSJulian Elischer 	TAILQ_REMOVE(&kg->kg_runq, td, td_runq);
3181f955e2dSJulian Elischer 	td->td_priority = newpri;
3191f955e2dSJulian Elischer 	setrunqueue(td);
3201f955e2dSJulian Elischer }
321e602ba25SJulian Elischer 
322d5a08a60SJake Burkholder void
323b40ce416SJulian Elischer setrunqueue(struct thread *td)
324d5a08a60SJake Burkholder {
325e602ba25SJulian Elischer 	struct kse *ke;
326e602ba25SJulian Elischer 	struct ksegrp *kg;
327e602ba25SJulian Elischer 	struct thread *td2;
328e602ba25SJulian Elischer 	struct thread *tda;
329e602ba25SJulian Elischer 
330e602ba25SJulian Elischer 	CTR1(KTR_RUNQ, "setrunqueue: td%p", td);
331e602ba25SJulian Elischer 	mtx_assert(&sched_lock, MA_OWNED);
33271fad9fdSJulian Elischer 	KASSERT((TD_CAN_RUN(td) || TD_IS_RUNNING(td)),
33371fad9fdSJulian Elischer 	    ("setrunqueue: bad thread state"));
33471fad9fdSJulian Elischer 	TD_SET_RUNQ(td);
335e602ba25SJulian Elischer 	kg = td->td_ksegrp;
336e602ba25SJulian Elischer 	kg->kg_runnable++;
3370e2a4d3aSDavid Xu 	if ((td->td_proc->p_flag & P_SA) == 0) {
33848bfcdddSJulian Elischer 		/*
33948bfcdddSJulian Elischer 		 * Common path optimisation: Only one of everything
34048bfcdddSJulian Elischer 		 * and the KSE is always already attached.
34148bfcdddSJulian Elischer 		 * Totally ignore the ksegrp run queue.
34248bfcdddSJulian Elischer 		 */
3437cf90fb3SJeff Roberson 		sched_add(td);
34448bfcdddSJulian Elischer 		return;
34548bfcdddSJulian Elischer 	}
34648bfcdddSJulian Elischer 
347e602ba25SJulian Elischer 	tda = kg->kg_last_assigned;
348e602ba25SJulian Elischer 	if ((ke = td->td_kse) == NULL) {
3495215b187SJeff Roberson 		if (kg->kg_idle_kses) {
350e602ba25SJulian Elischer 			/*
3515215b187SJeff Roberson 			 * There is a free one so it's ours for the asking..
352e602ba25SJulian Elischer 			 */
3535215b187SJeff Roberson 			ke = TAILQ_FIRST(&kg->kg_iq);
3545215b187SJeff Roberson 			TAILQ_REMOVE(&kg->kg_iq, ke, ke_kgrlist);
3559eb1fdeaSJulian Elischer 			ke->ke_state = KES_THREAD;
3565215b187SJeff Roberson 			kg->kg_idle_kses--;
357e602ba25SJulian Elischer 		} else if (tda && (tda->td_priority > td->td_priority)) {
358e602ba25SJulian Elischer 			/*
359e602ba25SJulian Elischer 			 * None free, but there is one we can commandeer.
360e602ba25SJulian Elischer 			 */
361e602ba25SJulian Elischer 			ke = tda->td_kse;
36294816f6dSJeff Roberson 			sched_rem(tda);
363e602ba25SJulian Elischer 			tda->td_kse = NULL;
364e602ba25SJulian Elischer 			ke->ke_thread = NULL;
365e602ba25SJulian Elischer 			tda = kg->kg_last_assigned =
366e602ba25SJulian Elischer 		    	    TAILQ_PREV(tda, threadqueue, td_runq);
367e602ba25SJulian Elischer 		}
368e602ba25SJulian Elischer 	} else {
369c3b98db0SJulian Elischer 		/*
370c3b98db0SJulian Elischer 		 * Temporarily disassociate so it looks like the other cases.
371c3b98db0SJulian Elischer 		 */
372e602ba25SJulian Elischer 		ke->ke_thread = NULL;
373e602ba25SJulian Elischer 		td->td_kse = NULL;
374d5a08a60SJake Burkholder 	}
375d5a08a60SJake Burkholder 
376e602ba25SJulian Elischer 	/*
377e602ba25SJulian Elischer 	 * Add the thread to the ksegrp's run queue at
378e602ba25SJulian Elischer 	 * the appropriate place.
379e602ba25SJulian Elischer 	 */
380e602ba25SJulian Elischer 	TAILQ_FOREACH(td2, &kg->kg_runq, td_runq) {
381e602ba25SJulian Elischer 		if (td2->td_priority > td->td_priority) {
382e602ba25SJulian Elischer 			TAILQ_INSERT_BEFORE(td2, td, td_runq);
383e602ba25SJulian Elischer 			break;
384e602ba25SJulian Elischer 		}
385e602ba25SJulian Elischer 	}
386e602ba25SJulian Elischer 	if (td2 == NULL) {
387e602ba25SJulian Elischer 		/* We ran off the end of the TAILQ or it was empty. */
388e602ba25SJulian Elischer 		TAILQ_INSERT_TAIL(&kg->kg_runq, td, td_runq);
389e602ba25SJulian Elischer 	}
390e602ba25SJulian Elischer 
391e602ba25SJulian Elischer 	/*
392e602ba25SJulian Elischer 	 * If we have a ke to use, then put it on the run queue and
393e602ba25SJulian Elischer 	 * If needed, readjust the last_assigned pointer.
394e602ba25SJulian Elischer 	 */
395e602ba25SJulian Elischer 	if (ke) {
396e602ba25SJulian Elischer 		if (tda == NULL) {
397e602ba25SJulian Elischer 			/*
398e602ba25SJulian Elischer 			 * No pre-existing last assigned so whoever is first
399c3b98db0SJulian Elischer 			 * gets the KSE we brought in.. (maybe us)
400e602ba25SJulian Elischer 			 */
401e602ba25SJulian Elischer 			td2 = TAILQ_FIRST(&kg->kg_runq);
402e602ba25SJulian Elischer 			KASSERT((td2->td_kse == NULL),
403e602ba25SJulian Elischer 			    ("unexpected ke present"));
404e602ba25SJulian Elischer 			td2->td_kse = ke;
405e602ba25SJulian Elischer 			ke->ke_thread = td2;
406e602ba25SJulian Elischer 			kg->kg_last_assigned = td2;
407e602ba25SJulian Elischer 		} else if (tda->td_priority > td->td_priority) {
408e602ba25SJulian Elischer 			/*
409e602ba25SJulian Elischer 			 * It's ours, grab it, but last_assigned is past us
410e602ba25SJulian Elischer 			 * so don't change it.
411e602ba25SJulian Elischer 			 */
412e602ba25SJulian Elischer 			td->td_kse = ke;
413e602ba25SJulian Elischer 			ke->ke_thread = td;
414e602ba25SJulian Elischer 		} else {
415e602ba25SJulian Elischer 			/*
416e602ba25SJulian Elischer 			 * We are past last_assigned, so
417e602ba25SJulian Elischer 			 * put the new kse on whatever is next,
418e602ba25SJulian Elischer 			 * which may or may not be us.
419e602ba25SJulian Elischer 			 */
420e602ba25SJulian Elischer 			td2 = TAILQ_NEXT(tda, td_runq);
421e602ba25SJulian Elischer 			kg->kg_last_assigned = td2;
422e602ba25SJulian Elischer 			td2->td_kse = ke;
423e602ba25SJulian Elischer 			ke->ke_thread = td2;
424e602ba25SJulian Elischer 		}
4257cf90fb3SJeff Roberson 		sched_add(ke->ke_thread);
426e602ba25SJulian Elischer 	}
427e602ba25SJulian Elischer }
428e602ba25SJulian Elischer 
4290c0b25aeSJohn Baldwin /*
4300c0b25aeSJohn Baldwin  * Kernel thread preemption implementation.  Critical sections mark
4310c0b25aeSJohn Baldwin  * regions of code in which preemptions are not allowed.
4320c0b25aeSJohn Baldwin  */
4337e1f6dfeSJohn Baldwin void
4347e1f6dfeSJohn Baldwin critical_enter(void)
4357e1f6dfeSJohn Baldwin {
4367e1f6dfeSJohn Baldwin 	struct thread *td;
4377e1f6dfeSJohn Baldwin 
4387e1f6dfeSJohn Baldwin 	td = curthread;
4397e1f6dfeSJohn Baldwin 	if (td->td_critnest == 0)
440d74ac681SMatthew Dillon 		cpu_critical_enter();
4417e1f6dfeSJohn Baldwin 	td->td_critnest++;
4427e1f6dfeSJohn Baldwin }
4437e1f6dfeSJohn Baldwin 
4447e1f6dfeSJohn Baldwin void
4457e1f6dfeSJohn Baldwin critical_exit(void)
4467e1f6dfeSJohn Baldwin {
4477e1f6dfeSJohn Baldwin 	struct thread *td;
4487e1f6dfeSJohn Baldwin 
4497e1f6dfeSJohn Baldwin 	td = curthread;
450b209e5e3SJeff Roberson 	KASSERT(td->td_critnest != 0,
451b209e5e3SJeff Roberson 	    ("critical_exit: td_critnest == 0"));
4527e1f6dfeSJohn Baldwin 	if (td->td_critnest == 1) {
4530c0b25aeSJohn Baldwin #ifdef PREEMPTION
4540c0b25aeSJohn Baldwin 		if (td->td_flags & TDF_OWEPREEMPT) {
4550c0b25aeSJohn Baldwin 			mtx_lock_spin(&sched_lock);
4560c0b25aeSJohn Baldwin 			mi_switch(SW_INVOL, NULL);
4570c0b25aeSJohn Baldwin 			mtx_unlock_spin(&sched_lock);
4580c0b25aeSJohn Baldwin 		}
4590c0b25aeSJohn Baldwin #endif
4607e1f6dfeSJohn Baldwin 		td->td_critnest = 0;
461d74ac681SMatthew Dillon 		cpu_critical_exit();
462d74ac681SMatthew Dillon 	} else {
4637e1f6dfeSJohn Baldwin 		td->td_critnest--;
4647e1f6dfeSJohn Baldwin 	}
465d74ac681SMatthew Dillon }
4667e1f6dfeSJohn Baldwin 
4670c0b25aeSJohn Baldwin /*
4680c0b25aeSJohn Baldwin  * This function is called when a thread is about to be put on run queue
4690c0b25aeSJohn Baldwin  * because it has been made runnable or its priority has been adjusted.  It
4700c0b25aeSJohn Baldwin  * determines if the new thread should be immediately preempted to.  If so,
4710c0b25aeSJohn Baldwin  * it switches to it and eventually returns true.  If not, it returns false
4720c0b25aeSJohn Baldwin  * so that the caller may place the thread on an appropriate run queue.
4730c0b25aeSJohn Baldwin  */
4740c0b25aeSJohn Baldwin int
4750c0b25aeSJohn Baldwin maybe_preempt(struct thread *td)
4760c0b25aeSJohn Baldwin {
4778b44a2e2SMarcel Moolenaar #ifdef PREEMPTION
4780c0b25aeSJohn Baldwin 	struct thread *ctd;
4790c0b25aeSJohn Baldwin 	int cpri, pri;
4808b44a2e2SMarcel Moolenaar #endif
4810c0b25aeSJohn Baldwin 
4820c0b25aeSJohn Baldwin 	mtx_assert(&sched_lock, MA_OWNED);
4830c0b25aeSJohn Baldwin #ifdef PREEMPTION
4840c0b25aeSJohn Baldwin 	/*
4850c0b25aeSJohn Baldwin 	 * The new thread should not preempt the current thread if any of the
4860c0b25aeSJohn Baldwin 	 * following conditions are true:
4870c0b25aeSJohn Baldwin 	 *
4880c0b25aeSJohn Baldwin 	 *  - The current thread has a higher (numerically lower) priority.
4890c0b25aeSJohn Baldwin 	 *  - It is too early in the boot for context switches (cold is set).
4900c0b25aeSJohn Baldwin 	 *  - The current thread has an inhibitor set or is in the process of
4910c0b25aeSJohn Baldwin 	 *    exiting.  In this case, the current thread is about to switch
4920c0b25aeSJohn Baldwin 	 *    out anyways, so there's no point in preempting.  If we did,
4930c0b25aeSJohn Baldwin 	 *    the current thread would not be properly resumed as well, so
4940c0b25aeSJohn Baldwin 	 *    just avoid that whole landmine.
4950c0b25aeSJohn Baldwin 	 *  - If the new thread's priority is not a realtime priority and
4960c0b25aeSJohn Baldwin 	 *    the current thread's priority is not an idle priority and
4970c0b25aeSJohn Baldwin 	 *    FULL_PREEMPTION is disabled.
4980c0b25aeSJohn Baldwin 	 *
4990c0b25aeSJohn Baldwin 	 * If all of these conditions are false, but the current thread is in
5000c0b25aeSJohn Baldwin 	 * a nested critical section, then we have to defer the preemption
5010c0b25aeSJohn Baldwin 	 * until we exit the critical section.  Otherwise, switch immediately
5020c0b25aeSJohn Baldwin 	 * to the new thread.
5030c0b25aeSJohn Baldwin 	 */
5040c0b25aeSJohn Baldwin 	ctd = curthread;
5050c0b25aeSJohn Baldwin 	pri = td->td_priority;
5060c0b25aeSJohn Baldwin 	cpri = ctd->td_priority;
5070c0b25aeSJohn Baldwin 	if (pri >= cpri || cold /* || dumping */ || TD_IS_INHIBITED(ctd) ||
5080c0b25aeSJohn Baldwin 	    td->td_kse->ke_state != KES_THREAD)
5090c0b25aeSJohn Baldwin 		return (0);
5100c0b25aeSJohn Baldwin #ifndef FULL_PREEMPTION
5110c0b25aeSJohn Baldwin 	if (!(pri >= PRI_MIN_ITHD && pri <= PRI_MAX_ITHD) &&
5120c0b25aeSJohn Baldwin 	    !(cpri >= PRI_MIN_IDLE))
5130c0b25aeSJohn Baldwin 		return (0);
5140c0b25aeSJohn Baldwin #endif
5150c0b25aeSJohn Baldwin 	if (ctd->td_critnest > 1) {
5160c0b25aeSJohn Baldwin 		CTR1(KTR_PROC, "maybe_preempt: in critical section %d",
5170c0b25aeSJohn Baldwin 		    ctd->td_critnest);
5180c0b25aeSJohn Baldwin 		ctd->td_flags |= TDF_OWEPREEMPT;
5190c0b25aeSJohn Baldwin 		return (0);
5200c0b25aeSJohn Baldwin 	}
5210c0b25aeSJohn Baldwin 
5220c0b25aeSJohn Baldwin 	/*
5230c0b25aeSJohn Baldwin 	 * Our thread state says that we are already on a run queue, so
5240c0b25aeSJohn Baldwin 	 * update our state as if we had been dequeued by choosethread().
5250c0b25aeSJohn Baldwin 	 */
5260c0b25aeSJohn Baldwin 	MPASS(TD_ON_RUNQ(td));
5270c0b25aeSJohn Baldwin 	TD_SET_RUNNING(td);
5280c0b25aeSJohn Baldwin 	CTR3(KTR_PROC, "preempting to thread %p (pid %d, %s)\n", td,
5290c0b25aeSJohn Baldwin 	    td->td_proc->p_pid, td->td_proc->p_comm);
5300c0b25aeSJohn Baldwin 	mi_switch(SW_INVOL, td);
5310c0b25aeSJohn Baldwin 	return (1);
5320c0b25aeSJohn Baldwin #else
5330c0b25aeSJohn Baldwin 	return (0);
5340c0b25aeSJohn Baldwin #endif
5350c0b25aeSJohn Baldwin }
5360c0b25aeSJohn Baldwin 
5370c0b25aeSJohn Baldwin #ifndef PREEMPTION
5380c0b25aeSJohn Baldwin /* XXX: There should be a non-static version of this. */
5390c0b25aeSJohn Baldwin static void
5400c0b25aeSJohn Baldwin printf_caddr_t(void *data)
5410c0b25aeSJohn Baldwin {
5420c0b25aeSJohn Baldwin 	printf("%s", (char *)data);
5430c0b25aeSJohn Baldwin }
5440c0b25aeSJohn Baldwin static char preempt_warning[] =
5450c0b25aeSJohn Baldwin     "WARNING: Kernel preemption is disabled, expect reduced performance.\n";
5460c0b25aeSJohn Baldwin SYSINIT(preempt_warning, SI_SUB_COPYRIGHT, SI_ORDER_ANY, printf_caddr_t,
5470c0b25aeSJohn Baldwin     preempt_warning)
5480c0b25aeSJohn Baldwin #endif
549e602ba25SJulian Elischer 
550e602ba25SJulian Elischer /************************************************************************
551e602ba25SJulian Elischer  * SYSTEM RUN QUEUE manipulations and tests				*
552e602ba25SJulian Elischer  ************************************************************************/
553e602ba25SJulian Elischer /*
554e602ba25SJulian Elischer  * Initialize a run structure.
555e602ba25SJulian Elischer  */
556e602ba25SJulian Elischer void
557e602ba25SJulian Elischer runq_init(struct runq *rq)
558e602ba25SJulian Elischer {
559e602ba25SJulian Elischer 	int i;
560e602ba25SJulian Elischer 
561e602ba25SJulian Elischer 	bzero(rq, sizeof *rq);
562e602ba25SJulian Elischer 	for (i = 0; i < RQ_NQS; i++)
563e602ba25SJulian Elischer 		TAILQ_INIT(&rq->rq_queues[i]);
564e602ba25SJulian Elischer }
565e602ba25SJulian Elischer 
566d5a08a60SJake Burkholder /*
567d5a08a60SJake Burkholder  * Clear the status bit of the queue corresponding to priority level pri,
568d5a08a60SJake Burkholder  * indicating that it is empty.
569d5a08a60SJake Burkholder  */
570d5a08a60SJake Burkholder static __inline void
571d5a08a60SJake Burkholder runq_clrbit(struct runq *rq, int pri)
572d5a08a60SJake Burkholder {
573d5a08a60SJake Burkholder 	struct rqbits *rqb;
574d5a08a60SJake Burkholder 
575d5a08a60SJake Burkholder 	rqb = &rq->rq_status;
576d5a08a60SJake Burkholder 	CTR4(KTR_RUNQ, "runq_clrbit: bits=%#x %#x bit=%#x word=%d",
577d5a08a60SJake Burkholder 	    rqb->rqb_bits[RQB_WORD(pri)],
578d5a08a60SJake Burkholder 	    rqb->rqb_bits[RQB_WORD(pri)] & ~RQB_BIT(pri),
579d5a08a60SJake Burkholder 	    RQB_BIT(pri), RQB_WORD(pri));
580d5a08a60SJake Burkholder 	rqb->rqb_bits[RQB_WORD(pri)] &= ~RQB_BIT(pri);
581d5a08a60SJake Burkholder }
582d5a08a60SJake Burkholder 
583d5a08a60SJake Burkholder /*
584d5a08a60SJake Burkholder  * Find the index of the first non-empty run queue.  This is done by
585d5a08a60SJake Burkholder  * scanning the status bits, a set bit indicates a non-empty queue.
586d5a08a60SJake Burkholder  */
587d5a08a60SJake Burkholder static __inline int
588d5a08a60SJake Burkholder runq_findbit(struct runq *rq)
589d5a08a60SJake Burkholder {
590d5a08a60SJake Burkholder 	struct rqbits *rqb;
591d5a08a60SJake Burkholder 	int pri;
592d5a08a60SJake Burkholder 	int i;
593d5a08a60SJake Burkholder 
594d5a08a60SJake Burkholder 	rqb = &rq->rq_status;
595d5a08a60SJake Burkholder 	for (i = 0; i < RQB_LEN; i++)
596d5a08a60SJake Burkholder 		if (rqb->rqb_bits[i]) {
5972f9267ecSPeter Wemm 			pri = RQB_FFS(rqb->rqb_bits[i]) + (i << RQB_L2BPW);
598d5a08a60SJake Burkholder 			CTR3(KTR_RUNQ, "runq_findbit: bits=%#x i=%d pri=%d",
599d5a08a60SJake Burkholder 			    rqb->rqb_bits[i], i, pri);
600d5a08a60SJake Burkholder 			return (pri);
601d5a08a60SJake Burkholder 		}
602d5a08a60SJake Burkholder 
603d5a08a60SJake Burkholder 	return (-1);
604d5a08a60SJake Burkholder }
605d5a08a60SJake Burkholder 
606d5a08a60SJake Burkholder /*
607d5a08a60SJake Burkholder  * Set the status bit of the queue corresponding to priority level pri,
608d5a08a60SJake Burkholder  * indicating that it is non-empty.
609d5a08a60SJake Burkholder  */
610d5a08a60SJake Burkholder static __inline void
611d5a08a60SJake Burkholder runq_setbit(struct runq *rq, int pri)
612d5a08a60SJake Burkholder {
613d5a08a60SJake Burkholder 	struct rqbits *rqb;
614d5a08a60SJake Burkholder 
615d5a08a60SJake Burkholder 	rqb = &rq->rq_status;
616d5a08a60SJake Burkholder 	CTR4(KTR_RUNQ, "runq_setbit: bits=%#x %#x bit=%#x word=%d",
617d5a08a60SJake Burkholder 	    rqb->rqb_bits[RQB_WORD(pri)],
618d5a08a60SJake Burkholder 	    rqb->rqb_bits[RQB_WORD(pri)] | RQB_BIT(pri),
619d5a08a60SJake Burkholder 	    RQB_BIT(pri), RQB_WORD(pri));
620d5a08a60SJake Burkholder 	rqb->rqb_bits[RQB_WORD(pri)] |= RQB_BIT(pri);
621d5a08a60SJake Burkholder }
622d5a08a60SJake Burkholder 
623d5a08a60SJake Burkholder /*
624e602ba25SJulian Elischer  * Add the KSE to the queue specified by its priority, and set the
625d5a08a60SJake Burkholder  * corresponding status bit.
626d5a08a60SJake Burkholder  */
627d5a08a60SJake Burkholder void
628b40ce416SJulian Elischer runq_add(struct runq *rq, struct kse *ke)
629d5a08a60SJake Burkholder {
630d5a08a60SJake Burkholder 	struct rqhead *rqh;
631d5a08a60SJake Burkholder 	int pri;
632dba6c5a6SPeter Wemm 
6332c100766SJulian Elischer 	pri = ke->ke_thread->td_priority / RQ_PPQ;
634b40ce416SJulian Elischer 	ke->ke_rqindex = pri;
635d5a08a60SJake Burkholder 	runq_setbit(rq, pri);
636d5a08a60SJake Burkholder 	rqh = &rq->rq_queues[pri];
637d5a08a60SJake Burkholder 	CTR4(KTR_RUNQ, "runq_add: p=%p pri=%d %d rqh=%p",
6382c100766SJulian Elischer 	    ke->ke_proc, ke->ke_thread->td_priority, pri, rqh);
639b40ce416SJulian Elischer 	TAILQ_INSERT_TAIL(rqh, ke, ke_procq);
640dba6c5a6SPeter Wemm }
641d5a08a60SJake Burkholder 
642d5a08a60SJake Burkholder /*
643d5a08a60SJake Burkholder  * Return true if there are runnable processes of any priority on the run
644d5a08a60SJake Burkholder  * queue, false otherwise.  Has no side effects, does not modify the run
645d5a08a60SJake Burkholder  * queue structure.
646d5a08a60SJake Burkholder  */
647d5a08a60SJake Burkholder int
648d5a08a60SJake Burkholder runq_check(struct runq *rq)
649d5a08a60SJake Burkholder {
650d5a08a60SJake Burkholder 	struct rqbits *rqb;
651d5a08a60SJake Burkholder 	int i;
652d5a08a60SJake Burkholder 
653d5a08a60SJake Burkholder 	rqb = &rq->rq_status;
654d5a08a60SJake Burkholder 	for (i = 0; i < RQB_LEN; i++)
655d5a08a60SJake Burkholder 		if (rqb->rqb_bits[i]) {
656d5a08a60SJake Burkholder 			CTR2(KTR_RUNQ, "runq_check: bits=%#x i=%d",
657d5a08a60SJake Burkholder 			    rqb->rqb_bits[i], i);
658d5a08a60SJake Burkholder 			return (1);
659dba6c5a6SPeter Wemm 		}
660d5a08a60SJake Burkholder 	CTR0(KTR_RUNQ, "runq_check: empty");
661d5a08a60SJake Burkholder 
662d5a08a60SJake Burkholder 	return (0);
663dba6c5a6SPeter Wemm }
664d5a08a60SJake Burkholder 
665d5a08a60SJake Burkholder /*
666b43179fbSJeff Roberson  * Find the highest priority process on the run queue.
667d5a08a60SJake Burkholder  */
668b40ce416SJulian Elischer struct kse *
669d5a08a60SJake Burkholder runq_choose(struct runq *rq)
670d5a08a60SJake Burkholder {
671d5a08a60SJake Burkholder 	struct rqhead *rqh;
672b40ce416SJulian Elischer 	struct kse *ke;
673d5a08a60SJake Burkholder 	int pri;
674d5a08a60SJake Burkholder 
675d5a08a60SJake Burkholder 	mtx_assert(&sched_lock, MA_OWNED);
676e602ba25SJulian Elischer 	while ((pri = runq_findbit(rq)) != -1) {
677d5a08a60SJake Burkholder 		rqh = &rq->rq_queues[pri];
678b40ce416SJulian Elischer 		ke = TAILQ_FIRST(rqh);
679b40ce416SJulian Elischer 		KASSERT(ke != NULL, ("runq_choose: no proc on busy queue"));
680e602ba25SJulian Elischer 		CTR3(KTR_RUNQ,
681e602ba25SJulian Elischer 		    "runq_choose: pri=%d kse=%p rqh=%p", pri, ke, rqh);
682b40ce416SJulian Elischer 		return (ke);
683d5a08a60SJake Burkholder 	}
684d5a08a60SJake Burkholder 	CTR1(KTR_RUNQ, "runq_choose: idleproc pri=%d", pri);
685d5a08a60SJake Burkholder 
686e602ba25SJulian Elischer 	return (NULL);
687d5a08a60SJake Burkholder }
688d5a08a60SJake Burkholder 
689d5a08a60SJake Burkholder /*
690e602ba25SJulian Elischer  * Remove the KSE from the queue specified by its priority, and clear the
691d5a08a60SJake Burkholder  * corresponding status bit if the queue becomes empty.
692e602ba25SJulian Elischer  * Caller must set ke->ke_state afterwards.
693d5a08a60SJake Burkholder  */
694d5a08a60SJake Burkholder void
695b40ce416SJulian Elischer runq_remove(struct runq *rq, struct kse *ke)
696d5a08a60SJake Burkholder {
697d5a08a60SJake Burkholder 	struct rqhead *rqh;
698d5a08a60SJake Burkholder 	int pri;
699d5a08a60SJake Burkholder 
7009eb881f8SSeigo Tanimura 	KASSERT(ke->ke_proc->p_sflag & PS_INMEM,
7019eb881f8SSeigo Tanimura 		("runq_remove: process swapped out"));
702b40ce416SJulian Elischer 	pri = ke->ke_rqindex;
703d5a08a60SJake Burkholder 	rqh = &rq->rq_queues[pri];
704d5a08a60SJake Burkholder 	CTR4(KTR_RUNQ, "runq_remove: p=%p pri=%d %d rqh=%p",
7052c100766SJulian Elischer 	    ke, ke->ke_thread->td_priority, pri, rqh);
706b40ce416SJulian Elischer 	KASSERT(ke != NULL, ("runq_remove: no proc on busy queue"));
707b40ce416SJulian Elischer 	TAILQ_REMOVE(rqh, ke, ke_procq);
708d5a08a60SJake Burkholder 	if (TAILQ_EMPTY(rqh)) {
709d5a08a60SJake Burkholder 		CTR0(KTR_RUNQ, "runq_remove: empty");
710d5a08a60SJake Burkholder 		runq_clrbit(rq, pri);
711d5a08a60SJake Burkholder 	}
712dba6c5a6SPeter Wemm }
713e602ba25SJulian Elischer 
71448bfcdddSJulian Elischer #if 0
715e602ba25SJulian Elischer void
71648bfcdddSJulian Elischer panc(char *string1, char *string2)
71748bfcdddSJulian Elischer {
71848bfcdddSJulian Elischer 	printf("%s", string1);
7192d50560aSMarcel Moolenaar 	kdb_enter(string2);
72048bfcdddSJulian Elischer }
72148bfcdddSJulian Elischer 
72248bfcdddSJulian Elischer void
72348bfcdddSJulian Elischer thread_sanity_check(struct thread *td, char *string)
724e602ba25SJulian Elischer {
725e602ba25SJulian Elischer 	struct proc *p;
726e602ba25SJulian Elischer 	struct ksegrp *kg;
727e602ba25SJulian Elischer 	struct kse *ke;
72848bfcdddSJulian Elischer 	struct thread *td2 = NULL;
729e602ba25SJulian Elischer 	unsigned int prevpri;
73048bfcdddSJulian Elischer 	int	saw_lastassigned = 0;
73148bfcdddSJulian Elischer 	int unassigned = 0;
73248bfcdddSJulian Elischer 	int assigned = 0;
733e602ba25SJulian Elischer 
734e602ba25SJulian Elischer 	p = td->td_proc;
735e602ba25SJulian Elischer 	kg = td->td_ksegrp;
736e602ba25SJulian Elischer 	ke = td->td_kse;
737e602ba25SJulian Elischer 
738e602ba25SJulian Elischer 
739e602ba25SJulian Elischer 	if (ke) {
7404f0db5e0SJulian Elischer 		if (p != ke->ke_proc) {
74148bfcdddSJulian Elischer 			panc(string, "wrong proc");
742e602ba25SJulian Elischer 		}
743e602ba25SJulian Elischer 		if (ke->ke_thread != td) {
74448bfcdddSJulian Elischer 			panc(string, "wrong thread");
745e602ba25SJulian Elischer 		}
746e602ba25SJulian Elischer 	}
747e602ba25SJulian Elischer 
7480e2a4d3aSDavid Xu 	if ((p->p_flag & P_SA) == 0) {
749e602ba25SJulian Elischer 		if (ke == NULL) {
75048bfcdddSJulian Elischer 			panc(string, "non KSE thread lost kse");
751e602ba25SJulian Elischer 		}
752e602ba25SJulian Elischer 	} else {
753e602ba25SJulian Elischer 		prevpri = 0;
754e602ba25SJulian Elischer 		saw_lastassigned = 0;
755e602ba25SJulian Elischer 		unassigned = 0;
756e602ba25SJulian Elischer 		assigned = 0;
757e602ba25SJulian Elischer 		TAILQ_FOREACH(td2, &kg->kg_runq, td_runq) {
758e602ba25SJulian Elischer 			if (td2->td_priority < prevpri) {
75948bfcdddSJulian Elischer 				panc(string, "thread runqueue unosorted");
76048bfcdddSJulian Elischer 			}
76148bfcdddSJulian Elischer 			if ((td2->td_state == TDS_RUNQ) &&
76248bfcdddSJulian Elischer 			    td2->td_kse &&
76348bfcdddSJulian Elischer 			    (td2->td_kse->ke_state != KES_ONRUNQ)) {
76448bfcdddSJulian Elischer 				panc(string, "KSE wrong state");
765e602ba25SJulian Elischer 			}
766e602ba25SJulian Elischer 			prevpri = td2->td_priority;
767e602ba25SJulian Elischer 			if (td2->td_kse) {
768e602ba25SJulian Elischer 				assigned++;
769e602ba25SJulian Elischer 				if (unassigned) {
77048bfcdddSJulian Elischer 					panc(string, "unassigned before assigned");
771e602ba25SJulian Elischer 				}
772e602ba25SJulian Elischer  				if  (kg->kg_last_assigned == NULL) {
77348bfcdddSJulian Elischer 					panc(string, "lastassigned corrupt");
774e602ba25SJulian Elischer 				}
775e602ba25SJulian Elischer 				if (saw_lastassigned) {
77648bfcdddSJulian Elischer 					panc(string, "last assigned not last");
777e602ba25SJulian Elischer 				}
778e602ba25SJulian Elischer 				if (td2->td_kse->ke_thread != td2) {
77948bfcdddSJulian Elischer 					panc(string, "mismatched kse/thread");
780e602ba25SJulian Elischer 				}
781e602ba25SJulian Elischer 			} else {
782e602ba25SJulian Elischer 				unassigned++;
783e602ba25SJulian Elischer 			}
784e602ba25SJulian Elischer 			if (td2 == kg->kg_last_assigned) {
785e602ba25SJulian Elischer 				saw_lastassigned = 1;
786e602ba25SJulian Elischer 				if (td2->td_kse == NULL) {
78748bfcdddSJulian Elischer 					panc(string, "last assigned not assigned");
788e602ba25SJulian Elischer 				}
789e602ba25SJulian Elischer 			}
790e602ba25SJulian Elischer 		}
791e602ba25SJulian Elischer 		if (kg->kg_last_assigned && (saw_lastassigned == 0)) {
79248bfcdddSJulian Elischer 			panc(string, "where on earth does lastassigned point?");
793e602ba25SJulian Elischer 		}
7945215b187SJeff Roberson #if 0
795e602ba25SJulian Elischer 		FOREACH_THREAD_IN_GROUP(kg, td2) {
796e602ba25SJulian Elischer 			if (((td2->td_flags & TDF_UNBOUND) == 0) &&
79771fad9fdSJulian Elischer 			    (TD_ON_RUNQ(td2))) {
798e602ba25SJulian Elischer 				assigned++;
799e602ba25SJulian Elischer 				if (td2->td_kse == NULL) {
80048bfcdddSJulian Elischer 					panc(string, "BOUND thread with no KSE");
801e602ba25SJulian Elischer 				}
802e602ba25SJulian Elischer 			}
803e602ba25SJulian Elischer 		}
8045215b187SJeff Roberson #endif
805e602ba25SJulian Elischer #if 0
806e602ba25SJulian Elischer 		if ((unassigned + assigned) != kg->kg_runnable) {
80748bfcdddSJulian Elischer 			panc(string, "wrong number in runnable");
808e602ba25SJulian Elischer 		}
809e602ba25SJulian Elischer #endif
810e602ba25SJulian Elischer 	}
81148bfcdddSJulian Elischer 	if (assigned == 12345) {
81248bfcdddSJulian Elischer 		printf("%p %p %p %p %p %d, %d",
81348bfcdddSJulian Elischer 		    td, td2, ke, kg, p, assigned, saw_lastassigned);
81448bfcdddSJulian Elischer 	}
815e602ba25SJulian Elischer }
8165e3da64eSJulian Elischer #endif
817e602ba25SJulian Elischer 
818