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