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