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 #if defined(SMP) && defined(SCHED_4BSD) 496804a3abSJulian Elischer #include <sys/sysctl.h> 506804a3abSJulian Elischer #endif 516804a3abSJulian Elischer 521335c4dfSNate Lawson /* Uncomment this to enable logging of critical_enter/exit. */ 531335c4dfSNate Lawson #if 0 541335c4dfSNate Lawson #define KTR_CRITICAL KTR_SCHED 551335c4dfSNate Lawson #else 561335c4dfSNate Lawson #define KTR_CRITICAL 0 571335c4dfSNate Lawson #endif 581335c4dfSNate Lawson 599923b511SScott Long #ifdef FULL_PREEMPTION 609923b511SScott Long #ifndef PREEMPTION 619923b511SScott Long #error "The FULL_PREEMPTION option requires the PREEMPTION option" 629923b511SScott Long #endif 639923b511SScott Long #endif 64dba6c5a6SPeter Wemm 65d2ac2316SJake Burkholder CTASSERT((RQB_BPW * RQB_LEN) == RQ_NQS); 66d2ac2316SJake Burkholder 676220dcbaSRobert Watson /* 686220dcbaSRobert Watson * kern.sched.preemption allows user space to determine if preemption support 696220dcbaSRobert Watson * is compiled in or not. It is not currently a boot or runtime flag that 706220dcbaSRobert Watson * can be changed. 716220dcbaSRobert Watson */ 726220dcbaSRobert Watson #ifdef PREEMPTION 736220dcbaSRobert Watson static int kern_sched_preemption = 1; 746220dcbaSRobert Watson #else 756220dcbaSRobert Watson static int kern_sched_preemption = 0; 766220dcbaSRobert Watson #endif 776220dcbaSRobert Watson SYSCTL_INT(_kern_sched, OID_AUTO, preemption, CTLFLAG_RD, 786220dcbaSRobert Watson &kern_sched_preemption, 0, "Kernel preemption enabled"); 796220dcbaSRobert Watson 80e602ba25SJulian Elischer /************************************************************************ 81e602ba25SJulian Elischer * Functions that manipulate runnability from a thread perspective. * 82e602ba25SJulian Elischer ************************************************************************/ 838460a577SJohn Birrell /* 848460a577SJohn Birrell * Select the thread that will be run next. 858460a577SJohn Birrell */ 86b40ce416SJulian Elischer struct thread * 87b40ce416SJulian Elischer choosethread(void) 88dba6c5a6SPeter Wemm { 89ad1e7d28SJulian Elischer struct td_sched *ts; 90e602ba25SJulian Elischer struct thread *td; 91e602ba25SJulian Elischer 920d2a2989SPeter Wemm #if defined(SMP) && (defined(__i386__) || defined(__amd64__)) 93cc66ebe2SPeter Wemm if (smp_active == 0 && PCPU_GET(cpuid) != 0) { 94cc66ebe2SPeter Wemm /* Shutting down, run idlethread on AP's */ 95cc66ebe2SPeter Wemm td = PCPU_GET(idlethread); 96ad1e7d28SJulian Elischer ts = td->td_sched; 97cc66ebe2SPeter Wemm CTR1(KTR_RUNQ, "choosethread: td=%p (idle)", td); 98ad1e7d28SJulian Elischer ts->ts_flags |= TSF_DIDRUN; 99cc66ebe2SPeter Wemm TD_SET_RUNNING(td); 100cc66ebe2SPeter Wemm return (td); 101cc66ebe2SPeter Wemm } 102cc66ebe2SPeter Wemm #endif 103cc66ebe2SPeter Wemm 104fe799533SAndrew Gallatin retry: 105ad1e7d28SJulian Elischer ts = sched_choose(); 106ad1e7d28SJulian Elischer if (ts) { 107ad1e7d28SJulian Elischer td = ts->ts_thread; 108e602ba25SJulian Elischer CTR2(KTR_RUNQ, "choosethread: td=%p pri=%d", 109e602ba25SJulian Elischer td, td->td_priority); 110e602ba25SJulian Elischer } else { 11140e55026SJulian Elischer /* Simulate runq_choose() having returned the idle thread */ 112e602ba25SJulian Elischer td = PCPU_GET(idlethread); 113ad1e7d28SJulian Elischer ts = td->td_sched; 114e602ba25SJulian Elischer CTR1(KTR_RUNQ, "choosethread: td=%p (idle)", td); 115e602ba25SJulian Elischer } 116ad1e7d28SJulian Elischer ts->ts_flags |= TSF_DIDRUN; 11793a7aa79SJulian Elischer 11893a7aa79SJulian Elischer /* 119faaa20f6SJulian Elischer * If we are in panic, only allow system threads, 120faaa20f6SJulian Elischer * plus the one we are running in, to be run. 12193a7aa79SJulian Elischer */ 122fe799533SAndrew Gallatin if (panicstr && ((td->td_proc->p_flag & P_SYSTEM) == 0 && 123faaa20f6SJulian Elischer (td->td_flags & TDF_INPANIC) == 0)) { 124faaa20f6SJulian Elischer /* note that it is no longer on the run queue */ 125faaa20f6SJulian Elischer TD_SET_CAN_RUN(td); 126fe799533SAndrew Gallatin goto retry; 127faaa20f6SJulian Elischer } 12893a7aa79SJulian Elischer 12971fad9fdSJulian Elischer TD_SET_RUNNING(td); 130e602ba25SJulian Elischer return (td); 131e602ba25SJulian Elischer } 132e602ba25SJulian Elischer 133e602ba25SJulian Elischer 134ad1e7d28SJulian Elischer #if 0 135e602ba25SJulian Elischer /* 136ad1e7d28SJulian Elischer * currently not used.. threads remove themselves from the 137ad1e7d28SJulian Elischer * run queue by running. 138e602ba25SJulian Elischer */ 1391f955e2dSJulian Elischer static void 140b40ce416SJulian Elischer remrunqueue(struct thread *td) 141d5a08a60SJake Burkholder { 142e602ba25SJulian Elischer mtx_assert(&sched_lock, MA_OWNED); 14371fad9fdSJulian Elischer KASSERT((TD_ON_RUNQ(td)), ("remrunqueue: Bad state on run queue")); 144e602ba25SJulian Elischer CTR1(KTR_RUNQ, "remrunqueue: td%p", td); 14571fad9fdSJulian Elischer TD_SET_CAN_RUN(td); 146ad1e7d28SJulian Elischer /* remove from sys run queue */ 1477cf90fb3SJeff Roberson sched_rem(td); 148e602ba25SJulian Elischer return; 149d5a08a60SJake Burkholder } 1508460a577SJohn Birrell #endif 1511f955e2dSJulian Elischer 1521f955e2dSJulian Elischer /* 1531f955e2dSJulian Elischer * Change the priority of a thread that is on the run queue. 1541f955e2dSJulian Elischer */ 1551f955e2dSJulian Elischer void 1561f955e2dSJulian Elischer adjustrunqueue( struct thread *td, int newpri) 1571f955e2dSJulian Elischer { 158ad1e7d28SJulian Elischer struct td_sched *ts; 1591f955e2dSJulian Elischer 1601f955e2dSJulian Elischer mtx_assert(&sched_lock, MA_OWNED); 1611f955e2dSJulian Elischer KASSERT((TD_ON_RUNQ(td)), ("adjustrunqueue: Bad state on run queue")); 1625215b187SJeff Roberson 163ad1e7d28SJulian Elischer ts = td->td_sched; 1641f955e2dSJulian Elischer CTR1(KTR_RUNQ, "adjustrunqueue: td%p", td); 165ad1e7d28SJulian Elischer /* We only care about the td_sched in the run queue. */ 16624c5baaeSJulian Elischer td->td_priority = newpri; 167b41f1452SDavid Xu #ifndef SCHED_CORE 168ad1e7d28SJulian Elischer if (ts->ts_rqindex != (newpri / RQ_PPQ)) 169b41f1452SDavid Xu #else 170ad1e7d28SJulian Elischer if (ts->ts_rqindex != newpri) 171b41f1452SDavid Xu #endif 172b41f1452SDavid Xu { 1737cf90fb3SJeff Roberson sched_rem(td); 1742630e4c9SJulian Elischer sched_add(td, SRQ_BORING); 1751f955e2dSJulian Elischer } 1761f955e2dSJulian Elischer } 1775215b187SJeff Roberson 178d5a08a60SJake Burkholder void 1792630e4c9SJulian Elischer setrunqueue(struct thread *td, int flags) 180d5a08a60SJake Burkholder { 181e602ba25SJulian Elischer 1828460a577SJohn Birrell CTR2(KTR_RUNQ, "setrunqueue: td:%p pid:%d", 1838460a577SJohn Birrell td, td->td_proc->p_pid); 18485da7a56SJeff Roberson CTR5(KTR_SCHED, "setrunqueue: %p(%s) prio %d by %p(%s)", 18585da7a56SJeff Roberson td, td->td_proc->p_comm, td->td_priority, curthread, 18685da7a56SJeff Roberson curthread->td_proc->p_comm); 187e602ba25SJulian Elischer mtx_assert(&sched_lock, MA_OWNED); 188b2578c6cSJulian Elischer KASSERT((td->td_inhibitors == 0), 189b2578c6cSJulian Elischer ("setrunqueue: trying to run inhibitted thread")); 19071fad9fdSJulian Elischer KASSERT((TD_CAN_RUN(td) || TD_IS_RUNNING(td)), 19171fad9fdSJulian Elischer ("setrunqueue: bad thread state")); 19271fad9fdSJulian Elischer TD_SET_RUNQ(td); 1932630e4c9SJulian Elischer sched_add(td, flags); 194e602ba25SJulian Elischer } 195e602ba25SJulian Elischer 1960c0b25aeSJohn Baldwin /* 1970c0b25aeSJohn Baldwin * Kernel thread preemption implementation. Critical sections mark 1980c0b25aeSJohn Baldwin * regions of code in which preemptions are not allowed. 1990c0b25aeSJohn Baldwin */ 2007e1f6dfeSJohn Baldwin void 2017e1f6dfeSJohn Baldwin critical_enter(void) 2027e1f6dfeSJohn Baldwin { 2037e1f6dfeSJohn Baldwin struct thread *td; 2047e1f6dfeSJohn Baldwin 2057e1f6dfeSJohn Baldwin td = curthread; 2067e1f6dfeSJohn Baldwin td->td_critnest++; 2071335c4dfSNate Lawson CTR4(KTR_CRITICAL, "critical_enter by thread %p (%ld, %s) to %d", td, 208f42a43faSRobert Watson (long)td->td_proc->p_pid, td->td_proc->p_comm, td->td_critnest); 2097e1f6dfeSJohn Baldwin } 2107e1f6dfeSJohn Baldwin 2117e1f6dfeSJohn Baldwin void 2127e1f6dfeSJohn Baldwin critical_exit(void) 2137e1f6dfeSJohn Baldwin { 2147e1f6dfeSJohn Baldwin struct thread *td; 2157e1f6dfeSJohn Baldwin 2167e1f6dfeSJohn Baldwin td = curthread; 217b209e5e3SJeff Roberson KASSERT(td->td_critnest != 0, 218b209e5e3SJeff Roberson ("critical_exit: td_critnest == 0")); 2190c0b25aeSJohn Baldwin #ifdef PREEMPTION 220d13ec713SStephan Uphoff if (td->td_critnest == 1) { 221d13ec713SStephan Uphoff td->td_critnest = 0; 22252eb8464SJohn Baldwin mtx_assert(&sched_lock, MA_NOTOWNED); 22377918643SStephan Uphoff if (td->td_owepreempt) { 22477918643SStephan Uphoff td->td_critnest = 1; 2250c0b25aeSJohn Baldwin mtx_lock_spin(&sched_lock); 22677918643SStephan Uphoff td->td_critnest--; 2270c0b25aeSJohn Baldwin mi_switch(SW_INVOL, NULL); 2280c0b25aeSJohn Baldwin mtx_unlock_spin(&sched_lock); 2290c0b25aeSJohn Baldwin } 230d13ec713SStephan Uphoff } else 2310c0b25aeSJohn Baldwin #endif 2327e1f6dfeSJohn Baldwin td->td_critnest--; 233d13ec713SStephan Uphoff 2341335c4dfSNate Lawson CTR4(KTR_CRITICAL, "critical_exit by thread %p (%ld, %s) to %d", td, 235f42a43faSRobert Watson (long)td->td_proc->p_pid, td->td_proc->p_comm, td->td_critnest); 236d74ac681SMatthew Dillon } 2377e1f6dfeSJohn Baldwin 2380c0b25aeSJohn Baldwin /* 2390c0b25aeSJohn Baldwin * This function is called when a thread is about to be put on run queue 2400c0b25aeSJohn Baldwin * because it has been made runnable or its priority has been adjusted. It 2410c0b25aeSJohn Baldwin * determines if the new thread should be immediately preempted to. If so, 2420c0b25aeSJohn Baldwin * it switches to it and eventually returns true. If not, it returns false 2430c0b25aeSJohn Baldwin * so that the caller may place the thread on an appropriate run queue. 2440c0b25aeSJohn Baldwin */ 2450c0b25aeSJohn Baldwin int 2460c0b25aeSJohn Baldwin maybe_preempt(struct thread *td) 2470c0b25aeSJohn Baldwin { 2488b44a2e2SMarcel Moolenaar #ifdef PREEMPTION 2490c0b25aeSJohn Baldwin struct thread *ctd; 2500c0b25aeSJohn Baldwin int cpri, pri; 2518b44a2e2SMarcel Moolenaar #endif 2520c0b25aeSJohn Baldwin 2530c0b25aeSJohn Baldwin mtx_assert(&sched_lock, MA_OWNED); 2540c0b25aeSJohn Baldwin #ifdef PREEMPTION 2550c0b25aeSJohn Baldwin /* 2560c0b25aeSJohn Baldwin * The new thread should not preempt the current thread if any of the 2570c0b25aeSJohn Baldwin * following conditions are true: 2580c0b25aeSJohn Baldwin * 259bc608306SRobert Watson * - The kernel is in the throes of crashing (panicstr). 26052eb8464SJohn Baldwin * - The current thread has a higher (numerically lower) or 26152eb8464SJohn Baldwin * equivalent priority. Note that this prevents curthread from 26252eb8464SJohn Baldwin * trying to preempt to itself. 2630c0b25aeSJohn Baldwin * - It is too early in the boot for context switches (cold is set). 2640c0b25aeSJohn Baldwin * - The current thread has an inhibitor set or is in the process of 2650c0b25aeSJohn Baldwin * exiting. In this case, the current thread is about to switch 2660c0b25aeSJohn Baldwin * out anyways, so there's no point in preempting. If we did, 2670c0b25aeSJohn Baldwin * the current thread would not be properly resumed as well, so 2680c0b25aeSJohn Baldwin * just avoid that whole landmine. 2690c0b25aeSJohn Baldwin * - If the new thread's priority is not a realtime priority and 2700c0b25aeSJohn Baldwin * the current thread's priority is not an idle priority and 2710c0b25aeSJohn Baldwin * FULL_PREEMPTION is disabled. 2720c0b25aeSJohn Baldwin * 2730c0b25aeSJohn Baldwin * If all of these conditions are false, but the current thread is in 2740c0b25aeSJohn Baldwin * a nested critical section, then we have to defer the preemption 2750c0b25aeSJohn Baldwin * until we exit the critical section. Otherwise, switch immediately 2760c0b25aeSJohn Baldwin * to the new thread. 2770c0b25aeSJohn Baldwin */ 2780c0b25aeSJohn Baldwin ctd = curthread; 279ad1e7d28SJulian Elischer KASSERT ((ctd->td_sched != NULL && ctd->td_sched->ts_thread == ctd), 2806a574b2aSJulian Elischer ("thread has no (or wrong) sched-private part.")); 281b2578c6cSJulian Elischer KASSERT((td->td_inhibitors == 0), 282b2578c6cSJulian Elischer ("maybe_preempt: trying to run inhibitted thread")); 2830c0b25aeSJohn Baldwin pri = td->td_priority; 2840c0b25aeSJohn Baldwin cpri = ctd->td_priority; 285bc608306SRobert Watson if (panicstr != NULL || pri >= cpri || cold /* || dumping */ || 286ad1e7d28SJulian Elischer TD_IS_INHIBITED(ctd) || td->td_sched->ts_state != TSS_THREAD) 2870c0b25aeSJohn Baldwin return (0); 2880c0b25aeSJohn Baldwin #ifndef FULL_PREEMPTION 2893ea6bbc5SStephan Uphoff if (pri > PRI_MAX_ITHD && cpri < PRI_MIN_IDLE) 2900c0b25aeSJohn Baldwin return (0); 2910c0b25aeSJohn Baldwin #endif 292a3f2d842SStephan Uphoff 2930c0b25aeSJohn Baldwin if (ctd->td_critnest > 1) { 2940c0b25aeSJohn Baldwin CTR1(KTR_PROC, "maybe_preempt: in critical section %d", 2950c0b25aeSJohn Baldwin ctd->td_critnest); 29677918643SStephan Uphoff ctd->td_owepreempt = 1; 2970c0b25aeSJohn Baldwin return (0); 2980c0b25aeSJohn Baldwin } 2990c0b25aeSJohn Baldwin 3000c0b25aeSJohn Baldwin /* 301c20c691bSJulian Elischer * Thread is runnable but not yet put on system run queue. 3020c0b25aeSJohn Baldwin */ 3030c0b25aeSJohn Baldwin MPASS(TD_ON_RUNQ(td)); 304ad1e7d28SJulian Elischer MPASS(td->td_sched->ts_state != TSS_ONRUNQ); 3050c0b25aeSJohn Baldwin TD_SET_RUNNING(td); 3060c0b25aeSJohn Baldwin CTR3(KTR_PROC, "preempting to thread %p (pid %d, %s)\n", td, 3070c0b25aeSJohn Baldwin td->td_proc->p_pid, td->td_proc->p_comm); 308c20c691bSJulian Elischer mi_switch(SW_INVOL|SW_PREEMPT, td); 3090c0b25aeSJohn Baldwin return (1); 3100c0b25aeSJohn Baldwin #else 3110c0b25aeSJohn Baldwin return (0); 3120c0b25aeSJohn Baldwin #endif 3130c0b25aeSJohn Baldwin } 3140c0b25aeSJohn Baldwin 31544fe3c1fSJohn Baldwin #if 0 3160c0b25aeSJohn Baldwin #ifndef PREEMPTION 3170c0b25aeSJohn Baldwin /* XXX: There should be a non-static version of this. */ 3180c0b25aeSJohn Baldwin static void 3190c0b25aeSJohn Baldwin printf_caddr_t(void *data) 3200c0b25aeSJohn Baldwin { 3210c0b25aeSJohn Baldwin printf("%s", (char *)data); 3220c0b25aeSJohn Baldwin } 3230c0b25aeSJohn Baldwin static char preempt_warning[] = 3240c0b25aeSJohn Baldwin "WARNING: Kernel preemption is disabled, expect reduced performance.\n"; 3250c0b25aeSJohn Baldwin SYSINIT(preempt_warning, SI_SUB_COPYRIGHT, SI_ORDER_ANY, printf_caddr_t, 3260c0b25aeSJohn Baldwin preempt_warning) 3270c0b25aeSJohn Baldwin #endif 32844fe3c1fSJohn Baldwin #endif 329e602ba25SJulian Elischer 330e602ba25SJulian Elischer /************************************************************************ 331e602ba25SJulian Elischer * SYSTEM RUN QUEUE manipulations and tests * 332e602ba25SJulian Elischer ************************************************************************/ 333e602ba25SJulian Elischer /* 334e602ba25SJulian Elischer * Initialize a run structure. 335e602ba25SJulian Elischer */ 336e602ba25SJulian Elischer void 337e602ba25SJulian Elischer runq_init(struct runq *rq) 338e602ba25SJulian Elischer { 339e602ba25SJulian Elischer int i; 340e602ba25SJulian Elischer 341e602ba25SJulian Elischer bzero(rq, sizeof *rq); 342e602ba25SJulian Elischer for (i = 0; i < RQ_NQS; i++) 343e602ba25SJulian Elischer TAILQ_INIT(&rq->rq_queues[i]); 344e602ba25SJulian Elischer } 345e602ba25SJulian Elischer 346d5a08a60SJake Burkholder /* 347d5a08a60SJake Burkholder * Clear the status bit of the queue corresponding to priority level pri, 348d5a08a60SJake Burkholder * indicating that it is empty. 349d5a08a60SJake Burkholder */ 350d5a08a60SJake Burkholder static __inline void 351d5a08a60SJake Burkholder runq_clrbit(struct runq *rq, int pri) 352d5a08a60SJake Burkholder { 353d5a08a60SJake Burkholder struct rqbits *rqb; 354d5a08a60SJake Burkholder 355d5a08a60SJake Burkholder rqb = &rq->rq_status; 356d5a08a60SJake Burkholder CTR4(KTR_RUNQ, "runq_clrbit: bits=%#x %#x bit=%#x word=%d", 357d5a08a60SJake Burkholder rqb->rqb_bits[RQB_WORD(pri)], 358d5a08a60SJake Burkholder rqb->rqb_bits[RQB_WORD(pri)] & ~RQB_BIT(pri), 359d5a08a60SJake Burkholder RQB_BIT(pri), RQB_WORD(pri)); 360d5a08a60SJake Burkholder rqb->rqb_bits[RQB_WORD(pri)] &= ~RQB_BIT(pri); 361d5a08a60SJake Burkholder } 362d5a08a60SJake Burkholder 363d5a08a60SJake Burkholder /* 364d5a08a60SJake Burkholder * Find the index of the first non-empty run queue. This is done by 365d5a08a60SJake Burkholder * scanning the status bits, a set bit indicates a non-empty queue. 366d5a08a60SJake Burkholder */ 367d5a08a60SJake Burkholder static __inline int 368d5a08a60SJake Burkholder runq_findbit(struct runq *rq) 369d5a08a60SJake Burkholder { 370d5a08a60SJake Burkholder struct rqbits *rqb; 371d5a08a60SJake Burkholder int pri; 372d5a08a60SJake Burkholder int i; 373d5a08a60SJake Burkholder 374d5a08a60SJake Burkholder rqb = &rq->rq_status; 375d5a08a60SJake Burkholder for (i = 0; i < RQB_LEN; i++) 376d5a08a60SJake Burkholder if (rqb->rqb_bits[i]) { 3772f9267ecSPeter Wemm pri = RQB_FFS(rqb->rqb_bits[i]) + (i << RQB_L2BPW); 378d5a08a60SJake Burkholder CTR3(KTR_RUNQ, "runq_findbit: bits=%#x i=%d pri=%d", 379d5a08a60SJake Burkholder rqb->rqb_bits[i], i, pri); 380d5a08a60SJake Burkholder return (pri); 381d5a08a60SJake Burkholder } 382d5a08a60SJake Burkholder 383d5a08a60SJake Burkholder return (-1); 384d5a08a60SJake Burkholder } 385d5a08a60SJake Burkholder 386d5a08a60SJake Burkholder /* 387d5a08a60SJake Burkholder * Set the status bit of the queue corresponding to priority level pri, 388d5a08a60SJake Burkholder * indicating that it is non-empty. 389d5a08a60SJake Burkholder */ 390d5a08a60SJake Burkholder static __inline void 391d5a08a60SJake Burkholder runq_setbit(struct runq *rq, int pri) 392d5a08a60SJake Burkholder { 393d5a08a60SJake Burkholder struct rqbits *rqb; 394d5a08a60SJake Burkholder 395d5a08a60SJake Burkholder rqb = &rq->rq_status; 396d5a08a60SJake Burkholder CTR4(KTR_RUNQ, "runq_setbit: bits=%#x %#x bit=%#x word=%d", 397d5a08a60SJake Burkholder rqb->rqb_bits[RQB_WORD(pri)], 398d5a08a60SJake Burkholder rqb->rqb_bits[RQB_WORD(pri)] | RQB_BIT(pri), 399d5a08a60SJake Burkholder RQB_BIT(pri), RQB_WORD(pri)); 400d5a08a60SJake Burkholder rqb->rqb_bits[RQB_WORD(pri)] |= RQB_BIT(pri); 401d5a08a60SJake Burkholder } 402d5a08a60SJake Burkholder 403d5a08a60SJake Burkholder /* 404ad1e7d28SJulian Elischer * Add the thread to the queue specified by its priority, and set the 405d5a08a60SJake Burkholder * corresponding status bit. 406d5a08a60SJake Burkholder */ 407d5a08a60SJake Burkholder void 408ad1e7d28SJulian Elischer runq_add(struct runq *rq, struct td_sched *ts, int flags) 409d5a08a60SJake Burkholder { 410d5a08a60SJake Burkholder struct rqhead *rqh; 411d5a08a60SJake Burkholder int pri; 412dba6c5a6SPeter Wemm 413ad1e7d28SJulian Elischer pri = ts->ts_thread->td_priority / RQ_PPQ; 414ad1e7d28SJulian Elischer ts->ts_rqindex = pri; 415d5a08a60SJake Burkholder runq_setbit(rq, pri); 416d5a08a60SJake Burkholder rqh = &rq->rq_queues[pri]; 417ad1e7d28SJulian Elischer CTR5(KTR_RUNQ, "runq_add: td=%p ts=%p pri=%d %d rqh=%p", 418ad1e7d28SJulian Elischer ts->ts_thread, ts, ts->ts_thread->td_priority, pri, rqh); 419c20c691bSJulian Elischer if (flags & SRQ_PREEMPTED) { 420ad1e7d28SJulian Elischer TAILQ_INSERT_HEAD(rqh, ts, ts_procq); 421c20c691bSJulian Elischer } else { 422ad1e7d28SJulian Elischer TAILQ_INSERT_TAIL(rqh, ts, ts_procq); 423dba6c5a6SPeter Wemm } 424c20c691bSJulian Elischer } 425d5a08a60SJake Burkholder 426d5a08a60SJake Burkholder /* 427d5a08a60SJake Burkholder * Return true if there are runnable processes of any priority on the run 428d5a08a60SJake Burkholder * queue, false otherwise. Has no side effects, does not modify the run 429d5a08a60SJake Burkholder * queue structure. 430d5a08a60SJake Burkholder */ 431d5a08a60SJake Burkholder int 432d5a08a60SJake Burkholder runq_check(struct runq *rq) 433d5a08a60SJake Burkholder { 434d5a08a60SJake Burkholder struct rqbits *rqb; 435d5a08a60SJake Burkholder int i; 436d5a08a60SJake Burkholder 437d5a08a60SJake Burkholder rqb = &rq->rq_status; 438d5a08a60SJake Burkholder for (i = 0; i < RQB_LEN; i++) 439d5a08a60SJake Burkholder if (rqb->rqb_bits[i]) { 440d5a08a60SJake Burkholder CTR2(KTR_RUNQ, "runq_check: bits=%#x i=%d", 441d5a08a60SJake Burkholder rqb->rqb_bits[i], i); 442d5a08a60SJake Burkholder return (1); 443dba6c5a6SPeter Wemm } 444d5a08a60SJake Burkholder CTR0(KTR_RUNQ, "runq_check: empty"); 445d5a08a60SJake Burkholder 446d5a08a60SJake Burkholder return (0); 447dba6c5a6SPeter Wemm } 448d5a08a60SJake Burkholder 4496804a3abSJulian Elischer #if defined(SMP) && defined(SCHED_4BSD) 4506804a3abSJulian Elischer int runq_fuzz = 1; 4516804a3abSJulian Elischer SYSCTL_INT(_kern_sched, OID_AUTO, runq_fuzz, CTLFLAG_RW, &runq_fuzz, 0, ""); 4526804a3abSJulian Elischer #endif 4536804a3abSJulian Elischer 454d5a08a60SJake Burkholder /* 455b43179fbSJeff Roberson * Find the highest priority process on the run queue. 456d5a08a60SJake Burkholder */ 457ad1e7d28SJulian Elischer struct td_sched * 458d5a08a60SJake Burkholder runq_choose(struct runq *rq) 459d5a08a60SJake Burkholder { 460d5a08a60SJake Burkholder struct rqhead *rqh; 461ad1e7d28SJulian Elischer struct td_sched *ts; 462d5a08a60SJake Burkholder int pri; 463d5a08a60SJake Burkholder 464d5a08a60SJake Burkholder mtx_assert(&sched_lock, MA_OWNED); 465e602ba25SJulian Elischer while ((pri = runq_findbit(rq)) != -1) { 466d5a08a60SJake Burkholder rqh = &rq->rq_queues[pri]; 4676804a3abSJulian Elischer #if defined(SMP) && defined(SCHED_4BSD) 4686804a3abSJulian Elischer /* fuzz == 1 is normal.. 0 or less are ignored */ 4696804a3abSJulian Elischer if (runq_fuzz > 1) { 4706804a3abSJulian Elischer /* 4716804a3abSJulian Elischer * In the first couple of entries, check if 4726804a3abSJulian Elischer * there is one for our CPU as a preference. 4736804a3abSJulian Elischer */ 4746804a3abSJulian Elischer int count = runq_fuzz; 4756804a3abSJulian Elischer int cpu = PCPU_GET(cpuid); 476ad1e7d28SJulian Elischer struct td_sched *ts2; 477ad1e7d28SJulian Elischer ts2 = ts = TAILQ_FIRST(rqh); 4786804a3abSJulian Elischer 479ad1e7d28SJulian Elischer while (count-- && ts2) { 480ad1e7d28SJulian Elischer if (ts->ts_thread->td_lastcpu == cpu) { 481ad1e7d28SJulian Elischer ts = ts2; 4826804a3abSJulian Elischer break; 4836804a3abSJulian Elischer } 484ad1e7d28SJulian Elischer ts2 = TAILQ_NEXT(ts2, ts_procq); 4856804a3abSJulian Elischer } 4866804a3abSJulian Elischer } else 4876804a3abSJulian Elischer #endif 488ad1e7d28SJulian Elischer ts = TAILQ_FIRST(rqh); 489ad1e7d28SJulian Elischer KASSERT(ts != NULL, ("runq_choose: no proc on busy queue")); 490e602ba25SJulian Elischer CTR3(KTR_RUNQ, 491ad1e7d28SJulian Elischer "runq_choose: pri=%d td_sched=%p rqh=%p", pri, ts, rqh); 492ad1e7d28SJulian Elischer return (ts); 493d5a08a60SJake Burkholder } 494d5a08a60SJake Burkholder CTR1(KTR_RUNQ, "runq_choose: idleproc pri=%d", pri); 495d5a08a60SJake Burkholder 496e602ba25SJulian Elischer return (NULL); 497d5a08a60SJake Burkholder } 498d5a08a60SJake Burkholder 499d5a08a60SJake Burkholder /* 500ad1e7d28SJulian Elischer * Remove the thread from the queue specified by its priority, and clear the 501d5a08a60SJake Burkholder * corresponding status bit if the queue becomes empty. 502ad1e7d28SJulian Elischer * Caller must set ts->ts_state afterwards. 503d5a08a60SJake Burkholder */ 504d5a08a60SJake Burkholder void 505ad1e7d28SJulian Elischer runq_remove(struct runq *rq, struct td_sched *ts) 506d5a08a60SJake Burkholder { 507d5a08a60SJake Burkholder struct rqhead *rqh; 508d5a08a60SJake Burkholder int pri; 509d5a08a60SJake Burkholder 510ad1e7d28SJulian Elischer KASSERT(ts->ts_thread->td_proc->p_sflag & PS_INMEM, 5119eb881f8SSeigo Tanimura ("runq_remove: process swapped out")); 512ad1e7d28SJulian Elischer pri = ts->ts_rqindex; 513d5a08a60SJake Burkholder rqh = &rq->rq_queues[pri]; 514ad1e7d28SJulian Elischer CTR5(KTR_RUNQ, "runq_remove: td=%p, ts=%p pri=%d %d rqh=%p", 515ad1e7d28SJulian Elischer ts->ts_thread, ts, ts->ts_thread->td_priority, pri, rqh); 516ad1e7d28SJulian Elischer KASSERT(ts != NULL, ("runq_remove: no proc on busy queue")); 517ad1e7d28SJulian Elischer TAILQ_REMOVE(rqh, ts, ts_procq); 518d5a08a60SJake Burkholder if (TAILQ_EMPTY(rqh)) { 519d5a08a60SJake Burkholder CTR0(KTR_RUNQ, "runq_remove: empty"); 520d5a08a60SJake Burkholder runq_clrbit(rq, pri); 521d5a08a60SJake Burkholder } 522dba6c5a6SPeter Wemm } 523e602ba25SJulian Elischer 524ed062c8dSJulian Elischer /****** functions that are temporarily here ***********/ 525ed062c8dSJulian Elischer #include <vm/uma.h> 526ed062c8dSJulian Elischer extern struct mtx kse_zombie_lock; 527ed062c8dSJulian Elischer 528ed062c8dSJulian Elischer /* 529ed062c8dSJulian Elischer * Allocate scheduler specific per-process resources. 530ad1e7d28SJulian Elischer * The thread and proc have already been linked in. 531ed062c8dSJulian Elischer * 532ed062c8dSJulian Elischer * Called from: 533ed062c8dSJulian Elischer * proc_init() (UMA init method) 534ed062c8dSJulian Elischer */ 535ed062c8dSJulian Elischer void 536ad1e7d28SJulian Elischer sched_newproc(struct proc *p, struct thread *td) 537ed062c8dSJulian Elischer { 538ed062c8dSJulian Elischer } 539ed062c8dSJulian Elischer 540ed062c8dSJulian Elischer /* 541ed062c8dSJulian Elischer * thread is being either created or recycled. 542ed062c8dSJulian Elischer * Fix up the per-scheduler resources associated with it. 543ed062c8dSJulian Elischer * Called from: 544ed062c8dSJulian Elischer * sched_fork_thread() 545ed062c8dSJulian Elischer * thread_dtor() (*may go away) 546ed062c8dSJulian Elischer * thread_init() (*may go away) 547ed062c8dSJulian Elischer */ 548ed062c8dSJulian Elischer void 549ed062c8dSJulian Elischer sched_newthread(struct thread *td) 550ed062c8dSJulian Elischer { 551ad1e7d28SJulian Elischer struct td_sched *ts; 552ed062c8dSJulian Elischer 553ad1e7d28SJulian Elischer ts = (struct td_sched *) (td + 1); 554ad1e7d28SJulian Elischer bzero(ts, sizeof(*ts)); 555ad1e7d28SJulian Elischer td->td_sched = ts; 556ad1e7d28SJulian Elischer ts->ts_thread = td; 557ad1e7d28SJulian Elischer ts->ts_state = TSS_THREAD; 558ed062c8dSJulian Elischer } 559ed062c8dSJulian Elischer 560ed062c8dSJulian Elischer /* 561ed062c8dSJulian Elischer * Called from: 562ed062c8dSJulian Elischer * thr_create() 563ed062c8dSJulian Elischer * proc_init() (UMA) via sched_newproc() 564ed062c8dSJulian Elischer */ 565ed062c8dSJulian Elischer void 566ad1e7d28SJulian Elischer sched_init_concurrency(struct proc *p) 567ed062c8dSJulian Elischer { 568ed062c8dSJulian Elischer } 569ed062c8dSJulian Elischer 570ed062c8dSJulian Elischer /* 571ad1e7d28SJulian Elischer * Change the concurrency of an existing proc to N 572ed062c8dSJulian Elischer * Called from: 573ed062c8dSJulian Elischer * kse_create() 574ed062c8dSJulian Elischer * kse_exit() 575ed062c8dSJulian Elischer * thread_exit() 576ed062c8dSJulian Elischer * thread_single() 577ed062c8dSJulian Elischer */ 578ed062c8dSJulian Elischer void 579ad1e7d28SJulian Elischer sched_set_concurrency(struct proc *p, int concurrency) 580ed062c8dSJulian Elischer { 581ed062c8dSJulian Elischer } 582ed062c8dSJulian Elischer 583ed062c8dSJulian Elischer /* 584ed062c8dSJulian Elischer * Called from thread_exit() for all exiting thread 585ed062c8dSJulian Elischer * 586ed062c8dSJulian Elischer * Not to be confused with sched_exit_thread() 587ed062c8dSJulian Elischer * that is only called from thread_exit() for threads exiting 588ed062c8dSJulian Elischer * without the rest of the process exiting because it is also called from 589ed062c8dSJulian Elischer * sched_exit() and we wouldn't want to call it twice. 590ed062c8dSJulian Elischer * XXX This can probably be fixed. 591ed062c8dSJulian Elischer */ 592ed062c8dSJulian Elischer void 593ed062c8dSJulian Elischer sched_thread_exit(struct thread *td) 594ed062c8dSJulian Elischer { 595ed062c8dSJulian Elischer } 596ed062c8dSJulian Elischer 597ed062c8dSJulian Elischer #endif /* KERN_SWITCH_INCLUDE */ 598