xref: /freebsd/sys/kern/kern_switch.c (revision 7f3dea244c40159a41ab22da77a434d7c5b5e85a)
1 /*
2  * Copyright (c) 1999 Peter Wemm <peter@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28 
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/kernel.h>
32 #include <sys/proc.h>
33 #include <sys/rtprio.h>
34 #include <sys/queue.h>
35 
36 /*
37  * We have NQS (32) run queues per scheduling class.  For the normal
38  * class, there are 128 priorities scaled onto these 32 queues.  New
39  * processes are added to the last entry in each queue, and processes
40  * are selected for running by taking them from the head and maintaining
41  * a simple FIFO arrangement.  Realtime and Idle priority processes have
42  * and explicit 0-31 priority which maps directly onto their class queue
43  * index.  When a queue has something in it, the corresponding bit is
44  * set in the queuebits variable, allowing a single read to determine
45  * the state of all 32 queues and then a ffs() to find the first busy
46  * queue.
47  */
48 struct rq queues[NQS];
49 struct rq rtqueues[NQS];
50 struct rq idqueues[NQS];
51 u_int32_t queuebits;
52 u_int32_t rtqueuebits;
53 u_int32_t idqueuebits;
54 
55 /*
56  * Initialize the run queues at boot time.
57  */
58 static void
59 rqinit(void *dummy)
60 {
61 	int i;
62 
63 	for (i = 0; i < NQS; i++) {
64 		TAILQ_INIT(&queues[i]);
65 		TAILQ_INIT(&rtqueues[i]);
66 		TAILQ_INIT(&idqueues[i]);
67 	}
68 }
69 SYSINIT(runqueue, SI_SUB_RUN_QUEUE, SI_ORDER_FIRST, rqinit, NULL)
70 
71 /*
72  * setrunqueue() examines a process priority and class and inserts it on
73  * the tail of it's appropriate run queue (based on class and priority).
74  * This sets the queue busy bit.
75  * The process must be runnable.
76  * This must be called at splhigh().
77  */
78 void
79 setrunqueue(struct proc *p)
80 {
81 	struct rq *q;
82 	u_int8_t pri;
83 
84 	KASSERT(p->p_stat == SRUN, ("setrunqueue: proc not SRUN"));
85 	if (p->p_rtprio.type == RTP_PRIO_NORMAL) {
86 		pri = p->p_priority >> 2;
87 		q = &queues[pri];
88 		queuebits |= 1 << pri;
89 	} else if (p->p_rtprio.type == RTP_PRIO_REALTIME ||
90 		   p->p_rtprio.type == RTP_PRIO_FIFO) {
91 		pri = p->p_rtprio.prio;
92 		q = &rtqueues[pri];
93 		rtqueuebits |= 1 << pri;
94 	} else if (p->p_rtprio.type == RTP_PRIO_IDLE) {
95 		pri = p->p_rtprio.prio;
96 		q = &idqueues[pri];
97 		idqueuebits |= 1 << pri;
98 	} else {
99 		panic("setrunqueue: invalid rtprio type");
100 	}
101 	p->p_rqindex = pri;		/* remember the queue index */
102 	TAILQ_INSERT_TAIL(q, p, p_procq);
103 }
104 
105 /*
106  * remrunqueue() removes a given process from the run queue that it is on,
107  * clearing the queue busy bit if it becomes empty.
108  * This must be called at splhigh().
109  */
110 void
111 remrunqueue(struct proc *p)
112 {
113 	struct rq *q;
114 	u_int32_t *which;
115 	u_int8_t pri;
116 
117 	pri = p->p_rqindex;
118 	if (p->p_rtprio.type == RTP_PRIO_NORMAL) {
119 		q = &queues[pri];
120 		which = &queuebits;
121 	} else if (p->p_rtprio.type == RTP_PRIO_REALTIME ||
122 		   p->p_rtprio.type == RTP_PRIO_FIFO) {
123 		q = &rtqueues[pri];
124 		which = &rtqueuebits;
125 	} else if (p->p_rtprio.type == RTP_PRIO_IDLE) {
126 		q = &idqueues[pri];
127 		which = &idqueuebits;
128 	} else {
129 		panic("remrunqueue: invalid rtprio type");
130 	}
131 	TAILQ_REMOVE(q, p, p_procq);
132 	if (TAILQ_EMPTY(q)) {
133 		KASSERT((*which & (1 << pri)) != 0,
134 			("remrunqueue: remove from empty queue"));
135 		*which &= ~(1 << pri);
136 	}
137 }
138 
139 /*
140  * procrunnable() returns a boolean true (non-zero) value if there are
141  * any runnable processes.  This is intended to be called from the idle
142  * loop to avoid the more expensive (and destructive) chooseproc().
143  */
144 u_int32_t
145 procrunnable(void)
146 {
147 	return (rtqueuebits || queuebits || idqueuebits);
148 }
149 
150 /*
151  * chooseproc() selects the next process to run.  Ideally, cpu_switch()
152  * would have determined that there is a process available before calling
153  * this, but it is not a requirement.  The selected process is removed
154  * from it's queue, and the queue busy bit is cleared if it becomes empty.
155  * This must be called at splhigh().
156  *
157  * For SMP, trivial affinity is implemented by locating the first process
158  * on the queue that has a matching lastcpu id.  Since normal priorities
159  * are mapped four priority levels per queue, this may allow the cpu to
160  * choose a slightly lower priority process in order to preserve the cpu
161  * caches.
162  */
163 struct proc *
164 chooseproc(void)
165 {
166 	struct proc *p;
167 	struct rq *q;
168 	u_int32_t *which;
169 	u_int32_t pri;
170 #ifdef SMP
171 	u_char id;
172 #endif
173 
174 	if (rtqueuebits) {
175 		pri = ffs(rtqueuebits) - 1;
176 		q = &rtqueues[pri];
177 		which = &rtqueuebits;
178 	} else if (queuebits) {
179 		pri = ffs(queuebits) - 1;
180 		q = &queues[pri];
181 		which = &queuebits;
182 	} else if (idqueuebits) {
183 		pri = ffs(idqueuebits) - 1;
184 		q = &idqueues[pri];
185 		which = &idqueuebits;
186 	} else {
187 		return NULL;
188 	}
189 	p = TAILQ_FIRST(q);
190 	KASSERT(p, ("chooseproc: no proc on busy queue"));
191 #ifdef SMP
192 	/* wander down the current run queue for this pri level for a match */
193 	id = cpuid;
194 	while (p->p_lastcpu != id) {
195 		p = TAILQ_NEXT(p, p_procq);
196 		if (p == NULL) {
197 			p = TAILQ_FIRST(q);
198 			break;
199 		}
200 	}
201 #endif
202 	TAILQ_REMOVE(q, p, p_procq);
203 	if (TAILQ_EMPTY(q))
204 		*which &= ~(1 << pri);
205 	return p;
206 }
207