xref: /freebsd/sys/kern/kern_switch.c (revision a90f3f2547a012ead16d3f10b13d2868bff1f25f)
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 
28677b542eSDavid E. O'Brien #include <sys/cdefs.h>
29677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$");
30e602ba25SJulian Elischer 
316804a3abSJulian Elischer #include "opt_sched.h"
320c0b25aeSJohn Baldwin 
33ed062c8dSJulian Elischer #ifndef KERN_SWITCH_INCLUDE
34dba6c5a6SPeter Wemm #include <sys/param.h>
35dba6c5a6SPeter Wemm #include <sys/systm.h>
362d50560aSMarcel Moolenaar #include <sys/kdb.h>
37dba6c5a6SPeter Wemm #include <sys/kernel.h>
380384fff8SJason Evans #include <sys/ktr.h>
39f34fa851SJohn Baldwin #include <sys/lock.h>
4035e0e5b3SJohn Baldwin #include <sys/mutex.h>
41dba6c5a6SPeter Wemm #include <sys/proc.h>
42dba6c5a6SPeter Wemm #include <sys/queue.h>
43b43179fbSJeff Roberson #include <sys/sched.h>
44ed062c8dSJulian Elischer #else  /* KERN_SWITCH_INCLUDE */
450d2a2989SPeter Wemm #if defined(SMP) && (defined(__i386__) || defined(__amd64__))
46cc66ebe2SPeter Wemm #include <sys/smp.h>
47cc66ebe2SPeter Wemm #endif
486804a3abSJulian Elischer 
497b20fb19SJeff Roberson #include <machine/cpu.h>
507b20fb19SJeff Roberson 
511335c4dfSNate Lawson /* Uncomment this to enable logging of critical_enter/exit. */
521335c4dfSNate Lawson #if 0
531335c4dfSNate Lawson #define	KTR_CRITICAL	KTR_SCHED
541335c4dfSNate Lawson #else
551335c4dfSNate Lawson #define	KTR_CRITICAL	0
561335c4dfSNate Lawson #endif
571335c4dfSNate Lawson 
589923b511SScott Long #ifdef FULL_PREEMPTION
599923b511SScott Long #ifndef PREEMPTION
609923b511SScott Long #error "The FULL_PREEMPTION option requires the PREEMPTION option"
619923b511SScott Long #endif
629923b511SScott Long #endif
63dba6c5a6SPeter Wemm 
64d2ac2316SJake Burkholder CTASSERT((RQB_BPW * RQB_LEN) == RQ_NQS);
65d2ac2316SJake Burkholder 
666220dcbaSRobert Watson /*
676220dcbaSRobert Watson  * kern.sched.preemption allows user space to determine if preemption support
686220dcbaSRobert Watson  * is compiled in or not.  It is not currently a boot or runtime flag that
696220dcbaSRobert Watson  * can be changed.
706220dcbaSRobert Watson  */
716220dcbaSRobert Watson #ifdef PREEMPTION
726220dcbaSRobert Watson static int kern_sched_preemption = 1;
736220dcbaSRobert Watson #else
746220dcbaSRobert Watson static int kern_sched_preemption = 0;
756220dcbaSRobert Watson #endif
766220dcbaSRobert Watson SYSCTL_INT(_kern_sched, OID_AUTO, preemption, CTLFLAG_RD,
776220dcbaSRobert Watson     &kern_sched_preemption, 0, "Kernel preemption enabled");
786220dcbaSRobert Watson 
797b20fb19SJeff Roberson #ifdef SCHED_STATS
807b20fb19SJeff Roberson long switch_preempt;
817b20fb19SJeff Roberson long switch_owepreempt;
827b20fb19SJeff Roberson long switch_turnstile;
837b20fb19SJeff Roberson long switch_sleepq;
847b20fb19SJeff Roberson long switch_sleepqtimo;
857b20fb19SJeff Roberson long switch_relinquish;
867b20fb19SJeff Roberson long switch_needresched;
877b20fb19SJeff Roberson static SYSCTL_NODE(_kern_sched, OID_AUTO, stats, CTLFLAG_RW, 0, "switch stats");
887b20fb19SJeff Roberson SYSCTL_INT(_kern_sched_stats, OID_AUTO, preempt, CTLFLAG_RD, &switch_preempt, 0, "");
897b20fb19SJeff Roberson SYSCTL_INT(_kern_sched_stats, OID_AUTO, owepreempt, CTLFLAG_RD, &switch_owepreempt, 0, "");
907b20fb19SJeff Roberson SYSCTL_INT(_kern_sched_stats, OID_AUTO, turnstile, CTLFLAG_RD, &switch_turnstile, 0, "");
917b20fb19SJeff Roberson SYSCTL_INT(_kern_sched_stats, OID_AUTO, sleepq, CTLFLAG_RD, &switch_sleepq, 0, "");
927b20fb19SJeff Roberson SYSCTL_INT(_kern_sched_stats, OID_AUTO, sleepqtimo, CTLFLAG_RD, &switch_sleepqtimo, 0, "");
937b20fb19SJeff Roberson SYSCTL_INT(_kern_sched_stats, OID_AUTO, relinquish, CTLFLAG_RD, &switch_relinquish, 0, "");
947b20fb19SJeff Roberson SYSCTL_INT(_kern_sched_stats, OID_AUTO, needresched, CTLFLAG_RD, &switch_needresched, 0, "");
957b20fb19SJeff Roberson static int
967b20fb19SJeff Roberson sysctl_stats_reset(SYSCTL_HANDLER_ARGS)
977b20fb19SJeff Roberson {
987b20fb19SJeff Roberson         int error;
997b20fb19SJeff Roberson 	int val;
1007b20fb19SJeff Roberson 
1017b20fb19SJeff Roberson         val = 0;
1027b20fb19SJeff Roberson         error = sysctl_handle_int(oidp, &val, 0, req);
1037b20fb19SJeff Roberson         if (error != 0 || req->newptr == NULL)
1047b20fb19SJeff Roberson                 return (error);
1057b20fb19SJeff Roberson         if (val == 0)
1067b20fb19SJeff Roberson                 return (0);
1077b20fb19SJeff Roberson 	switch_preempt = 0;
1087b20fb19SJeff Roberson 	switch_owepreempt = 0;
1097b20fb19SJeff Roberson 	switch_turnstile = 0;
1107b20fb19SJeff Roberson 	switch_sleepq = 0;
1117b20fb19SJeff Roberson 	switch_sleepqtimo = 0;
1127b20fb19SJeff Roberson 	switch_relinquish = 0;
1137b20fb19SJeff Roberson 	switch_needresched = 0;
1147b20fb19SJeff Roberson 
1157b20fb19SJeff Roberson 	return (0);
1167b20fb19SJeff Roberson }
1177b20fb19SJeff Roberson 
1187b20fb19SJeff Roberson SYSCTL_PROC(_kern_sched_stats, OID_AUTO, reset, CTLTYPE_INT | CTLFLAG_WR, NULL,
1197b20fb19SJeff Roberson     0, sysctl_stats_reset, "I", "Reset scheduler statistics");
1207b20fb19SJeff Roberson #endif
1217b20fb19SJeff Roberson 
122e602ba25SJulian Elischer /************************************************************************
123e602ba25SJulian Elischer  * Functions that manipulate runnability from a thread perspective.	*
124e602ba25SJulian Elischer  ************************************************************************/
1258460a577SJohn Birrell /*
1268460a577SJohn Birrell  * Select the thread that will be run next.
1278460a577SJohn Birrell  */
128b40ce416SJulian Elischer struct thread *
129b40ce416SJulian Elischer choosethread(void)
130dba6c5a6SPeter Wemm {
131e602ba25SJulian Elischer 	struct thread *td;
132e602ba25SJulian Elischer 
133fe799533SAndrew Gallatin retry:
134f0393f06SJeff Roberson 	td = sched_choose();
13593a7aa79SJulian Elischer 
13693a7aa79SJulian Elischer 	/*
137faaa20f6SJulian Elischer 	 * If we are in panic, only allow system threads,
138faaa20f6SJulian Elischer 	 * plus the one we are running in, to be run.
13993a7aa79SJulian Elischer 	 */
140fe799533SAndrew Gallatin 	if (panicstr && ((td->td_proc->p_flag & P_SYSTEM) == 0 &&
141faaa20f6SJulian Elischer 	    (td->td_flags & TDF_INPANIC) == 0)) {
142faaa20f6SJulian Elischer 		/* note that it is no longer on the run queue */
143faaa20f6SJulian Elischer 		TD_SET_CAN_RUN(td);
144fe799533SAndrew Gallatin 		goto retry;
145faaa20f6SJulian Elischer 	}
14693a7aa79SJulian Elischer 
14771fad9fdSJulian Elischer 	TD_SET_RUNNING(td);
148e602ba25SJulian Elischer 	return (td);
149e602ba25SJulian Elischer }
150e602ba25SJulian Elischer 
1510c0b25aeSJohn Baldwin /*
1520c0b25aeSJohn Baldwin  * Kernel thread preemption implementation.  Critical sections mark
1530c0b25aeSJohn Baldwin  * regions of code in which preemptions are not allowed.
1540c0b25aeSJohn Baldwin  */
1557e1f6dfeSJohn Baldwin void
1567e1f6dfeSJohn Baldwin critical_enter(void)
1577e1f6dfeSJohn Baldwin {
1587e1f6dfeSJohn Baldwin 	struct thread *td;
1597e1f6dfeSJohn Baldwin 
1607e1f6dfeSJohn Baldwin 	td = curthread;
1617e1f6dfeSJohn Baldwin 	td->td_critnest++;
1621335c4dfSNate Lawson 	CTR4(KTR_CRITICAL, "critical_enter by thread %p (%ld, %s) to %d", td,
163431f8906SJulian Elischer 	    (long)td->td_proc->p_pid, td->td_name, td->td_critnest);
1647e1f6dfeSJohn Baldwin }
1657e1f6dfeSJohn Baldwin 
1667e1f6dfeSJohn Baldwin void
1677e1f6dfeSJohn Baldwin critical_exit(void)
1687e1f6dfeSJohn Baldwin {
1697e1f6dfeSJohn Baldwin 	struct thread *td;
1707e1f6dfeSJohn Baldwin 
1717e1f6dfeSJohn Baldwin 	td = curthread;
172b209e5e3SJeff Roberson 	KASSERT(td->td_critnest != 0,
173b209e5e3SJeff Roberson 	    ("critical_exit: td_critnest == 0"));
1745bce4ae3SJeff Roberson 
175d13ec713SStephan Uphoff 	if (td->td_critnest == 1) {
176d13ec713SStephan Uphoff 		td->td_critnest = 0;
17777918643SStephan Uphoff 		if (td->td_owepreempt) {
17877918643SStephan Uphoff 			td->td_critnest = 1;
1797b20fb19SJeff Roberson 			thread_lock(td);
18077918643SStephan Uphoff 			td->td_critnest--;
1817b20fb19SJeff Roberson 			SCHED_STAT_INC(switch_owepreempt);
182413ea6f5SJeff Roberson 			mi_switch(SW_INVOL|SW_PREEMPT, NULL);
1837b20fb19SJeff Roberson 			thread_unlock(td);
1840c0b25aeSJohn Baldwin 		}
185d13ec713SStephan Uphoff 	} else
1867e1f6dfeSJohn Baldwin 		td->td_critnest--;
187d13ec713SStephan Uphoff 
1881335c4dfSNate Lawson 	CTR4(KTR_CRITICAL, "critical_exit by thread %p (%ld, %s) to %d", td,
189431f8906SJulian Elischer 	    (long)td->td_proc->p_pid, td->td_name, td->td_critnest);
190d74ac681SMatthew Dillon }
1917e1f6dfeSJohn Baldwin 
192e602ba25SJulian Elischer /************************************************************************
193e602ba25SJulian Elischer  * SYSTEM RUN QUEUE manipulations and tests				*
194e602ba25SJulian Elischer  ************************************************************************/
195e602ba25SJulian Elischer /*
196e602ba25SJulian Elischer  * Initialize a run structure.
197e602ba25SJulian Elischer  */
198e602ba25SJulian Elischer void
199e602ba25SJulian Elischer runq_init(struct runq *rq)
200e602ba25SJulian Elischer {
201e602ba25SJulian Elischer 	int i;
202e602ba25SJulian Elischer 
203e602ba25SJulian Elischer 	bzero(rq, sizeof *rq);
204e602ba25SJulian Elischer 	for (i = 0; i < RQ_NQS; i++)
205e602ba25SJulian Elischer 		TAILQ_INIT(&rq->rq_queues[i]);
206e602ba25SJulian Elischer }
207e602ba25SJulian Elischer 
208d5a08a60SJake Burkholder /*
209d5a08a60SJake Burkholder  * Clear the status bit of the queue corresponding to priority level pri,
210d5a08a60SJake Burkholder  * indicating that it is empty.
211d5a08a60SJake Burkholder  */
212d5a08a60SJake Burkholder static __inline void
213d5a08a60SJake Burkholder runq_clrbit(struct runq *rq, int pri)
214d5a08a60SJake Burkholder {
215d5a08a60SJake Burkholder 	struct rqbits *rqb;
216d5a08a60SJake Burkholder 
217d5a08a60SJake Burkholder 	rqb = &rq->rq_status;
218d5a08a60SJake Burkholder 	CTR4(KTR_RUNQ, "runq_clrbit: bits=%#x %#x bit=%#x word=%d",
219d5a08a60SJake Burkholder 	    rqb->rqb_bits[RQB_WORD(pri)],
220d5a08a60SJake Burkholder 	    rqb->rqb_bits[RQB_WORD(pri)] & ~RQB_BIT(pri),
221d5a08a60SJake Burkholder 	    RQB_BIT(pri), RQB_WORD(pri));
222d5a08a60SJake Burkholder 	rqb->rqb_bits[RQB_WORD(pri)] &= ~RQB_BIT(pri);
223d5a08a60SJake Burkholder }
224d5a08a60SJake Burkholder 
225d5a08a60SJake Burkholder /*
226d5a08a60SJake Burkholder  * Find the index of the first non-empty run queue.  This is done by
227d5a08a60SJake Burkholder  * scanning the status bits, a set bit indicates a non-empty queue.
228d5a08a60SJake Burkholder  */
229d5a08a60SJake Burkholder static __inline int
230d5a08a60SJake Burkholder runq_findbit(struct runq *rq)
231d5a08a60SJake Burkholder {
232d5a08a60SJake Burkholder 	struct rqbits *rqb;
233d5a08a60SJake Burkholder 	int pri;
234d5a08a60SJake Burkholder 	int i;
235d5a08a60SJake Burkholder 
236d5a08a60SJake Burkholder 	rqb = &rq->rq_status;
237d5a08a60SJake Burkholder 	for (i = 0; i < RQB_LEN; i++)
238d5a08a60SJake Burkholder 		if (rqb->rqb_bits[i]) {
2392f9267ecSPeter Wemm 			pri = RQB_FFS(rqb->rqb_bits[i]) + (i << RQB_L2BPW);
240d5a08a60SJake Burkholder 			CTR3(KTR_RUNQ, "runq_findbit: bits=%#x i=%d pri=%d",
241d5a08a60SJake Burkholder 			    rqb->rqb_bits[i], i, pri);
242d5a08a60SJake Burkholder 			return (pri);
243d5a08a60SJake Burkholder 		}
244d5a08a60SJake Burkholder 
245d5a08a60SJake Burkholder 	return (-1);
246d5a08a60SJake Burkholder }
247d5a08a60SJake Burkholder 
2483fed7d23SJeff Roberson static __inline int
24967e20930SJeff Roberson runq_findbit_from(struct runq *rq, u_char pri)
2503fed7d23SJeff Roberson {
2513fed7d23SJeff Roberson 	struct rqbits *rqb;
25267e20930SJeff Roberson 	rqb_word_t mask;
2533fed7d23SJeff Roberson 	int i;
2543fed7d23SJeff Roberson 
25567e20930SJeff Roberson 	/*
25667e20930SJeff Roberson 	 * Set the mask for the first word so we ignore priorities before 'pri'.
25767e20930SJeff Roberson 	 */
25867e20930SJeff Roberson 	mask = (rqb_word_t)-1 << (pri & (RQB_BPW - 1));
2593fed7d23SJeff Roberson 	rqb = &rq->rq_status;
2603fed7d23SJeff Roberson again:
26167e20930SJeff Roberson 	for (i = RQB_WORD(pri); i < RQB_LEN; mask = -1, i++) {
26267e20930SJeff Roberson 		mask = rqb->rqb_bits[i] & mask;
26367e20930SJeff Roberson 		if (mask == 0)
2643fed7d23SJeff Roberson 			continue;
26567e20930SJeff Roberson 		pri = RQB_FFS(mask) + (i << RQB_L2BPW);
2663fed7d23SJeff Roberson 		CTR3(KTR_RUNQ, "runq_findbit_from: bits=%#x i=%d pri=%d",
26767e20930SJeff Roberson 		    mask, i, pri);
2683fed7d23SJeff Roberson 		return (pri);
2693fed7d23SJeff Roberson 	}
27067e20930SJeff Roberson 	if (pri == 0)
2713fed7d23SJeff Roberson 		return (-1);
27267e20930SJeff Roberson 	/*
27367e20930SJeff Roberson 	 * Wrap back around to the beginning of the list just once so we
27467e20930SJeff Roberson 	 * scan the whole thing.
27567e20930SJeff Roberson 	 */
27667e20930SJeff Roberson 	pri = 0;
27767e20930SJeff Roberson 	goto again;
2783fed7d23SJeff Roberson }
2793fed7d23SJeff Roberson 
280d5a08a60SJake Burkholder /*
281d5a08a60SJake Burkholder  * Set the status bit of the queue corresponding to priority level pri,
282d5a08a60SJake Burkholder  * indicating that it is non-empty.
283d5a08a60SJake Burkholder  */
284d5a08a60SJake Burkholder static __inline void
285d5a08a60SJake Burkholder runq_setbit(struct runq *rq, int pri)
286d5a08a60SJake Burkholder {
287d5a08a60SJake Burkholder 	struct rqbits *rqb;
288d5a08a60SJake Burkholder 
289d5a08a60SJake Burkholder 	rqb = &rq->rq_status;
290d5a08a60SJake Burkholder 	CTR4(KTR_RUNQ, "runq_setbit: bits=%#x %#x bit=%#x word=%d",
291d5a08a60SJake Burkholder 	    rqb->rqb_bits[RQB_WORD(pri)],
292d5a08a60SJake Burkholder 	    rqb->rqb_bits[RQB_WORD(pri)] | RQB_BIT(pri),
293d5a08a60SJake Burkholder 	    RQB_BIT(pri), RQB_WORD(pri));
294d5a08a60SJake Burkholder 	rqb->rqb_bits[RQB_WORD(pri)] |= RQB_BIT(pri);
295d5a08a60SJake Burkholder }
296d5a08a60SJake Burkholder 
297d5a08a60SJake Burkholder /*
298ad1e7d28SJulian Elischer  * Add the thread to the queue specified by its priority, and set the
299d5a08a60SJake Burkholder  * corresponding status bit.
300d5a08a60SJake Burkholder  */
301d5a08a60SJake Burkholder void
302ad1e7d28SJulian Elischer runq_add(struct runq *rq, struct td_sched *ts, int flags)
303d5a08a60SJake Burkholder {
304d5a08a60SJake Burkholder 	struct rqhead *rqh;
305d5a08a60SJake Burkholder 	int pri;
306dba6c5a6SPeter Wemm 
307ad1e7d28SJulian Elischer 	pri = ts->ts_thread->td_priority / RQ_PPQ;
308ad1e7d28SJulian Elischer 	ts->ts_rqindex = pri;
309d5a08a60SJake Burkholder 	runq_setbit(rq, pri);
310d5a08a60SJake Burkholder 	rqh = &rq->rq_queues[pri];
311ad1e7d28SJulian Elischer 	CTR5(KTR_RUNQ, "runq_add: td=%p ts=%p pri=%d %d rqh=%p",
312ad1e7d28SJulian Elischer 	    ts->ts_thread, ts, ts->ts_thread->td_priority, pri, rqh);
313c20c691bSJulian Elischer 	if (flags & SRQ_PREEMPTED) {
314ad1e7d28SJulian Elischer 		TAILQ_INSERT_HEAD(rqh, ts, ts_procq);
315c20c691bSJulian Elischer 	} else {
316ad1e7d28SJulian Elischer 		TAILQ_INSERT_TAIL(rqh, ts, ts_procq);
317dba6c5a6SPeter Wemm 	}
318c20c691bSJulian Elischer }
319d5a08a60SJake Burkholder 
3203fed7d23SJeff Roberson void
321ed0e8f2fSJeff Roberson runq_add_pri(struct runq *rq, struct td_sched *ts, u_char pri, int flags)
3223fed7d23SJeff Roberson {
3233fed7d23SJeff Roberson 	struct rqhead *rqh;
3243fed7d23SJeff Roberson 
3253fed7d23SJeff Roberson 	KASSERT(pri < RQ_NQS, ("runq_add_pri: %d out of range", pri));
3263fed7d23SJeff Roberson 	ts->ts_rqindex = pri;
3273fed7d23SJeff Roberson 	runq_setbit(rq, pri);
3283fed7d23SJeff Roberson 	rqh = &rq->rq_queues[pri];
3293fed7d23SJeff Roberson 	CTR5(KTR_RUNQ, "runq_add_pri: td=%p ke=%p pri=%d idx=%d rqh=%p",
3303fed7d23SJeff Roberson 	    ts->ts_thread, ts, ts->ts_thread->td_priority, pri, rqh);
3313fed7d23SJeff Roberson 	if (flags & SRQ_PREEMPTED) {
3323fed7d23SJeff Roberson 		TAILQ_INSERT_HEAD(rqh, ts, ts_procq);
3333fed7d23SJeff Roberson 	} else {
3343fed7d23SJeff Roberson 		TAILQ_INSERT_TAIL(rqh, ts, ts_procq);
3353fed7d23SJeff Roberson 	}
3363fed7d23SJeff Roberson }
337d5a08a60SJake Burkholder /*
338d5a08a60SJake Burkholder  * Return true if there are runnable processes of any priority on the run
339d5a08a60SJake Burkholder  * queue, false otherwise.  Has no side effects, does not modify the run
340d5a08a60SJake Burkholder  * queue structure.
341d5a08a60SJake Burkholder  */
342d5a08a60SJake Burkholder int
343d5a08a60SJake Burkholder runq_check(struct runq *rq)
344d5a08a60SJake Burkholder {
345d5a08a60SJake Burkholder 	struct rqbits *rqb;
346d5a08a60SJake Burkholder 	int i;
347d5a08a60SJake Burkholder 
348d5a08a60SJake Burkholder 	rqb = &rq->rq_status;
349d5a08a60SJake Burkholder 	for (i = 0; i < RQB_LEN; i++)
350d5a08a60SJake Burkholder 		if (rqb->rqb_bits[i]) {
351d5a08a60SJake Burkholder 			CTR2(KTR_RUNQ, "runq_check: bits=%#x i=%d",
352d5a08a60SJake Burkholder 			    rqb->rqb_bits[i], i);
353d5a08a60SJake Burkholder 			return (1);
354dba6c5a6SPeter Wemm 		}
355d5a08a60SJake Burkholder 	CTR0(KTR_RUNQ, "runq_check: empty");
356d5a08a60SJake Burkholder 
357d5a08a60SJake Burkholder 	return (0);
358dba6c5a6SPeter Wemm }
359d5a08a60SJake Burkholder 
360a90f3f25SJeff Roberson /*
361a90f3f25SJeff Roberson  * Find the highest priority process on the run queue.
362a90f3f25SJeff Roberson  */
363a90f3f25SJeff Roberson struct td_sched *
364a90f3f25SJeff Roberson runq_choose_fuzz(struct runq *rq, int fuzz)
365a90f3f25SJeff Roberson {
366a90f3f25SJeff Roberson 	struct rqhead *rqh;
367a90f3f25SJeff Roberson 	struct td_sched *ts;
368a90f3f25SJeff Roberson 	int pri;
369a90f3f25SJeff Roberson 
370a90f3f25SJeff Roberson 	while ((pri = runq_findbit(rq)) != -1) {
371a90f3f25SJeff Roberson 		rqh = &rq->rq_queues[pri];
372a90f3f25SJeff Roberson 		/* fuzz == 1 is normal.. 0 or less are ignored */
373a90f3f25SJeff Roberson 		if (fuzz > 1) {
374a90f3f25SJeff Roberson 			/*
375a90f3f25SJeff Roberson 			 * In the first couple of entries, check if
376a90f3f25SJeff Roberson 			 * there is one for our CPU as a preference.
377a90f3f25SJeff Roberson 			 */
378a90f3f25SJeff Roberson 			int count = fuzz;
379a90f3f25SJeff Roberson 			int cpu = PCPU_GET(cpuid);
380a90f3f25SJeff Roberson 			struct td_sched *ts2;
381a90f3f25SJeff Roberson 			ts2 = ts = TAILQ_FIRST(rqh);
382a90f3f25SJeff Roberson 
383a90f3f25SJeff Roberson 			while (count-- && ts2) {
384a90f3f25SJeff Roberson 				if (ts->ts_thread->td_lastcpu == cpu) {
385a90f3f25SJeff Roberson 					ts = ts2;
386a90f3f25SJeff Roberson 					break;
387a90f3f25SJeff Roberson 				}
388a90f3f25SJeff Roberson 				ts2 = TAILQ_NEXT(ts2, ts_procq);
389a90f3f25SJeff Roberson 			}
390a90f3f25SJeff Roberson 		} else
391a90f3f25SJeff Roberson 			ts = TAILQ_FIRST(rqh);
392a90f3f25SJeff Roberson 		KASSERT(ts != NULL, ("runq_choose_fuzz: no proc on busy queue"));
393a90f3f25SJeff Roberson 		CTR3(KTR_RUNQ,
394a90f3f25SJeff Roberson 		    "runq_choose_fuzz: pri=%d td_sched=%p rqh=%p", pri, ts, rqh);
395a90f3f25SJeff Roberson 		return (ts);
396a90f3f25SJeff Roberson 	}
397a90f3f25SJeff Roberson 	CTR1(KTR_RUNQ, "runq_choose_fuzz: idleproc pri=%d", pri);
398a90f3f25SJeff Roberson 
399a90f3f25SJeff Roberson 	return (NULL);
400a90f3f25SJeff Roberson }
4016804a3abSJulian Elischer 
402d5a08a60SJake Burkholder /*
403b43179fbSJeff Roberson  * Find the highest priority process on the run queue.
404d5a08a60SJake Burkholder  */
405ad1e7d28SJulian Elischer struct td_sched *
406d5a08a60SJake Burkholder runq_choose(struct runq *rq)
407d5a08a60SJake Burkholder {
408d5a08a60SJake Burkholder 	struct rqhead *rqh;
409ad1e7d28SJulian Elischer 	struct td_sched *ts;
410d5a08a60SJake Burkholder 	int pri;
411d5a08a60SJake Burkholder 
412e602ba25SJulian Elischer 	while ((pri = runq_findbit(rq)) != -1) {
413d5a08a60SJake Burkholder 		rqh = &rq->rq_queues[pri];
414ad1e7d28SJulian Elischer 		ts = TAILQ_FIRST(rqh);
415ad1e7d28SJulian Elischer 		KASSERT(ts != NULL, ("runq_choose: no proc on busy queue"));
416e602ba25SJulian Elischer 		CTR3(KTR_RUNQ,
417ad1e7d28SJulian Elischer 		    "runq_choose: pri=%d td_sched=%p rqh=%p", pri, ts, rqh);
418ad1e7d28SJulian Elischer 		return (ts);
419d5a08a60SJake Burkholder 	}
420d5a08a60SJake Burkholder 	CTR1(KTR_RUNQ, "runq_choose: idleproc pri=%d", pri);
421d5a08a60SJake Burkholder 
422e602ba25SJulian Elischer 	return (NULL);
423d5a08a60SJake Burkholder }
424d5a08a60SJake Burkholder 
4253fed7d23SJeff Roberson struct td_sched *
426ed0e8f2fSJeff Roberson runq_choose_from(struct runq *rq, u_char idx)
4273fed7d23SJeff Roberson {
4283fed7d23SJeff Roberson 	struct rqhead *rqh;
4293fed7d23SJeff Roberson 	struct td_sched *ts;
4303fed7d23SJeff Roberson 	int pri;
4313fed7d23SJeff Roberson 
432cd49bb70SJeff Roberson 	if ((pri = runq_findbit_from(rq, idx)) != -1) {
4333fed7d23SJeff Roberson 		rqh = &rq->rq_queues[pri];
4343fed7d23SJeff Roberson 		ts = TAILQ_FIRST(rqh);
4353fed7d23SJeff Roberson 		KASSERT(ts != NULL, ("runq_choose: no proc on busy queue"));
4363fed7d23SJeff Roberson 		CTR4(KTR_RUNQ,
4376617724cSJeff Roberson 		    "runq_choose_from: pri=%d td_sched=%p idx=%d rqh=%p",
4383fed7d23SJeff Roberson 		    pri, ts, ts->ts_rqindex, rqh);
4393fed7d23SJeff Roberson 		return (ts);
4403fed7d23SJeff Roberson 	}
4413fed7d23SJeff Roberson 	CTR1(KTR_RUNQ, "runq_choose_from: idleproc pri=%d", pri);
4423fed7d23SJeff Roberson 
4433fed7d23SJeff Roberson 	return (NULL);
4443fed7d23SJeff Roberson }
445d5a08a60SJake Burkholder /*
446ad1e7d28SJulian Elischer  * Remove the thread from the queue specified by its priority, and clear the
447d5a08a60SJake Burkholder  * corresponding status bit if the queue becomes empty.
448f0393f06SJeff Roberson  * Caller must set state afterwards.
449d5a08a60SJake Burkholder  */
450d5a08a60SJake Burkholder void
451ad1e7d28SJulian Elischer runq_remove(struct runq *rq, struct td_sched *ts)
452d5a08a60SJake Burkholder {
4533fed7d23SJeff Roberson 
4543fed7d23SJeff Roberson 	runq_remove_idx(rq, ts, NULL);
4553fed7d23SJeff Roberson }
4563fed7d23SJeff Roberson 
4573fed7d23SJeff Roberson void
458ed0e8f2fSJeff Roberson runq_remove_idx(struct runq *rq, struct td_sched *ts, u_char *idx)
4593fed7d23SJeff Roberson {
460d5a08a60SJake Burkholder 	struct rqhead *rqh;
461ed0e8f2fSJeff Roberson 	u_char pri;
462d5a08a60SJake Burkholder 
463b61ce5b0SJeff Roberson 	KASSERT(ts->ts_thread->td_flags & TDF_INMEM,
464b61ce5b0SJeff Roberson 		("runq_remove_idx: thread swapped out"));
465ad1e7d28SJulian Elischer 	pri = ts->ts_rqindex;
4667b20fb19SJeff Roberson 	KASSERT(pri < RQ_NQS, ("runq_remove_idx: Invalid index %d\n", pri));
467d5a08a60SJake Burkholder 	rqh = &rq->rq_queues[pri];
4683fed7d23SJeff Roberson 	CTR5(KTR_RUNQ, "runq_remove_idx: td=%p, ts=%p pri=%d %d rqh=%p",
469ad1e7d28SJulian Elischer 	    ts->ts_thread, ts, ts->ts_thread->td_priority, pri, rqh);
4707b20fb19SJeff Roberson 	{
4717b20fb19SJeff Roberson 		struct td_sched *nts;
4727b20fb19SJeff Roberson 
4737b20fb19SJeff Roberson 		TAILQ_FOREACH(nts, rqh, ts_procq)
4747b20fb19SJeff Roberson 			if (nts == ts)
4757b20fb19SJeff Roberson 				break;
4767b20fb19SJeff Roberson 		if (ts != nts)
4777b20fb19SJeff Roberson 			panic("runq_remove_idx: ts %p not on rqindex %d",
4787b20fb19SJeff Roberson 			    ts, pri);
4797b20fb19SJeff Roberson 	}
480ad1e7d28SJulian Elischer 	TAILQ_REMOVE(rqh, ts, ts_procq);
481d5a08a60SJake Burkholder 	if (TAILQ_EMPTY(rqh)) {
4823fed7d23SJeff Roberson 		CTR0(KTR_RUNQ, "runq_remove_idx: empty");
483d5a08a60SJake Burkholder 		runq_clrbit(rq, pri);
4843fed7d23SJeff Roberson 		if (idx != NULL && *idx == pri)
4853fed7d23SJeff Roberson 			*idx = (pri + 1) % RQ_NQS;
486d5a08a60SJake Burkholder 	}
487dba6c5a6SPeter Wemm }
488e602ba25SJulian Elischer 
489ed062c8dSJulian Elischer /****** functions that are temporarily here ***********/
490ed062c8dSJulian Elischer #include <vm/uma.h>
491ed062c8dSJulian Elischer 
492ed062c8dSJulian Elischer /*
493ed062c8dSJulian Elischer  *  Allocate scheduler specific per-process resources.
494ad1e7d28SJulian Elischer  * The thread and proc have already been linked in.
495ed062c8dSJulian Elischer  *
496ed062c8dSJulian Elischer  * Called from:
497ed062c8dSJulian Elischer  *  proc_init() (UMA init method)
498ed062c8dSJulian Elischer  */
499ed062c8dSJulian Elischer void
500ad1e7d28SJulian Elischer sched_newproc(struct proc *p, struct thread *td)
501ed062c8dSJulian Elischer {
502ed062c8dSJulian Elischer }
503ed062c8dSJulian Elischer 
504ed062c8dSJulian Elischer /*
505ed062c8dSJulian Elischer  * thread is being either created or recycled.
506ed062c8dSJulian Elischer  * Fix up the per-scheduler resources associated with it.
507ed062c8dSJulian Elischer  * Called from:
508ed062c8dSJulian Elischer  *  sched_fork_thread()
509ed062c8dSJulian Elischer  *  thread_dtor()  (*may go away)
510ed062c8dSJulian Elischer  *  thread_init()  (*may go away)
511ed062c8dSJulian Elischer  */
512ed062c8dSJulian Elischer void
513ed062c8dSJulian Elischer sched_newthread(struct thread *td)
514ed062c8dSJulian Elischer {
515ad1e7d28SJulian Elischer 	struct td_sched *ts;
516ed062c8dSJulian Elischer 
517ad1e7d28SJulian Elischer 	ts = (struct td_sched *) (td + 1);
518ad1e7d28SJulian Elischer 	bzero(ts, sizeof(*ts));
519ad1e7d28SJulian Elischer 	td->td_sched     = ts;
520ad1e7d28SJulian Elischer 	ts->ts_thread	= td;
521ed062c8dSJulian Elischer }
522ed062c8dSJulian Elischer 
523ed062c8dSJulian Elischer #endif /* KERN_SWITCH_INCLUDE */
524