xref: /freebsd/sys/kern/kern_switch.c (revision d5a08a6065a153f519dc5ada150c981d37f91345)
1dba6c5a6SPeter Wemm /*
2dba6c5a6SPeter Wemm  * Copyright (c) 1999 Peter Wemm <peter@FreeBSD.org>
3dba6c5a6SPeter Wemm  * All rights reserved.
4d5a08a60SJake Burkholder  * Copyright (c) 2001 Jake Burkholder <jake@FreeBSD.org>
5d5a08a60SJake Burkholder  * All rights reserved.
6dba6c5a6SPeter Wemm  *
7dba6c5a6SPeter Wemm  * Redistribution and use in source and binary forms, with or without
8dba6c5a6SPeter Wemm  * modification, are permitted provided that the following conditions
9dba6c5a6SPeter Wemm  * are met:
10dba6c5a6SPeter Wemm  * 1. Redistributions of source code must retain the above copyright
11dba6c5a6SPeter Wemm  *    notice, this list of conditions and the following disclaimer.
12dba6c5a6SPeter Wemm  * 2. Redistributions in binary form must reproduce the above copyright
13dba6c5a6SPeter Wemm  *    notice, this list of conditions and the following disclaimer in the
14dba6c5a6SPeter Wemm  *    documentation and/or other materials provided with the distribution.
15dba6c5a6SPeter Wemm  *
16dba6c5a6SPeter Wemm  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17dba6c5a6SPeter Wemm  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18dba6c5a6SPeter Wemm  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19dba6c5a6SPeter Wemm  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20dba6c5a6SPeter Wemm  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21dba6c5a6SPeter Wemm  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22dba6c5a6SPeter Wemm  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23dba6c5a6SPeter Wemm  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24dba6c5a6SPeter Wemm  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25dba6c5a6SPeter Wemm  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26dba6c5a6SPeter Wemm  * SUCH DAMAGE.
27dba6c5a6SPeter Wemm  *
28dba6c5a6SPeter Wemm  * $FreeBSD$
29dba6c5a6SPeter Wemm  */
30dba6c5a6SPeter Wemm 
31dba6c5a6SPeter Wemm #include <sys/param.h>
32dba6c5a6SPeter Wemm #include <sys/systm.h>
33dba6c5a6SPeter Wemm #include <sys/kernel.h>
340384fff8SJason Evans #include <sys/ktr.h>
3535e0e5b3SJohn Baldwin #include <sys/mutex.h>
36dba6c5a6SPeter Wemm #include <sys/proc.h>
37dba6c5a6SPeter Wemm #include <sys/queue.h>
38dba6c5a6SPeter Wemm 
39dba6c5a6SPeter Wemm /*
40d5a08a60SJake Burkholder  * Global run queue.
41dba6c5a6SPeter Wemm  */
42d5a08a60SJake Burkholder static struct runq runq;
43d5a08a60SJake Burkholder SYSINIT(runq, SI_SUB_RUN_QUEUE, SI_ORDER_FIRST, runq_init, &runq)
44dba6c5a6SPeter Wemm 
45dba6c5a6SPeter Wemm /*
46d5a08a60SJake Burkholder  * Wrappers which implement old interface; act on global run queue.
47dba6c5a6SPeter Wemm  */
48dba6c5a6SPeter Wemm 
49dba6c5a6SPeter Wemm struct proc *
50dba6c5a6SPeter Wemm chooseproc(void)
51dba6c5a6SPeter Wemm {
52d5a08a60SJake Burkholder 	return runq_choose(&runq);
53d5a08a60SJake Burkholder }
54d5a08a60SJake Burkholder 
55d5a08a60SJake Burkholder int
56d5a08a60SJake Burkholder procrunnable(void)
57d5a08a60SJake Burkholder {
58d5a08a60SJake Burkholder 	return runq_check(&runq);
59d5a08a60SJake Burkholder }
60d5a08a60SJake Burkholder 
61d5a08a60SJake Burkholder void
62d5a08a60SJake Burkholder remrunqueue(struct proc *p)
63d5a08a60SJake Burkholder {
64d5a08a60SJake Burkholder 	runq_remove(&runq, p);
65d5a08a60SJake Burkholder }
66d5a08a60SJake Burkholder 
67d5a08a60SJake Burkholder void
68d5a08a60SJake Burkholder setrunqueue(struct proc *p)
69d5a08a60SJake Burkholder {
70d5a08a60SJake Burkholder 	runq_add(&runq, p);
71d5a08a60SJake Burkholder }
72d5a08a60SJake Burkholder 
73d5a08a60SJake Burkholder /*
74d5a08a60SJake Burkholder  * Clear the status bit of the queue corresponding to priority level pri,
75d5a08a60SJake Burkholder  * indicating that it is empty.
76d5a08a60SJake Burkholder  */
77d5a08a60SJake Burkholder static __inline void
78d5a08a60SJake Burkholder runq_clrbit(struct runq *rq, int pri)
79d5a08a60SJake Burkholder {
80d5a08a60SJake Burkholder 	struct rqbits *rqb;
81d5a08a60SJake Burkholder 
82d5a08a60SJake Burkholder 	rqb = &rq->rq_status;
83d5a08a60SJake Burkholder 	CTR4(KTR_RUNQ, "runq_clrbit: bits=%#x %#x bit=%#x word=%d",
84d5a08a60SJake Burkholder 	    rqb->rqb_bits[RQB_WORD(pri)],
85d5a08a60SJake Burkholder 	    rqb->rqb_bits[RQB_WORD(pri)] & ~RQB_BIT(pri),
86d5a08a60SJake Burkholder 	    RQB_BIT(pri), RQB_WORD(pri));
87d5a08a60SJake Burkholder 	rqb->rqb_bits[RQB_WORD(pri)] &= ~RQB_BIT(pri);
88d5a08a60SJake Burkholder }
89d5a08a60SJake Burkholder 
90d5a08a60SJake Burkholder /*
91d5a08a60SJake Burkholder  * Find the index of the first non-empty run queue.  This is done by
92d5a08a60SJake Burkholder  * scanning the status bits, a set bit indicates a non-empty queue.
93d5a08a60SJake Burkholder  */
94d5a08a60SJake Burkholder static __inline int
95d5a08a60SJake Burkholder runq_findbit(struct runq *rq)
96d5a08a60SJake Burkholder {
97d5a08a60SJake Burkholder 	struct rqbits *rqb;
98d5a08a60SJake Burkholder 	int pri;
99d5a08a60SJake Burkholder 	int i;
100d5a08a60SJake Burkholder 
101d5a08a60SJake Burkholder 	rqb = &rq->rq_status;
102d5a08a60SJake Burkholder 	for (i = 0; i < RQB_LEN; i++)
103d5a08a60SJake Burkholder 		if (rqb->rqb_bits[i]) {
104d5a08a60SJake Burkholder 			pri = (RQB_FFS(rqb->rqb_bits[i]) - 1) +
105d5a08a60SJake Burkholder 			    (i << RQB_L2BPW);
106d5a08a60SJake Burkholder 			CTR3(KTR_RUNQ, "runq_findbit: bits=%#x i=%d pri=%d",
107d5a08a60SJake Burkholder 			    rqb->rqb_bits[i], i, pri);
108d5a08a60SJake Burkholder 			return (pri);
109d5a08a60SJake Burkholder 		}
110d5a08a60SJake Burkholder 
111d5a08a60SJake Burkholder 	return (-1);
112d5a08a60SJake Burkholder }
113d5a08a60SJake Burkholder 
114d5a08a60SJake Burkholder /*
115d5a08a60SJake Burkholder  * Set the status bit of the queue corresponding to priority level pri,
116d5a08a60SJake Burkholder  * indicating that it is non-empty.
117d5a08a60SJake Burkholder  */
118d5a08a60SJake Burkholder static __inline void
119d5a08a60SJake Burkholder runq_setbit(struct runq *rq, int pri)
120d5a08a60SJake Burkholder {
121d5a08a60SJake Burkholder 	struct rqbits *rqb;
122d5a08a60SJake Burkholder 
123d5a08a60SJake Burkholder 	rqb = &rq->rq_status;
124d5a08a60SJake Burkholder 	CTR4(KTR_RUNQ, "runq_setbit: bits=%#x %#x bit=%#x word=%d",
125d5a08a60SJake Burkholder 	    rqb->rqb_bits[RQB_WORD(pri)],
126d5a08a60SJake Burkholder 	    rqb->rqb_bits[RQB_WORD(pri)] | RQB_BIT(pri),
127d5a08a60SJake Burkholder 	    RQB_BIT(pri), RQB_WORD(pri));
128d5a08a60SJake Burkholder 	rqb->rqb_bits[RQB_WORD(pri)] |= RQB_BIT(pri);
129d5a08a60SJake Burkholder }
130d5a08a60SJake Burkholder 
131d5a08a60SJake Burkholder /*
132d5a08a60SJake Burkholder  * Add the process to the queue specified by its priority, and set the
133d5a08a60SJake Burkholder  * corresponding status bit.
134d5a08a60SJake Burkholder  */
135d5a08a60SJake Burkholder void
136d5a08a60SJake Burkholder runq_add(struct runq *rq, struct proc *p)
137d5a08a60SJake Burkholder {
138d5a08a60SJake Burkholder 	struct rqhead *rqh;
139d5a08a60SJake Burkholder 	int pri;
140dba6c5a6SPeter Wemm 
1410384fff8SJason Evans 	mtx_assert(&sched_lock, MA_OWNED);
142d5a08a60SJake Burkholder 	KASSERT(p->p_stat == SRUN, ("runq_add: proc %p (%s) not SRUN",
143d5a08a60SJake Burkholder 	    p, p->p_comm));
144d5a08a60SJake Burkholder 	pri = p->p_pri.pri_level / RQ_PPQ;
145d5a08a60SJake Burkholder 	p->p_rqindex = pri;
146d5a08a60SJake Burkholder 	runq_setbit(rq, pri);
147d5a08a60SJake Burkholder 	rqh = &rq->rq_queues[pri];
148d5a08a60SJake Burkholder 	CTR4(KTR_RUNQ, "runq_add: p=%p pri=%d %d rqh=%p",
149d5a08a60SJake Burkholder 	    p, p->p_pri.pri_level, pri, rqh);
150d5a08a60SJake Burkholder 	TAILQ_INSERT_TAIL(rqh, p, p_procq);
151dba6c5a6SPeter Wemm }
152d5a08a60SJake Burkholder 
153d5a08a60SJake Burkholder /*
154d5a08a60SJake Burkholder  * Return true if there are runnable processes of any priority on the run
155d5a08a60SJake Burkholder  * queue, false otherwise.  Has no side effects, does not modify the run
156d5a08a60SJake Burkholder  * queue structure.
157d5a08a60SJake Burkholder  */
158d5a08a60SJake Burkholder int
159d5a08a60SJake Burkholder runq_check(struct runq *rq)
160d5a08a60SJake Burkholder {
161d5a08a60SJake Burkholder 	struct rqbits *rqb;
162d5a08a60SJake Burkholder 	int i;
163d5a08a60SJake Burkholder 
164d5a08a60SJake Burkholder 	rqb = &rq->rq_status;
165d5a08a60SJake Burkholder 	for (i = 0; i < RQB_LEN; i++)
166d5a08a60SJake Burkholder 		if (rqb->rqb_bits[i]) {
167d5a08a60SJake Burkholder 			CTR2(KTR_RUNQ, "runq_check: bits=%#x i=%d",
168d5a08a60SJake Burkholder 			    rqb->rqb_bits[i], i);
169d5a08a60SJake Burkholder 			return (1);
170dba6c5a6SPeter Wemm 		}
171d5a08a60SJake Burkholder 	CTR0(KTR_RUNQ, "runq_check: empty");
172d5a08a60SJake Burkholder 
173d5a08a60SJake Burkholder 	return (0);
174dba6c5a6SPeter Wemm }
175d5a08a60SJake Burkholder 
176d5a08a60SJake Burkholder /*
177d5a08a60SJake Burkholder  * Find and remove the highest priority process from the run queue.
178d5a08a60SJake Burkholder  * If there are no runnable processes, the per-cpu idle process is
179d5a08a60SJake Burkholder  * returned.  Will not return NULL under any circumstances.
180d5a08a60SJake Burkholder  */
181d5a08a60SJake Burkholder struct proc *
182d5a08a60SJake Burkholder runq_choose(struct runq *rq)
183d5a08a60SJake Burkholder {
184d5a08a60SJake Burkholder 	struct rqhead *rqh;
185d5a08a60SJake Burkholder 	struct proc *p;
186d5a08a60SJake Burkholder 	int pri;
187d5a08a60SJake Burkholder 
188d5a08a60SJake Burkholder 	mtx_assert(&sched_lock, MA_OWNED);
189d5a08a60SJake Burkholder 	if ((pri = runq_findbit(rq)) != -1) {
190d5a08a60SJake Burkholder 		rqh = &rq->rq_queues[pri];
191d5a08a60SJake Burkholder 		p = TAILQ_FIRST(rqh);
192d5a08a60SJake Burkholder 		CTR3(KTR_RUNQ, "runq_choose: pri=%d p=%p rqh=%p", pri, p, rqh);
193d5a08a60SJake Burkholder 		TAILQ_REMOVE(rqh, p, p_procq);
194d5a08a60SJake Burkholder 		if (TAILQ_EMPTY(rqh)) {
195d5a08a60SJake Burkholder 			CTR0(KTR_RUNQ, "runq_choose: empty");
196d5a08a60SJake Burkholder 			runq_clrbit(rq, pri);
197d5a08a60SJake Burkholder 		}
198d5a08a60SJake Burkholder 		return (p);
199d5a08a60SJake Burkholder 	}
200d5a08a60SJake Burkholder 	CTR1(KTR_RUNQ, "runq_choose: idleproc pri=%d", pri);
201d5a08a60SJake Burkholder 
202d5a08a60SJake Burkholder 	return (PCPU_GET(idleproc));
203d5a08a60SJake Burkholder }
204d5a08a60SJake Burkholder 
205d5a08a60SJake Burkholder /*
206d5a08a60SJake Burkholder  * Initialize a run structure.
207d5a08a60SJake Burkholder  */
208d5a08a60SJake Burkholder void
209d5a08a60SJake Burkholder runq_init(struct runq *rq)
210d5a08a60SJake Burkholder {
211d5a08a60SJake Burkholder 	int i;
212d5a08a60SJake Burkholder 
213d5a08a60SJake Burkholder 	for (i = 0; i < RQ_NQS; i++)
214d5a08a60SJake Burkholder 		TAILQ_INIT(&rq->rq_queues[i]);
215d5a08a60SJake Burkholder }
216d5a08a60SJake Burkholder 
217d5a08a60SJake Burkholder /*
218d5a08a60SJake Burkholder  * Remove the process from the queue specified by its priority, and clear the
219d5a08a60SJake Burkholder  * corresponding status bit if the queue becomes empty.
220d5a08a60SJake Burkholder  */
221d5a08a60SJake Burkholder void
222d5a08a60SJake Burkholder runq_remove(struct runq *rq, struct proc *p)
223d5a08a60SJake Burkholder {
224d5a08a60SJake Burkholder 	struct rqhead *rqh;
225d5a08a60SJake Burkholder 	int pri;
226d5a08a60SJake Burkholder 
227d5a08a60SJake Burkholder 	mtx_assert(&sched_lock, MA_OWNED);
228d5a08a60SJake Burkholder 	pri = p->p_rqindex;
229d5a08a60SJake Burkholder 	rqh = &rq->rq_queues[pri];
230d5a08a60SJake Burkholder 	CTR4(KTR_RUNQ, "runq_remove: p=%p pri=%d %d rqh=%p",
231d5a08a60SJake Burkholder 	    p, p->p_pri.pri_level, pri, rqh);
232d5a08a60SJake Burkholder 	KASSERT(p != NULL, ("runq_remove: no proc on busy queue"));
233d5a08a60SJake Burkholder 	TAILQ_REMOVE(rqh, p, p_procq);
234d5a08a60SJake Burkholder 	if (TAILQ_EMPTY(rqh)) {
235d5a08a60SJake Burkholder 		CTR0(KTR_RUNQ, "runq_remove: empty");
236d5a08a60SJake Burkholder 		runq_clrbit(rq, pri);
237d5a08a60SJake Burkholder 	}
238dba6c5a6SPeter Wemm }
239