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