xref: /freebsd/sys/kern/kern_switch.c (revision d2ac231616f04bd63795021f23d324351a24788b)
1dba6c5a6SPeter Wemm /*
2d5a08a60SJake Burkholder  * Copyright (c) 2001 Jake Burkholder <jake@FreeBSD.org>
3d5a08a60SJake Burkholder  * All rights reserved.
4dba6c5a6SPeter Wemm  *
5dba6c5a6SPeter Wemm  * Redistribution and use in source and binary forms, with or without
6dba6c5a6SPeter Wemm  * modification, are permitted provided that the following conditions
7dba6c5a6SPeter Wemm  * are met:
8dba6c5a6SPeter Wemm  * 1. Redistributions of source code must retain the above copyright
9dba6c5a6SPeter Wemm  *    notice, this list of conditions and the following disclaimer.
10dba6c5a6SPeter Wemm  * 2. Redistributions in binary form must reproduce the above copyright
11dba6c5a6SPeter Wemm  *    notice, this list of conditions and the following disclaimer in the
12dba6c5a6SPeter Wemm  *    documentation and/or other materials provided with the distribution.
13dba6c5a6SPeter Wemm  *
14dba6c5a6SPeter Wemm  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15dba6c5a6SPeter Wemm  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16dba6c5a6SPeter Wemm  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17dba6c5a6SPeter Wemm  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18dba6c5a6SPeter Wemm  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19dba6c5a6SPeter Wemm  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20dba6c5a6SPeter Wemm  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21dba6c5a6SPeter Wemm  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22dba6c5a6SPeter Wemm  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23dba6c5a6SPeter Wemm  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24dba6c5a6SPeter Wemm  * SUCH DAMAGE.
25dba6c5a6SPeter Wemm  *
26dba6c5a6SPeter Wemm  * $FreeBSD$
27dba6c5a6SPeter Wemm  */
28dba6c5a6SPeter Wemm 
29dba6c5a6SPeter Wemm #include <sys/param.h>
30dba6c5a6SPeter Wemm #include <sys/systm.h>
31dba6c5a6SPeter Wemm #include <sys/kernel.h>
320384fff8SJason Evans #include <sys/ktr.h>
33f34fa851SJohn Baldwin #include <sys/lock.h>
3435e0e5b3SJohn Baldwin #include <sys/mutex.h>
35dba6c5a6SPeter Wemm #include <sys/proc.h>
36dba6c5a6SPeter Wemm #include <sys/queue.h>
37182da820SMatthew Dillon #include <machine/critical.h>
38dba6c5a6SPeter Wemm 
39d2ac2316SJake Burkholder CTASSERT((RQB_BPW * RQB_LEN) == RQ_NQS);
40d2ac2316SJake Burkholder 
41dba6c5a6SPeter Wemm /*
42d5a08a60SJake Burkholder  * Global run queue.
43dba6c5a6SPeter Wemm  */
44d5a08a60SJake Burkholder static struct runq runq;
45d5a08a60SJake Burkholder SYSINIT(runq, SI_SUB_RUN_QUEUE, SI_ORDER_FIRST, runq_init, &runq)
46dba6c5a6SPeter Wemm 
47dba6c5a6SPeter Wemm /*
48d5a08a60SJake Burkholder  * Wrappers which implement old interface; act on global run queue.
49dba6c5a6SPeter Wemm  */
50dba6c5a6SPeter Wemm 
51b40ce416SJulian Elischer struct thread *
52b40ce416SJulian Elischer choosethread(void)
53dba6c5a6SPeter Wemm {
54b40ce416SJulian Elischer 	return (runq_choose(&runq)->ke_thread);
55d5a08a60SJake Burkholder }
56d5a08a60SJake Burkholder 
57d5a08a60SJake Burkholder int
58d5a08a60SJake Burkholder procrunnable(void)
59d5a08a60SJake Burkholder {
60d5a08a60SJake Burkholder 	return runq_check(&runq);
61d5a08a60SJake Burkholder }
62d5a08a60SJake Burkholder 
63d5a08a60SJake Burkholder void
64b40ce416SJulian Elischer remrunqueue(struct thread *td)
65d5a08a60SJake Burkholder {
66b40ce416SJulian Elischer 	runq_remove(&runq, td->td_kse);
67d5a08a60SJake Burkholder }
68d5a08a60SJake Burkholder 
69d5a08a60SJake Burkholder void
70b40ce416SJulian Elischer setrunqueue(struct thread *td)
71d5a08a60SJake Burkholder {
72b40ce416SJulian Elischer 	runq_add(&runq, td->td_kse);
73d5a08a60SJake Burkholder }
74d5a08a60SJake Burkholder 
757e1f6dfeSJohn Baldwin /* Critical sections that prevent preemption. */
767e1f6dfeSJohn Baldwin void
777e1f6dfeSJohn Baldwin critical_enter(void)
787e1f6dfeSJohn Baldwin {
797e1f6dfeSJohn Baldwin 	struct thread *td;
807e1f6dfeSJohn Baldwin 
817e1f6dfeSJohn Baldwin 	td = curthread;
827e1f6dfeSJohn Baldwin 	if (td->td_critnest == 0)
83d74ac681SMatthew Dillon 		cpu_critical_enter();
847e1f6dfeSJohn Baldwin 	td->td_critnest++;
857e1f6dfeSJohn Baldwin }
867e1f6dfeSJohn Baldwin 
877e1f6dfeSJohn Baldwin void
887e1f6dfeSJohn Baldwin critical_exit(void)
897e1f6dfeSJohn Baldwin {
907e1f6dfeSJohn Baldwin 	struct thread *td;
917e1f6dfeSJohn Baldwin 
927e1f6dfeSJohn Baldwin 	td = curthread;
937e1f6dfeSJohn Baldwin 	if (td->td_critnest == 1) {
947e1f6dfeSJohn Baldwin 		td->td_critnest = 0;
95d74ac681SMatthew Dillon 		cpu_critical_exit();
96d74ac681SMatthew Dillon 	} else {
977e1f6dfeSJohn Baldwin 		td->td_critnest--;
987e1f6dfeSJohn Baldwin 	}
99d74ac681SMatthew Dillon }
1007e1f6dfeSJohn Baldwin 
101d5a08a60SJake Burkholder /*
102d5a08a60SJake Burkholder  * Clear the status bit of the queue corresponding to priority level pri,
103d5a08a60SJake Burkholder  * indicating that it is empty.
104d5a08a60SJake Burkholder  */
105d5a08a60SJake Burkholder static __inline void
106d5a08a60SJake Burkholder runq_clrbit(struct runq *rq, int pri)
107d5a08a60SJake Burkholder {
108d5a08a60SJake Burkholder 	struct rqbits *rqb;
109d5a08a60SJake Burkholder 
110d5a08a60SJake Burkholder 	rqb = &rq->rq_status;
111d5a08a60SJake Burkholder 	CTR4(KTR_RUNQ, "runq_clrbit: bits=%#x %#x bit=%#x word=%d",
112d5a08a60SJake Burkholder 	    rqb->rqb_bits[RQB_WORD(pri)],
113d5a08a60SJake Burkholder 	    rqb->rqb_bits[RQB_WORD(pri)] & ~RQB_BIT(pri),
114d5a08a60SJake Burkholder 	    RQB_BIT(pri), RQB_WORD(pri));
115d5a08a60SJake Burkholder 	rqb->rqb_bits[RQB_WORD(pri)] &= ~RQB_BIT(pri);
116d5a08a60SJake Burkholder }
117d5a08a60SJake Burkholder 
118d5a08a60SJake Burkholder /*
119d5a08a60SJake Burkholder  * Find the index of the first non-empty run queue.  This is done by
120d5a08a60SJake Burkholder  * scanning the status bits, a set bit indicates a non-empty queue.
121d5a08a60SJake Burkholder  */
122d5a08a60SJake Burkholder static __inline int
123d5a08a60SJake Burkholder runq_findbit(struct runq *rq)
124d5a08a60SJake Burkholder {
125d5a08a60SJake Burkholder 	struct rqbits *rqb;
126d5a08a60SJake Burkholder 	int pri;
127d5a08a60SJake Burkholder 	int i;
128d5a08a60SJake Burkholder 
129d5a08a60SJake Burkholder 	rqb = &rq->rq_status;
130d5a08a60SJake Burkholder 	for (i = 0; i < RQB_LEN; i++)
131d5a08a60SJake Burkholder 		if (rqb->rqb_bits[i]) {
132d5a08a60SJake Burkholder 			pri = (RQB_FFS(rqb->rqb_bits[i]) - 1) +
133d5a08a60SJake Burkholder 			    (i << RQB_L2BPW);
134d5a08a60SJake Burkholder 			CTR3(KTR_RUNQ, "runq_findbit: bits=%#x i=%d pri=%d",
135d5a08a60SJake Burkholder 			    rqb->rqb_bits[i], i, pri);
136d5a08a60SJake Burkholder 			return (pri);
137d5a08a60SJake Burkholder 		}
138d5a08a60SJake Burkholder 
139d5a08a60SJake Burkholder 	return (-1);
140d5a08a60SJake Burkholder }
141d5a08a60SJake Burkholder 
142d5a08a60SJake Burkholder /*
143d5a08a60SJake Burkholder  * Set the status bit of the queue corresponding to priority level pri,
144d5a08a60SJake Burkholder  * indicating that it is non-empty.
145d5a08a60SJake Burkholder  */
146d5a08a60SJake Burkholder static __inline void
147d5a08a60SJake Burkholder runq_setbit(struct runq *rq, int pri)
148d5a08a60SJake Burkholder {
149d5a08a60SJake Burkholder 	struct rqbits *rqb;
150d5a08a60SJake Burkholder 
151d5a08a60SJake Burkholder 	rqb = &rq->rq_status;
152d5a08a60SJake Burkholder 	CTR4(KTR_RUNQ, "runq_setbit: bits=%#x %#x bit=%#x word=%d",
153d5a08a60SJake Burkholder 	    rqb->rqb_bits[RQB_WORD(pri)],
154d5a08a60SJake Burkholder 	    rqb->rqb_bits[RQB_WORD(pri)] | RQB_BIT(pri),
155d5a08a60SJake Burkholder 	    RQB_BIT(pri), RQB_WORD(pri));
156d5a08a60SJake Burkholder 	rqb->rqb_bits[RQB_WORD(pri)] |= RQB_BIT(pri);
157d5a08a60SJake Burkholder }
158d5a08a60SJake Burkholder 
159d5a08a60SJake Burkholder /*
160d5a08a60SJake Burkholder  * Add the process to the queue specified by its priority, and set the
161d5a08a60SJake Burkholder  * corresponding status bit.
162d5a08a60SJake Burkholder  */
163d5a08a60SJake Burkholder void
164b40ce416SJulian Elischer runq_add(struct runq *rq, struct kse *ke)
165d5a08a60SJake Burkholder {
166d5a08a60SJake Burkholder 	struct rqhead *rqh;
167d5a08a60SJake Burkholder 	int pri;
168dba6c5a6SPeter Wemm 
169b40ce416SJulian Elischer #ifdef INVARIANTS
170b40ce416SJulian Elischer 	struct proc *p = ke->ke_proc;
171b40ce416SJulian Elischer #endif
172b40ce416SJulian Elischer 	if (ke->ke_flags & KEF_ONRUNQ)
173b40ce416SJulian Elischer 		return;
1740384fff8SJason Evans 	mtx_assert(&sched_lock, MA_OWNED);
175d5a08a60SJake Burkholder 	KASSERT(p->p_stat == SRUN, ("runq_add: proc %p (%s) not SRUN",
176d5a08a60SJake Burkholder 	    p, p->p_comm));
1772c100766SJulian Elischer 	pri = ke->ke_thread->td_priority / RQ_PPQ;
178b40ce416SJulian Elischer 	ke->ke_rqindex = pri;
179d5a08a60SJake Burkholder 	runq_setbit(rq, pri);
180d5a08a60SJake Burkholder 	rqh = &rq->rq_queues[pri];
181d5a08a60SJake Burkholder 	CTR4(KTR_RUNQ, "runq_add: p=%p pri=%d %d rqh=%p",
1822c100766SJulian Elischer 	    ke->ke_proc, ke->ke_thread->td_priority, pri, rqh);
183b40ce416SJulian Elischer 	TAILQ_INSERT_TAIL(rqh, ke, ke_procq);
184b40ce416SJulian Elischer 	ke->ke_flags |= KEF_ONRUNQ;
185dba6c5a6SPeter Wemm }
186d5a08a60SJake Burkholder 
187d5a08a60SJake Burkholder /*
188d5a08a60SJake Burkholder  * Return true if there are runnable processes of any priority on the run
189d5a08a60SJake Burkholder  * queue, false otherwise.  Has no side effects, does not modify the run
190d5a08a60SJake Burkholder  * queue structure.
191d5a08a60SJake Burkholder  */
192d5a08a60SJake Burkholder int
193d5a08a60SJake Burkholder runq_check(struct runq *rq)
194d5a08a60SJake Burkholder {
195d5a08a60SJake Burkholder 	struct rqbits *rqb;
196d5a08a60SJake Burkholder 	int i;
197d5a08a60SJake Burkholder 
198d5a08a60SJake Burkholder 	rqb = &rq->rq_status;
199d5a08a60SJake Burkholder 	for (i = 0; i < RQB_LEN; i++)
200d5a08a60SJake Burkholder 		if (rqb->rqb_bits[i]) {
201d5a08a60SJake Burkholder 			CTR2(KTR_RUNQ, "runq_check: bits=%#x i=%d",
202d5a08a60SJake Burkholder 			    rqb->rqb_bits[i], i);
203d5a08a60SJake Burkholder 			return (1);
204dba6c5a6SPeter Wemm 		}
205d5a08a60SJake Burkholder 	CTR0(KTR_RUNQ, "runq_check: empty");
206d5a08a60SJake Burkholder 
207d5a08a60SJake Burkholder 	return (0);
208dba6c5a6SPeter Wemm }
209d5a08a60SJake Burkholder 
210d5a08a60SJake Burkholder /*
211d5a08a60SJake Burkholder  * Find and remove the highest priority process from the run queue.
212d5a08a60SJake Burkholder  * If there are no runnable processes, the per-cpu idle process is
213d5a08a60SJake Burkholder  * returned.  Will not return NULL under any circumstances.
214d5a08a60SJake Burkholder  */
215b40ce416SJulian Elischer struct kse *
216d5a08a60SJake Burkholder runq_choose(struct runq *rq)
217d5a08a60SJake Burkholder {
218d5a08a60SJake Burkholder 	struct rqhead *rqh;
219b40ce416SJulian Elischer 	struct kse *ke;
220d5a08a60SJake Burkholder 	int pri;
221d5a08a60SJake Burkholder 
222d5a08a60SJake Burkholder 	mtx_assert(&sched_lock, MA_OWNED);
223d5a08a60SJake Burkholder 	if ((pri = runq_findbit(rq)) != -1) {
224d5a08a60SJake Burkholder 		rqh = &rq->rq_queues[pri];
225b40ce416SJulian Elischer 		ke = TAILQ_FIRST(rqh);
226b40ce416SJulian Elischer 		KASSERT(ke != NULL, ("runq_choose: no proc on busy queue"));
227b40ce416SJulian Elischer 		KASSERT(ke->ke_proc->p_stat == SRUN,
228b40ce416SJulian Elischer 		    ("runq_choose: process %d(%s) in state %d", ke->ke_proc->p_pid,
229b40ce416SJulian Elischer 		    ke->ke_proc->p_comm, ke->ke_proc->p_stat));
230b40ce416SJulian Elischer 		CTR3(KTR_RUNQ, "runq_choose: pri=%d kse=%p rqh=%p", pri, ke, rqh);
231b40ce416SJulian Elischer 		TAILQ_REMOVE(rqh, ke, ke_procq);
232d5a08a60SJake Burkholder 		if (TAILQ_EMPTY(rqh)) {
233d5a08a60SJake Burkholder 			CTR0(KTR_RUNQ, "runq_choose: empty");
234d5a08a60SJake Burkholder 			runq_clrbit(rq, pri);
235d5a08a60SJake Burkholder 		}
236b40ce416SJulian Elischer 		ke->ke_flags &= ~KEF_ONRUNQ;
237b40ce416SJulian Elischer 		return (ke);
238d5a08a60SJake Burkholder 	}
239d5a08a60SJake Burkholder 	CTR1(KTR_RUNQ, "runq_choose: idleproc pri=%d", pri);
240d5a08a60SJake Burkholder 
241b40ce416SJulian Elischer 	return (PCPU_GET(idlethread)->td_kse);
242d5a08a60SJake Burkholder }
243d5a08a60SJake Burkholder 
244d5a08a60SJake Burkholder /*
245d5a08a60SJake Burkholder  * Initialize a run structure.
246d5a08a60SJake Burkholder  */
247d5a08a60SJake Burkholder void
248d5a08a60SJake Burkholder runq_init(struct runq *rq)
249d5a08a60SJake Burkholder {
250d5a08a60SJake Burkholder 	int i;
251d5a08a60SJake Burkholder 
252f32ded2fSJake Burkholder 	bzero(rq, sizeof *rq);
253d5a08a60SJake Burkholder 	for (i = 0; i < RQ_NQS; i++)
254d5a08a60SJake Burkholder 		TAILQ_INIT(&rq->rq_queues[i]);
255d5a08a60SJake Burkholder }
256d5a08a60SJake Burkholder 
257d5a08a60SJake Burkholder /*
258d5a08a60SJake Burkholder  * Remove the process from the queue specified by its priority, and clear the
259d5a08a60SJake Burkholder  * corresponding status bit if the queue becomes empty.
260d5a08a60SJake Burkholder  */
261d5a08a60SJake Burkholder void
262b40ce416SJulian Elischer runq_remove(struct runq *rq, struct kse *ke)
263d5a08a60SJake Burkholder {
264d5a08a60SJake Burkholder 	struct rqhead *rqh;
265d5a08a60SJake Burkholder 	int pri;
266d5a08a60SJake Burkholder 
267b40ce416SJulian Elischer 	if (!(ke->ke_flags & KEF_ONRUNQ))
268b40ce416SJulian Elischer 		return;
269d5a08a60SJake Burkholder 	mtx_assert(&sched_lock, MA_OWNED);
270b40ce416SJulian Elischer 	pri = ke->ke_rqindex;
271d5a08a60SJake Burkholder 	rqh = &rq->rq_queues[pri];
272d5a08a60SJake Burkholder 	CTR4(KTR_RUNQ, "runq_remove: p=%p pri=%d %d rqh=%p",
2732c100766SJulian Elischer 	    ke, ke->ke_thread->td_priority, pri, rqh);
274b40ce416SJulian Elischer 	KASSERT(ke != NULL, ("runq_remove: no proc on busy queue"));
275b40ce416SJulian Elischer 	TAILQ_REMOVE(rqh, ke, ke_procq);
276d5a08a60SJake Burkholder 	if (TAILQ_EMPTY(rqh)) {
277d5a08a60SJake Burkholder 		CTR0(KTR_RUNQ, "runq_remove: empty");
278d5a08a60SJake Burkholder 		runq_clrbit(rq, pri);
279d5a08a60SJake Burkholder 	}
280b40ce416SJulian Elischer 	ke->ke_flags &= ~KEF_ONRUNQ;
281dba6c5a6SPeter Wemm }
282