19454b2d8SWarner Losh /*- 2d5a08a60SJake Burkholder * Copyright (c) 2001 Jake Burkholder <jake@FreeBSD.org> 3d5a08a60SJake Burkholder * All rights reserved. 4dba6c5a6SPeter Wemm * 5dba6c5a6SPeter Wemm * Redistribution and use in source and binary forms, with or without 6dba6c5a6SPeter Wemm * modification, are permitted provided that the following conditions 7dba6c5a6SPeter Wemm * are met: 8dba6c5a6SPeter Wemm * 1. Redistributions of source code must retain the above copyright 9dba6c5a6SPeter Wemm * notice, this list of conditions and the following disclaimer. 10dba6c5a6SPeter Wemm * 2. Redistributions in binary form must reproduce the above copyright 11dba6c5a6SPeter Wemm * notice, this list of conditions and the following disclaimer in the 12dba6c5a6SPeter Wemm * documentation and/or other materials provided with the distribution. 13dba6c5a6SPeter Wemm * 14dba6c5a6SPeter Wemm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15dba6c5a6SPeter Wemm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16dba6c5a6SPeter Wemm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17dba6c5a6SPeter Wemm * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18dba6c5a6SPeter Wemm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19dba6c5a6SPeter Wemm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20dba6c5a6SPeter Wemm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21dba6c5a6SPeter Wemm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22dba6c5a6SPeter Wemm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23dba6c5a6SPeter Wemm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24dba6c5a6SPeter Wemm * SUCH DAMAGE. 25dba6c5a6SPeter Wemm */ 26dba6c5a6SPeter Wemm 27e602ba25SJulian Elischer 28677b542eSDavid E. O'Brien #include <sys/cdefs.h> 29677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 30e602ba25SJulian Elischer 316804a3abSJulian Elischer #include "opt_sched.h" 320c0b25aeSJohn Baldwin 33ed062c8dSJulian Elischer #ifndef KERN_SWITCH_INCLUDE 34dba6c5a6SPeter Wemm #include <sys/param.h> 35dba6c5a6SPeter Wemm #include <sys/systm.h> 362d50560aSMarcel Moolenaar #include <sys/kdb.h> 37dba6c5a6SPeter Wemm #include <sys/kernel.h> 380384fff8SJason Evans #include <sys/ktr.h> 39f34fa851SJohn Baldwin #include <sys/lock.h> 4035e0e5b3SJohn Baldwin #include <sys/mutex.h> 41dba6c5a6SPeter Wemm #include <sys/proc.h> 42dba6c5a6SPeter Wemm #include <sys/queue.h> 43b43179fbSJeff Roberson #include <sys/sched.h> 44ed062c8dSJulian Elischer #else /* KERN_SWITCH_INCLUDE */ 450d2a2989SPeter Wemm #if defined(SMP) && (defined(__i386__) || defined(__amd64__)) 46cc66ebe2SPeter Wemm #include <sys/smp.h> 47cc66ebe2SPeter Wemm #endif 486804a3abSJulian Elischer 497b20fb19SJeff Roberson #include <machine/cpu.h> 507b20fb19SJeff Roberson 511335c4dfSNate Lawson /* Uncomment this to enable logging of critical_enter/exit. */ 521335c4dfSNate Lawson #if 0 531335c4dfSNate Lawson #define KTR_CRITICAL KTR_SCHED 541335c4dfSNate Lawson #else 551335c4dfSNate Lawson #define KTR_CRITICAL 0 561335c4dfSNate Lawson #endif 571335c4dfSNate Lawson 589923b511SScott Long #ifdef FULL_PREEMPTION 599923b511SScott Long #ifndef PREEMPTION 609923b511SScott Long #error "The FULL_PREEMPTION option requires the PREEMPTION option" 619923b511SScott Long #endif 629923b511SScott Long #endif 63dba6c5a6SPeter Wemm 64d2ac2316SJake Burkholder CTASSERT((RQB_BPW * RQB_LEN) == RQ_NQS); 65d2ac2316SJake Burkholder 666220dcbaSRobert Watson /* 676220dcbaSRobert Watson * kern.sched.preemption allows user space to determine if preemption support 686220dcbaSRobert Watson * is compiled in or not. It is not currently a boot or runtime flag that 696220dcbaSRobert Watson * can be changed. 706220dcbaSRobert Watson */ 716220dcbaSRobert Watson #ifdef PREEMPTION 726220dcbaSRobert Watson static int kern_sched_preemption = 1; 736220dcbaSRobert Watson #else 746220dcbaSRobert Watson static int kern_sched_preemption = 0; 756220dcbaSRobert Watson #endif 766220dcbaSRobert Watson SYSCTL_INT(_kern_sched, OID_AUTO, preemption, CTLFLAG_RD, 776220dcbaSRobert Watson &kern_sched_preemption, 0, "Kernel preemption enabled"); 786220dcbaSRobert Watson 797b20fb19SJeff Roberson #ifdef SCHED_STATS 807b20fb19SJeff Roberson long switch_preempt; 817b20fb19SJeff Roberson long switch_owepreempt; 827b20fb19SJeff Roberson long switch_turnstile; 837b20fb19SJeff Roberson long switch_sleepq; 847b20fb19SJeff Roberson long switch_sleepqtimo; 857b20fb19SJeff Roberson long switch_relinquish; 867b20fb19SJeff Roberson long switch_needresched; 877b20fb19SJeff Roberson static SYSCTL_NODE(_kern_sched, OID_AUTO, stats, CTLFLAG_RW, 0, "switch stats"); 887b20fb19SJeff Roberson SYSCTL_INT(_kern_sched_stats, OID_AUTO, preempt, CTLFLAG_RD, &switch_preempt, 0, ""); 897b20fb19SJeff Roberson SYSCTL_INT(_kern_sched_stats, OID_AUTO, owepreempt, CTLFLAG_RD, &switch_owepreempt, 0, ""); 907b20fb19SJeff Roberson SYSCTL_INT(_kern_sched_stats, OID_AUTO, turnstile, CTLFLAG_RD, &switch_turnstile, 0, ""); 917b20fb19SJeff Roberson SYSCTL_INT(_kern_sched_stats, OID_AUTO, sleepq, CTLFLAG_RD, &switch_sleepq, 0, ""); 927b20fb19SJeff Roberson SYSCTL_INT(_kern_sched_stats, OID_AUTO, sleepqtimo, CTLFLAG_RD, &switch_sleepqtimo, 0, ""); 937b20fb19SJeff Roberson SYSCTL_INT(_kern_sched_stats, OID_AUTO, relinquish, CTLFLAG_RD, &switch_relinquish, 0, ""); 947b20fb19SJeff Roberson SYSCTL_INT(_kern_sched_stats, OID_AUTO, needresched, CTLFLAG_RD, &switch_needresched, 0, ""); 957b20fb19SJeff Roberson static int 967b20fb19SJeff Roberson sysctl_stats_reset(SYSCTL_HANDLER_ARGS) 977b20fb19SJeff Roberson { 987b20fb19SJeff Roberson int error; 997b20fb19SJeff Roberson int val; 1007b20fb19SJeff Roberson 1017b20fb19SJeff Roberson val = 0; 1027b20fb19SJeff Roberson error = sysctl_handle_int(oidp, &val, 0, req); 1037b20fb19SJeff Roberson if (error != 0 || req->newptr == NULL) 1047b20fb19SJeff Roberson return (error); 1057b20fb19SJeff Roberson if (val == 0) 1067b20fb19SJeff Roberson return (0); 1077b20fb19SJeff Roberson switch_preempt = 0; 1087b20fb19SJeff Roberson switch_owepreempt = 0; 1097b20fb19SJeff Roberson switch_turnstile = 0; 1107b20fb19SJeff Roberson switch_sleepq = 0; 1117b20fb19SJeff Roberson switch_sleepqtimo = 0; 1127b20fb19SJeff Roberson switch_relinquish = 0; 1137b20fb19SJeff Roberson switch_needresched = 0; 1147b20fb19SJeff Roberson 1157b20fb19SJeff Roberson return (0); 1167b20fb19SJeff Roberson } 1177b20fb19SJeff Roberson 1187b20fb19SJeff Roberson SYSCTL_PROC(_kern_sched_stats, OID_AUTO, reset, CTLTYPE_INT | CTLFLAG_WR, NULL, 1197b20fb19SJeff Roberson 0, sysctl_stats_reset, "I", "Reset scheduler statistics"); 1207b20fb19SJeff Roberson #endif 1217b20fb19SJeff Roberson 122e602ba25SJulian Elischer /************************************************************************ 123e602ba25SJulian Elischer * Functions that manipulate runnability from a thread perspective. * 124e602ba25SJulian Elischer ************************************************************************/ 1258460a577SJohn Birrell /* 1268460a577SJohn Birrell * Select the thread that will be run next. 1278460a577SJohn Birrell */ 128b40ce416SJulian Elischer struct thread * 129b40ce416SJulian Elischer choosethread(void) 130dba6c5a6SPeter Wemm { 131e602ba25SJulian Elischer struct thread *td; 132e602ba25SJulian Elischer 133fe799533SAndrew Gallatin retry: 134f0393f06SJeff Roberson td = sched_choose(); 13593a7aa79SJulian Elischer 13693a7aa79SJulian Elischer /* 137faaa20f6SJulian Elischer * If we are in panic, only allow system threads, 138faaa20f6SJulian Elischer * plus the one we are running in, to be run. 13993a7aa79SJulian Elischer */ 140fe799533SAndrew Gallatin if (panicstr && ((td->td_proc->p_flag & P_SYSTEM) == 0 && 141faaa20f6SJulian Elischer (td->td_flags & TDF_INPANIC) == 0)) { 142faaa20f6SJulian Elischer /* note that it is no longer on the run queue */ 143faaa20f6SJulian Elischer TD_SET_CAN_RUN(td); 144fe799533SAndrew Gallatin goto retry; 145faaa20f6SJulian Elischer } 14693a7aa79SJulian Elischer 14771fad9fdSJulian Elischer TD_SET_RUNNING(td); 148e602ba25SJulian Elischer return (td); 149e602ba25SJulian Elischer } 150e602ba25SJulian Elischer 1510c0b25aeSJohn Baldwin /* 1520c0b25aeSJohn Baldwin * Kernel thread preemption implementation. Critical sections mark 1530c0b25aeSJohn Baldwin * regions of code in which preemptions are not allowed. 1540c0b25aeSJohn Baldwin */ 1557e1f6dfeSJohn Baldwin void 1567e1f6dfeSJohn Baldwin critical_enter(void) 1577e1f6dfeSJohn Baldwin { 1587e1f6dfeSJohn Baldwin struct thread *td; 1597e1f6dfeSJohn Baldwin 1607e1f6dfeSJohn Baldwin td = curthread; 1617e1f6dfeSJohn Baldwin td->td_critnest++; 1621335c4dfSNate Lawson CTR4(KTR_CRITICAL, "critical_enter by thread %p (%ld, %s) to %d", td, 163431f8906SJulian Elischer (long)td->td_proc->p_pid, td->td_name, td->td_critnest); 1647e1f6dfeSJohn Baldwin } 1657e1f6dfeSJohn Baldwin 1667e1f6dfeSJohn Baldwin void 1677e1f6dfeSJohn Baldwin critical_exit(void) 1687e1f6dfeSJohn Baldwin { 1697e1f6dfeSJohn Baldwin struct thread *td; 1707e1f6dfeSJohn Baldwin 1717e1f6dfeSJohn Baldwin td = curthread; 172b209e5e3SJeff Roberson KASSERT(td->td_critnest != 0, 173b209e5e3SJeff Roberson ("critical_exit: td_critnest == 0")); 1745bce4ae3SJeff Roberson 175d13ec713SStephan Uphoff if (td->td_critnest == 1) { 176d13ec713SStephan Uphoff td->td_critnest = 0; 17777918643SStephan Uphoff if (td->td_owepreempt) { 17877918643SStephan Uphoff td->td_critnest = 1; 1797b20fb19SJeff Roberson thread_lock(td); 18077918643SStephan Uphoff td->td_critnest--; 1817b20fb19SJeff Roberson SCHED_STAT_INC(switch_owepreempt); 182413ea6f5SJeff Roberson mi_switch(SW_INVOL|SW_PREEMPT, NULL); 1837b20fb19SJeff Roberson thread_unlock(td); 1840c0b25aeSJohn Baldwin } 185d13ec713SStephan Uphoff } else 1867e1f6dfeSJohn Baldwin td->td_critnest--; 187d13ec713SStephan Uphoff 1881335c4dfSNate Lawson CTR4(KTR_CRITICAL, "critical_exit by thread %p (%ld, %s) to %d", td, 189431f8906SJulian Elischer (long)td->td_proc->p_pid, td->td_name, td->td_critnest); 190d74ac681SMatthew Dillon } 1917e1f6dfeSJohn Baldwin 192e602ba25SJulian Elischer /************************************************************************ 193e602ba25SJulian Elischer * SYSTEM RUN QUEUE manipulations and tests * 194e602ba25SJulian Elischer ************************************************************************/ 195e602ba25SJulian Elischer /* 196e602ba25SJulian Elischer * Initialize a run structure. 197e602ba25SJulian Elischer */ 198e602ba25SJulian Elischer void 199e602ba25SJulian Elischer runq_init(struct runq *rq) 200e602ba25SJulian Elischer { 201e602ba25SJulian Elischer int i; 202e602ba25SJulian Elischer 203e602ba25SJulian Elischer bzero(rq, sizeof *rq); 204e602ba25SJulian Elischer for (i = 0; i < RQ_NQS; i++) 205e602ba25SJulian Elischer TAILQ_INIT(&rq->rq_queues[i]); 206e602ba25SJulian Elischer } 207e602ba25SJulian Elischer 208d5a08a60SJake Burkholder /* 209d5a08a60SJake Burkholder * Clear the status bit of the queue corresponding to priority level pri, 210d5a08a60SJake Burkholder * indicating that it is empty. 211d5a08a60SJake Burkholder */ 212d5a08a60SJake Burkholder static __inline void 213d5a08a60SJake Burkholder runq_clrbit(struct runq *rq, int pri) 214d5a08a60SJake Burkholder { 215d5a08a60SJake Burkholder struct rqbits *rqb; 216d5a08a60SJake Burkholder 217d5a08a60SJake Burkholder rqb = &rq->rq_status; 218d5a08a60SJake Burkholder CTR4(KTR_RUNQ, "runq_clrbit: bits=%#x %#x bit=%#x word=%d", 219d5a08a60SJake Burkholder rqb->rqb_bits[RQB_WORD(pri)], 220d5a08a60SJake Burkholder rqb->rqb_bits[RQB_WORD(pri)] & ~RQB_BIT(pri), 221d5a08a60SJake Burkholder RQB_BIT(pri), RQB_WORD(pri)); 222d5a08a60SJake Burkholder rqb->rqb_bits[RQB_WORD(pri)] &= ~RQB_BIT(pri); 223d5a08a60SJake Burkholder } 224d5a08a60SJake Burkholder 225d5a08a60SJake Burkholder /* 226d5a08a60SJake Burkholder * Find the index of the first non-empty run queue. This is done by 227d5a08a60SJake Burkholder * scanning the status bits, a set bit indicates a non-empty queue. 228d5a08a60SJake Burkholder */ 229d5a08a60SJake Burkholder static __inline int 230d5a08a60SJake Burkholder runq_findbit(struct runq *rq) 231d5a08a60SJake Burkholder { 232d5a08a60SJake Burkholder struct rqbits *rqb; 233d5a08a60SJake Burkholder int pri; 234d5a08a60SJake Burkholder int i; 235d5a08a60SJake Burkholder 236d5a08a60SJake Burkholder rqb = &rq->rq_status; 237d5a08a60SJake Burkholder for (i = 0; i < RQB_LEN; i++) 238d5a08a60SJake Burkholder if (rqb->rqb_bits[i]) { 2392f9267ecSPeter Wemm pri = RQB_FFS(rqb->rqb_bits[i]) + (i << RQB_L2BPW); 240d5a08a60SJake Burkholder CTR3(KTR_RUNQ, "runq_findbit: bits=%#x i=%d pri=%d", 241d5a08a60SJake Burkholder rqb->rqb_bits[i], i, pri); 242d5a08a60SJake Burkholder return (pri); 243d5a08a60SJake Burkholder } 244d5a08a60SJake Burkholder 245d5a08a60SJake Burkholder return (-1); 246d5a08a60SJake Burkholder } 247d5a08a60SJake Burkholder 2483fed7d23SJeff Roberson static __inline int 24967e20930SJeff Roberson runq_findbit_from(struct runq *rq, u_char pri) 2503fed7d23SJeff Roberson { 2513fed7d23SJeff Roberson struct rqbits *rqb; 25267e20930SJeff Roberson rqb_word_t mask; 2533fed7d23SJeff Roberson int i; 2543fed7d23SJeff Roberson 25567e20930SJeff Roberson /* 25667e20930SJeff Roberson * Set the mask for the first word so we ignore priorities before 'pri'. 25767e20930SJeff Roberson */ 25867e20930SJeff Roberson mask = (rqb_word_t)-1 << (pri & (RQB_BPW - 1)); 2593fed7d23SJeff Roberson rqb = &rq->rq_status; 2603fed7d23SJeff Roberson again: 26167e20930SJeff Roberson for (i = RQB_WORD(pri); i < RQB_LEN; mask = -1, i++) { 26267e20930SJeff Roberson mask = rqb->rqb_bits[i] & mask; 26367e20930SJeff Roberson if (mask == 0) 2643fed7d23SJeff Roberson continue; 26567e20930SJeff Roberson pri = RQB_FFS(mask) + (i << RQB_L2BPW); 2663fed7d23SJeff Roberson CTR3(KTR_RUNQ, "runq_findbit_from: bits=%#x i=%d pri=%d", 26767e20930SJeff Roberson mask, i, pri); 2683fed7d23SJeff Roberson return (pri); 2693fed7d23SJeff Roberson } 27067e20930SJeff Roberson if (pri == 0) 2713fed7d23SJeff Roberson return (-1); 27267e20930SJeff Roberson /* 27367e20930SJeff Roberson * Wrap back around to the beginning of the list just once so we 27467e20930SJeff Roberson * scan the whole thing. 27567e20930SJeff Roberson */ 27667e20930SJeff Roberson pri = 0; 27767e20930SJeff Roberson goto again; 2783fed7d23SJeff Roberson } 2793fed7d23SJeff Roberson 280d5a08a60SJake Burkholder /* 281d5a08a60SJake Burkholder * Set the status bit of the queue corresponding to priority level pri, 282d5a08a60SJake Burkholder * indicating that it is non-empty. 283d5a08a60SJake Burkholder */ 284d5a08a60SJake Burkholder static __inline void 285d5a08a60SJake Burkholder runq_setbit(struct runq *rq, int pri) 286d5a08a60SJake Burkholder { 287d5a08a60SJake Burkholder struct rqbits *rqb; 288d5a08a60SJake Burkholder 289d5a08a60SJake Burkholder rqb = &rq->rq_status; 290d5a08a60SJake Burkholder CTR4(KTR_RUNQ, "runq_setbit: bits=%#x %#x bit=%#x word=%d", 291d5a08a60SJake Burkholder rqb->rqb_bits[RQB_WORD(pri)], 292d5a08a60SJake Burkholder rqb->rqb_bits[RQB_WORD(pri)] | RQB_BIT(pri), 293d5a08a60SJake Burkholder RQB_BIT(pri), RQB_WORD(pri)); 294d5a08a60SJake Burkholder rqb->rqb_bits[RQB_WORD(pri)] |= RQB_BIT(pri); 295d5a08a60SJake Burkholder } 296d5a08a60SJake Burkholder 297d5a08a60SJake Burkholder /* 298ad1e7d28SJulian Elischer * Add the thread to the queue specified by its priority, and set the 299d5a08a60SJake Burkholder * corresponding status bit. 300d5a08a60SJake Burkholder */ 301d5a08a60SJake Burkholder void 302ad1e7d28SJulian Elischer runq_add(struct runq *rq, struct td_sched *ts, int flags) 303d5a08a60SJake Burkholder { 304d5a08a60SJake Burkholder struct rqhead *rqh; 305d5a08a60SJake Burkholder int pri; 306dba6c5a6SPeter Wemm 307ad1e7d28SJulian Elischer pri = ts->ts_thread->td_priority / RQ_PPQ; 308ad1e7d28SJulian Elischer ts->ts_rqindex = pri; 309d5a08a60SJake Burkholder runq_setbit(rq, pri); 310d5a08a60SJake Burkholder rqh = &rq->rq_queues[pri]; 311ad1e7d28SJulian Elischer CTR5(KTR_RUNQ, "runq_add: td=%p ts=%p pri=%d %d rqh=%p", 312ad1e7d28SJulian Elischer ts->ts_thread, ts, ts->ts_thread->td_priority, pri, rqh); 313c20c691bSJulian Elischer if (flags & SRQ_PREEMPTED) { 314ad1e7d28SJulian Elischer TAILQ_INSERT_HEAD(rqh, ts, ts_procq); 315c20c691bSJulian Elischer } else { 316ad1e7d28SJulian Elischer TAILQ_INSERT_TAIL(rqh, ts, ts_procq); 317dba6c5a6SPeter Wemm } 318c20c691bSJulian Elischer } 319d5a08a60SJake Burkholder 3203fed7d23SJeff Roberson void 321ed0e8f2fSJeff Roberson runq_add_pri(struct runq *rq, struct td_sched *ts, u_char pri, int flags) 3223fed7d23SJeff Roberson { 3233fed7d23SJeff Roberson struct rqhead *rqh; 3243fed7d23SJeff Roberson 3253fed7d23SJeff Roberson KASSERT(pri < RQ_NQS, ("runq_add_pri: %d out of range", pri)); 3263fed7d23SJeff Roberson ts->ts_rqindex = pri; 3273fed7d23SJeff Roberson runq_setbit(rq, pri); 3283fed7d23SJeff Roberson rqh = &rq->rq_queues[pri]; 3293fed7d23SJeff Roberson CTR5(KTR_RUNQ, "runq_add_pri: td=%p ke=%p pri=%d idx=%d rqh=%p", 3303fed7d23SJeff Roberson ts->ts_thread, ts, ts->ts_thread->td_priority, pri, rqh); 3313fed7d23SJeff Roberson if (flags & SRQ_PREEMPTED) { 3323fed7d23SJeff Roberson TAILQ_INSERT_HEAD(rqh, ts, ts_procq); 3333fed7d23SJeff Roberson } else { 3343fed7d23SJeff Roberson TAILQ_INSERT_TAIL(rqh, ts, ts_procq); 3353fed7d23SJeff Roberson } 3363fed7d23SJeff Roberson } 337d5a08a60SJake Burkholder /* 338d5a08a60SJake Burkholder * Return true if there are runnable processes of any priority on the run 339d5a08a60SJake Burkholder * queue, false otherwise. Has no side effects, does not modify the run 340d5a08a60SJake Burkholder * queue structure. 341d5a08a60SJake Burkholder */ 342d5a08a60SJake Burkholder int 343d5a08a60SJake Burkholder runq_check(struct runq *rq) 344d5a08a60SJake Burkholder { 345d5a08a60SJake Burkholder struct rqbits *rqb; 346d5a08a60SJake Burkholder int i; 347d5a08a60SJake Burkholder 348d5a08a60SJake Burkholder rqb = &rq->rq_status; 349d5a08a60SJake Burkholder for (i = 0; i < RQB_LEN; i++) 350d5a08a60SJake Burkholder if (rqb->rqb_bits[i]) { 351d5a08a60SJake Burkholder CTR2(KTR_RUNQ, "runq_check: bits=%#x i=%d", 352d5a08a60SJake Burkholder rqb->rqb_bits[i], i); 353d5a08a60SJake Burkholder return (1); 354dba6c5a6SPeter Wemm } 355d5a08a60SJake Burkholder CTR0(KTR_RUNQ, "runq_check: empty"); 356d5a08a60SJake Burkholder 357d5a08a60SJake Burkholder return (0); 358dba6c5a6SPeter Wemm } 359d5a08a60SJake Burkholder 360a90f3f25SJeff Roberson /* 361a90f3f25SJeff Roberson * Find the highest priority process on the run queue. 362a90f3f25SJeff Roberson */ 363a90f3f25SJeff Roberson struct td_sched * 364a90f3f25SJeff Roberson runq_choose_fuzz(struct runq *rq, int fuzz) 365a90f3f25SJeff Roberson { 366a90f3f25SJeff Roberson struct rqhead *rqh; 367a90f3f25SJeff Roberson struct td_sched *ts; 368a90f3f25SJeff Roberson int pri; 369a90f3f25SJeff Roberson 370a90f3f25SJeff Roberson while ((pri = runq_findbit(rq)) != -1) { 371a90f3f25SJeff Roberson rqh = &rq->rq_queues[pri]; 372a90f3f25SJeff Roberson /* fuzz == 1 is normal.. 0 or less are ignored */ 373a90f3f25SJeff Roberson if (fuzz > 1) { 374a90f3f25SJeff Roberson /* 375a90f3f25SJeff Roberson * In the first couple of entries, check if 376a90f3f25SJeff Roberson * there is one for our CPU as a preference. 377a90f3f25SJeff Roberson */ 378a90f3f25SJeff Roberson int count = fuzz; 379a90f3f25SJeff Roberson int cpu = PCPU_GET(cpuid); 380a90f3f25SJeff Roberson struct td_sched *ts2; 381a90f3f25SJeff Roberson ts2 = ts = TAILQ_FIRST(rqh); 382a90f3f25SJeff Roberson 383a90f3f25SJeff Roberson while (count-- && ts2) { 384a90f3f25SJeff Roberson if (ts->ts_thread->td_lastcpu == cpu) { 385a90f3f25SJeff Roberson ts = ts2; 386a90f3f25SJeff Roberson break; 387a90f3f25SJeff Roberson } 388a90f3f25SJeff Roberson ts2 = TAILQ_NEXT(ts2, ts_procq); 389a90f3f25SJeff Roberson } 390a90f3f25SJeff Roberson } else 391a90f3f25SJeff Roberson ts = TAILQ_FIRST(rqh); 392a90f3f25SJeff Roberson KASSERT(ts != NULL, ("runq_choose_fuzz: no proc on busy queue")); 393a90f3f25SJeff Roberson CTR3(KTR_RUNQ, 394a90f3f25SJeff Roberson "runq_choose_fuzz: pri=%d td_sched=%p rqh=%p", pri, ts, rqh); 395a90f3f25SJeff Roberson return (ts); 396a90f3f25SJeff Roberson } 397a90f3f25SJeff Roberson CTR1(KTR_RUNQ, "runq_choose_fuzz: idleproc pri=%d", pri); 398a90f3f25SJeff Roberson 399a90f3f25SJeff Roberson return (NULL); 400a90f3f25SJeff Roberson } 4016804a3abSJulian Elischer 402d5a08a60SJake Burkholder /* 403b43179fbSJeff Roberson * Find the highest priority process on the run queue. 404d5a08a60SJake Burkholder */ 405ad1e7d28SJulian Elischer struct td_sched * 406d5a08a60SJake Burkholder runq_choose(struct runq *rq) 407d5a08a60SJake Burkholder { 408d5a08a60SJake Burkholder struct rqhead *rqh; 409ad1e7d28SJulian Elischer struct td_sched *ts; 410d5a08a60SJake Burkholder int pri; 411d5a08a60SJake Burkholder 412e602ba25SJulian Elischer while ((pri = runq_findbit(rq)) != -1) { 413d5a08a60SJake Burkholder rqh = &rq->rq_queues[pri]; 414ad1e7d28SJulian Elischer ts = TAILQ_FIRST(rqh); 415ad1e7d28SJulian Elischer KASSERT(ts != NULL, ("runq_choose: no proc on busy queue")); 416e602ba25SJulian Elischer CTR3(KTR_RUNQ, 417ad1e7d28SJulian Elischer "runq_choose: pri=%d td_sched=%p rqh=%p", pri, ts, rqh); 418ad1e7d28SJulian Elischer return (ts); 419d5a08a60SJake Burkholder } 420d5a08a60SJake Burkholder CTR1(KTR_RUNQ, "runq_choose: idleproc pri=%d", pri); 421d5a08a60SJake Burkholder 422e602ba25SJulian Elischer return (NULL); 423d5a08a60SJake Burkholder } 424d5a08a60SJake Burkholder 4253fed7d23SJeff Roberson struct td_sched * 426ed0e8f2fSJeff Roberson runq_choose_from(struct runq *rq, u_char idx) 4273fed7d23SJeff Roberson { 4283fed7d23SJeff Roberson struct rqhead *rqh; 4293fed7d23SJeff Roberson struct td_sched *ts; 4303fed7d23SJeff Roberson int pri; 4313fed7d23SJeff Roberson 432cd49bb70SJeff Roberson if ((pri = runq_findbit_from(rq, idx)) != -1) { 4333fed7d23SJeff Roberson rqh = &rq->rq_queues[pri]; 4343fed7d23SJeff Roberson ts = TAILQ_FIRST(rqh); 4353fed7d23SJeff Roberson KASSERT(ts != NULL, ("runq_choose: no proc on busy queue")); 4363fed7d23SJeff Roberson CTR4(KTR_RUNQ, 4376617724cSJeff Roberson "runq_choose_from: pri=%d td_sched=%p idx=%d rqh=%p", 4383fed7d23SJeff Roberson pri, ts, ts->ts_rqindex, rqh); 4393fed7d23SJeff Roberson return (ts); 4403fed7d23SJeff Roberson } 4413fed7d23SJeff Roberson CTR1(KTR_RUNQ, "runq_choose_from: idleproc pri=%d", pri); 4423fed7d23SJeff Roberson 4433fed7d23SJeff Roberson return (NULL); 4443fed7d23SJeff Roberson } 445d5a08a60SJake Burkholder /* 446ad1e7d28SJulian Elischer * Remove the thread from the queue specified by its priority, and clear the 447d5a08a60SJake Burkholder * corresponding status bit if the queue becomes empty. 448f0393f06SJeff Roberson * Caller must set state afterwards. 449d5a08a60SJake Burkholder */ 450d5a08a60SJake Burkholder void 451ad1e7d28SJulian Elischer runq_remove(struct runq *rq, struct td_sched *ts) 452d5a08a60SJake Burkholder { 4533fed7d23SJeff Roberson 4543fed7d23SJeff Roberson runq_remove_idx(rq, ts, NULL); 4553fed7d23SJeff Roberson } 4563fed7d23SJeff Roberson 4573fed7d23SJeff Roberson void 458ed0e8f2fSJeff Roberson runq_remove_idx(struct runq *rq, struct td_sched *ts, u_char *idx) 4593fed7d23SJeff Roberson { 460d5a08a60SJake Burkholder struct rqhead *rqh; 461ed0e8f2fSJeff Roberson u_char pri; 462d5a08a60SJake Burkholder 463b61ce5b0SJeff Roberson KASSERT(ts->ts_thread->td_flags & TDF_INMEM, 464b61ce5b0SJeff Roberson ("runq_remove_idx: thread swapped out")); 465ad1e7d28SJulian Elischer pri = ts->ts_rqindex; 4667b20fb19SJeff Roberson KASSERT(pri < RQ_NQS, ("runq_remove_idx: Invalid index %d\n", pri)); 467d5a08a60SJake Burkholder rqh = &rq->rq_queues[pri]; 4683fed7d23SJeff Roberson CTR5(KTR_RUNQ, "runq_remove_idx: td=%p, ts=%p pri=%d %d rqh=%p", 469ad1e7d28SJulian Elischer ts->ts_thread, ts, ts->ts_thread->td_priority, pri, rqh); 4707b20fb19SJeff Roberson { 4717b20fb19SJeff Roberson struct td_sched *nts; 4727b20fb19SJeff Roberson 4737b20fb19SJeff Roberson TAILQ_FOREACH(nts, rqh, ts_procq) 4747b20fb19SJeff Roberson if (nts == ts) 4757b20fb19SJeff Roberson break; 4767b20fb19SJeff Roberson if (ts != nts) 4777b20fb19SJeff Roberson panic("runq_remove_idx: ts %p not on rqindex %d", 4787b20fb19SJeff Roberson ts, pri); 4797b20fb19SJeff Roberson } 480ad1e7d28SJulian Elischer TAILQ_REMOVE(rqh, ts, ts_procq); 481d5a08a60SJake Burkholder if (TAILQ_EMPTY(rqh)) { 4823fed7d23SJeff Roberson CTR0(KTR_RUNQ, "runq_remove_idx: empty"); 483d5a08a60SJake Burkholder runq_clrbit(rq, pri); 4843fed7d23SJeff Roberson if (idx != NULL && *idx == pri) 4853fed7d23SJeff Roberson *idx = (pri + 1) % RQ_NQS; 486d5a08a60SJake Burkholder } 487dba6c5a6SPeter Wemm } 488e602ba25SJulian Elischer 489ed062c8dSJulian Elischer /****** functions that are temporarily here ***********/ 490ed062c8dSJulian Elischer #include <vm/uma.h> 491ed062c8dSJulian Elischer 492ed062c8dSJulian Elischer /* 493ed062c8dSJulian Elischer * Allocate scheduler specific per-process resources. 494ad1e7d28SJulian Elischer * The thread and proc have already been linked in. 495ed062c8dSJulian Elischer * 496ed062c8dSJulian Elischer * Called from: 497ed062c8dSJulian Elischer * proc_init() (UMA init method) 498ed062c8dSJulian Elischer */ 499ed062c8dSJulian Elischer void 500ad1e7d28SJulian Elischer sched_newproc(struct proc *p, struct thread *td) 501ed062c8dSJulian Elischer { 502ed062c8dSJulian Elischer } 503ed062c8dSJulian Elischer 504ed062c8dSJulian Elischer /* 505ed062c8dSJulian Elischer * thread is being either created or recycled. 506ed062c8dSJulian Elischer * Fix up the per-scheduler resources associated with it. 507ed062c8dSJulian Elischer * Called from: 508ed062c8dSJulian Elischer * sched_fork_thread() 509ed062c8dSJulian Elischer * thread_dtor() (*may go away) 510ed062c8dSJulian Elischer * thread_init() (*may go away) 511ed062c8dSJulian Elischer */ 512ed062c8dSJulian Elischer void 513ed062c8dSJulian Elischer sched_newthread(struct thread *td) 514ed062c8dSJulian Elischer { 515ad1e7d28SJulian Elischer struct td_sched *ts; 516ed062c8dSJulian Elischer 517ad1e7d28SJulian Elischer ts = (struct td_sched *) (td + 1); 518ad1e7d28SJulian Elischer bzero(ts, sizeof(*ts)); 519ad1e7d28SJulian Elischer td->td_sched = ts; 520ad1e7d28SJulian Elischer ts->ts_thread = td; 521ed062c8dSJulian Elischer } 522ed062c8dSJulian Elischer 523ed062c8dSJulian Elischer #endif /* KERN_SWITCH_INCLUDE */ 524