1dba6c5a6SPeter Wemm /* 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 * $FreeBSD$ 27dba6c5a6SPeter Wemm */ 28dba6c5a6SPeter Wemm 29e602ba25SJulian Elischer /*** 30e602ba25SJulian Elischer 31e602ba25SJulian Elischer Here is the logic.. 32e602ba25SJulian Elischer 33e602ba25SJulian Elischer If there are N processors, then there are at most N KSEs (kernel 34e602ba25SJulian Elischer schedulable entities) working to process threads that belong to a 35e602ba25SJulian Elischer KSEGOUP (kg). If there are X of these KSEs actually running at the 36e602ba25SJulian Elischer moment in question, then there are at most M (N-X) of these KSEs on 37e602ba25SJulian Elischer the run queue, as running KSEs are not on the queue. 38e602ba25SJulian Elischer 39e602ba25SJulian Elischer Runnable threads are queued off the KSEGROUP in priority order. 40e602ba25SJulian Elischer If there are M or more threads runnable, the top M threads 41e602ba25SJulian Elischer (by priority) are 'preassigned' to the M KSEs not running. The KSEs take 42e602ba25SJulian Elischer their priority from those threads and are put on the run queue. 43e602ba25SJulian Elischer 44e602ba25SJulian Elischer The last thread that had a priority high enough to have a KSE associated 45e602ba25SJulian Elischer with it, AND IS ON THE RUN QUEUE is pointed to by 46e602ba25SJulian Elischer kg->kg_last_assigned. If no threads queued off the KSEGROUP have KSEs 47e602ba25SJulian Elischer assigned as all the available KSEs are activly running, or because there 48e602ba25SJulian Elischer are no threads queued, that pointer is NULL. 49e602ba25SJulian Elischer 50e602ba25SJulian Elischer When a KSE is removed from the run queue to become runnable, we know 51e602ba25SJulian Elischer it was associated with the highest priority thread in the queue (at the head 52e602ba25SJulian Elischer of the queue). If it is also the last assigned we know M was 1 and must 53e602ba25SJulian Elischer now be 0. Since the thread is no longer queued that pointer must be 54e602ba25SJulian Elischer removed from it. Since we know there were no more KSEs available, 55e602ba25SJulian Elischer (M was 1 and is now 0) and since we are not FREEING our KSE 56e602ba25SJulian Elischer but using it, we know there are STILL no more KSEs available, we can prove 57e602ba25SJulian Elischer that the next thread in the ksegrp list will not have a KSE to assign to 58e602ba25SJulian Elischer it, so we can show that the pointer must be made 'invalid' (NULL). 59e602ba25SJulian Elischer 60e602ba25SJulian Elischer The pointer exists so that when a new thread is made runnable, it can 61e602ba25SJulian Elischer have its priority compared with the last assigned thread to see if 62e602ba25SJulian Elischer it should 'steal' its KSE or not.. i.e. is it 'earlier' 63e602ba25SJulian Elischer on the list than that thread or later.. If it's earlier, then the KSE is 64e602ba25SJulian Elischer removed from the last assigned (which is now not assigned a KSE) 65e602ba25SJulian Elischer and reassigned to the new thread, which is placed earlier in the list. 66e602ba25SJulian Elischer The pointer is then backed up to the previous thread (which may or may not 67e602ba25SJulian Elischer be the new thread). 68e602ba25SJulian Elischer 69e602ba25SJulian Elischer When a thread sleeps or is removed, the KSE becomes available and if there 70e602ba25SJulian Elischer are queued threads that are not assigned KSEs, the highest priority one of 71e602ba25SJulian Elischer them is assigned the KSE, which is then placed back on the run queue at 72e602ba25SJulian Elischer the approipriate place, and the kg->kg_last_assigned pointer is adjusted down 73e602ba25SJulian Elischer to point to it. 74e602ba25SJulian Elischer 75e602ba25SJulian Elischer The following diagram shows 2 KSEs and 3 threads from a single process. 76e602ba25SJulian Elischer 77e602ba25SJulian Elischer RUNQ: --->KSE---KSE--... (KSEs queued at priorities from threads) 78e602ba25SJulian Elischer \ \____ 79e602ba25SJulian Elischer \ \ 80e602ba25SJulian Elischer KSEGROUP---thread--thread--thread (queued in priority order) 81e602ba25SJulian Elischer \ / 82e602ba25SJulian Elischer \_______________/ 83e602ba25SJulian Elischer (last_assigned) 84e602ba25SJulian Elischer 85e602ba25SJulian Elischer The result of this scheme is that the M available KSEs are always 86e602ba25SJulian Elischer queued at the priorities they have inherrited from the M highest priority 87e602ba25SJulian Elischer threads for that KSEGROUP. If this situation changes, the KSEs are 88e602ba25SJulian Elischer reassigned to keep this true. 89e602ba25SJulian Elischer 90e602ba25SJulian Elischer */ 91e602ba25SJulian Elischer 92dba6c5a6SPeter Wemm #include <sys/param.h> 93dba6c5a6SPeter Wemm #include <sys/systm.h> 94dba6c5a6SPeter Wemm #include <sys/kernel.h> 950384fff8SJason Evans #include <sys/ktr.h> 96f34fa851SJohn Baldwin #include <sys/lock.h> 9735e0e5b3SJohn Baldwin #include <sys/mutex.h> 98dba6c5a6SPeter Wemm #include <sys/proc.h> 99dba6c5a6SPeter Wemm #include <sys/queue.h> 100b43179fbSJeff Roberson #include <sys/sched.h> 101cc66ebe2SPeter Wemm #if defined(SMP) && defined(__i386__) 102cc66ebe2SPeter Wemm #include <sys/smp.h> 103cc66ebe2SPeter Wemm #endif 104182da820SMatthew Dillon #include <machine/critical.h> 105dba6c5a6SPeter Wemm 106d2ac2316SJake Burkholder CTASSERT((RQB_BPW * RQB_LEN) == RQ_NQS); 107d2ac2316SJake Burkholder 10848bfcdddSJulian Elischer void panc(char *string1, char *string2); 10948bfcdddSJulian Elischer 11048bfcdddSJulian Elischer #if 0 111e602ba25SJulian Elischer static void runq_readjust(struct runq *rq, struct kse *ke); 11248bfcdddSJulian Elischer #endif 113e602ba25SJulian Elischer /************************************************************************ 114e602ba25SJulian Elischer * Functions that manipulate runnability from a thread perspective. * 115e602ba25SJulian Elischer ************************************************************************/ 116e602ba25SJulian Elischer /* 1175215b187SJeff Roberson * Select the KSE that will be run next. From that find the thread, and 118e602ba25SJulian Elischer * remove it from the KSEGRP's run queue. If there is thread clustering, 119e602ba25SJulian Elischer * this will be what does it. 120e602ba25SJulian Elischer */ 121b40ce416SJulian Elischer struct thread * 122b40ce416SJulian Elischer choosethread(void) 123dba6c5a6SPeter Wemm { 124e602ba25SJulian Elischer struct kse *ke; 125e602ba25SJulian Elischer struct thread *td; 126e602ba25SJulian Elischer struct ksegrp *kg; 127e602ba25SJulian Elischer 128cc66ebe2SPeter Wemm #if defined(SMP) && defined(__i386__) 129cc66ebe2SPeter Wemm if (smp_active == 0 && PCPU_GET(cpuid) != 0) { 130cc66ebe2SPeter Wemm /* Shutting down, run idlethread on AP's */ 131cc66ebe2SPeter Wemm td = PCPU_GET(idlethread); 132cc66ebe2SPeter Wemm ke = td->td_kse; 133cc66ebe2SPeter Wemm CTR1(KTR_RUNQ, "choosethread: td=%p (idle)", td); 134cc66ebe2SPeter Wemm ke->ke_flags |= KEF_DIDRUN; 135cc66ebe2SPeter Wemm TD_SET_RUNNING(td); 136cc66ebe2SPeter Wemm return (td); 137cc66ebe2SPeter Wemm } 138cc66ebe2SPeter Wemm #endif 139cc66ebe2SPeter Wemm 140fe799533SAndrew Gallatin retry: 141cc66ebe2SPeter Wemm ke = sched_choose(); 142cc66ebe2SPeter Wemm if (ke) { 143e602ba25SJulian Elischer td = ke->ke_thread; 144e602ba25SJulian Elischer KASSERT((td->td_kse == ke), ("kse/thread mismatch")); 145e602ba25SJulian Elischer kg = ke->ke_ksegrp; 146ac2e4153SJulian Elischer if (td->td_proc->p_flag & P_THREADED) { 14733c06e1dSJulian Elischer if (kg->kg_last_assigned == td) { 148e602ba25SJulian Elischer kg->kg_last_assigned = TAILQ_PREV(td, 149e602ba25SJulian Elischer threadqueue, td_runq); 15033c06e1dSJulian Elischer } 151d03c79eeSDavid Xu TAILQ_REMOVE(&kg->kg_runq, td, td_runq); 152e602ba25SJulian Elischer } 153e602ba25SJulian Elischer kg->kg_runnable--; 154e602ba25SJulian Elischer CTR2(KTR_RUNQ, "choosethread: td=%p pri=%d", 155e602ba25SJulian Elischer td, td->td_priority); 156e602ba25SJulian Elischer } else { 15740e55026SJulian Elischer /* Simulate runq_choose() having returned the idle thread */ 158e602ba25SJulian Elischer td = PCPU_GET(idlethread); 159472be958SJulian Elischer ke = td->td_kse; 160e602ba25SJulian Elischer CTR1(KTR_RUNQ, "choosethread: td=%p (idle)", td); 161e602ba25SJulian Elischer } 162472be958SJulian Elischer ke->ke_flags |= KEF_DIDRUN; 16393a7aa79SJulian Elischer 16493a7aa79SJulian Elischer /* 16593a7aa79SJulian Elischer * Only allow non system threads to run in panic 16693a7aa79SJulian Elischer * if they are the one we are tracing. (I think.. [JRE]) 16793a7aa79SJulian Elischer */ 168fe799533SAndrew Gallatin if (panicstr && ((td->td_proc->p_flag & P_SYSTEM) == 0 && 169fe799533SAndrew Gallatin (td->td_flags & TDF_INPANIC) == 0)) 170fe799533SAndrew Gallatin goto retry; 17193a7aa79SJulian Elischer 17271fad9fdSJulian Elischer TD_SET_RUNNING(td); 173e602ba25SJulian Elischer return (td); 174e602ba25SJulian Elischer } 175e602ba25SJulian Elischer 176e602ba25SJulian Elischer /* 1775215b187SJeff Roberson * Given a surplus KSE, either assign a new runable thread to it 1785215b187SJeff Roberson * (and put it in the run queue) or put it in the ksegrp's idle KSE list. 1794f6cfa45SDavid Xu * Assumes that the original thread is not runnable. 180e602ba25SJulian Elischer */ 181e602ba25SJulian Elischer void 182e602ba25SJulian Elischer kse_reassign(struct kse *ke) 183e602ba25SJulian Elischer { 184e602ba25SJulian Elischer struct ksegrp *kg; 185e602ba25SJulian Elischer struct thread *td; 18648bfcdddSJulian Elischer struct thread *original; 187e602ba25SJulian Elischer 18833c06e1dSJulian Elischer mtx_assert(&sched_lock, MA_OWNED); 1896f8132a8SJulian Elischer original = ke->ke_thread; 1905215b187SJeff Roberson KASSERT(original == NULL || TD_IS_INHIBITED(original), 1915215b187SJeff Roberson ("reassigning KSE with runnable thread")); 1925215b187SJeff Roberson kg = ke->ke_ksegrp; 1936ce75196SDavid Xu if (original) 1945215b187SJeff Roberson original->td_kse = NULL; 195e602ba25SJulian Elischer 196e602ba25SJulian Elischer /* 1976f8132a8SJulian Elischer * Find the first unassigned thread 1986f8132a8SJulian Elischer */ 1995215b187SJeff Roberson if ((td = kg->kg_last_assigned) != NULL) 2006f8132a8SJulian Elischer td = TAILQ_NEXT(td, td_runq); 2015215b187SJeff Roberson else 2026f8132a8SJulian Elischer td = TAILQ_FIRST(&kg->kg_runq); 2036f8132a8SJulian Elischer 2046f8132a8SJulian Elischer /* 2055215b187SJeff Roberson * If we found one, assign it the kse, otherwise idle the kse. 206e602ba25SJulian Elischer */ 207e602ba25SJulian Elischer if (td) { 208e602ba25SJulian Elischer kg->kg_last_assigned = td; 209e602ba25SJulian Elischer td->td_kse = ke; 210e602ba25SJulian Elischer ke->ke_thread = td; 211b43179fbSJeff Roberson sched_add(ke); 212e602ba25SJulian Elischer CTR2(KTR_RUNQ, "kse_reassign: ke%p -> td%p", ke, td); 21348bfcdddSJulian Elischer return; 21448bfcdddSJulian Elischer } 21548bfcdddSJulian Elischer 2165215b187SJeff Roberson ke->ke_state = KES_IDLE; 21793a7aa79SJulian Elischer ke->ke_thread = NULL; 2185215b187SJeff Roberson TAILQ_INSERT_TAIL(&kg->kg_iq, ke, ke_kgrlist); 2195215b187SJeff Roberson kg->kg_idle_kses++; 2205215b187SJeff Roberson CTR1(KTR_RUNQ, "kse_reassign: ke%p on idle queue", ke); 22148bfcdddSJulian Elischer return; 222d5a08a60SJake Burkholder } 223d5a08a60SJake Burkholder 2241f955e2dSJulian Elischer #if 0 225e602ba25SJulian Elischer /* 226e602ba25SJulian Elischer * Remove a thread from its KSEGRP's run queue. 227e602ba25SJulian Elischer * This in turn may remove it from a KSE if it was already assigned 228e602ba25SJulian Elischer * to one, possibly causing a new thread to be assigned to the KSE 2295215b187SJeff Roberson * and the KSE getting a new priority. 230e602ba25SJulian Elischer */ 2311f955e2dSJulian Elischer static void 232b40ce416SJulian Elischer remrunqueue(struct thread *td) 233d5a08a60SJake Burkholder { 23448bfcdddSJulian Elischer struct thread *td2, *td3; 235e602ba25SJulian Elischer struct ksegrp *kg; 236e602ba25SJulian Elischer struct kse *ke; 237e602ba25SJulian Elischer 238e602ba25SJulian Elischer mtx_assert(&sched_lock, MA_OWNED); 23971fad9fdSJulian Elischer KASSERT((TD_ON_RUNQ(td)), ("remrunqueue: Bad state on run queue")); 240e602ba25SJulian Elischer kg = td->td_ksegrp; 241e602ba25SJulian Elischer ke = td->td_kse; 242e602ba25SJulian Elischer CTR1(KTR_RUNQ, "remrunqueue: td%p", td); 243e602ba25SJulian Elischer kg->kg_runnable--; 24471fad9fdSJulian Elischer TD_SET_CAN_RUN(td); 2455215b187SJeff Roberson /* 2465215b187SJeff Roberson * If it is not a threaded process, take the shortcut. 2475215b187SJeff Roberson */ 248ac2e4153SJulian Elischer if ((td->td_proc->p_flag & P_THREADED) == 0) { 249e602ba25SJulian Elischer /* Bring its kse with it, leave the thread attached */ 250b43179fbSJeff Roberson sched_rem(ke); 251c3b98db0SJulian Elischer ke->ke_state = KES_THREAD; 252e602ba25SJulian Elischer return; 253d5a08a60SJake Burkholder } 25448bfcdddSJulian Elischer td3 = TAILQ_PREV(td, threadqueue, td_runq); 25548bfcdddSJulian Elischer TAILQ_REMOVE(&kg->kg_runq, td, td_runq); 256e602ba25SJulian Elischer if (ke) { 257e602ba25SJulian Elischer /* 258e602ba25SJulian Elischer * This thread has been assigned to a KSE. 259e602ba25SJulian Elischer * We need to dissociate it and try assign the 260e602ba25SJulian Elischer * KSE to the next available thread. Then, we should 261e602ba25SJulian Elischer * see if we need to move the KSE in the run queues. 262e602ba25SJulian Elischer */ 26393a7aa79SJulian Elischer sched_rem(ke); 26493a7aa79SJulian Elischer ke->ke_state = KES_THREAD; 265e602ba25SJulian Elischer td2 = kg->kg_last_assigned; 266e602ba25SJulian Elischer KASSERT((td2 != NULL), ("last assigned has wrong value")); 26748bfcdddSJulian Elischer if (td2 == td) 268e602ba25SJulian Elischer kg->kg_last_assigned = td3; 26948bfcdddSJulian Elischer kse_reassign(ke); 270e602ba25SJulian Elischer } 271e602ba25SJulian Elischer } 2721f955e2dSJulian Elischer #endif 2731f955e2dSJulian Elischer 2741f955e2dSJulian Elischer /* 2751f955e2dSJulian Elischer * Change the priority of a thread that is on the run queue. 2761f955e2dSJulian Elischer */ 2771f955e2dSJulian Elischer void 2781f955e2dSJulian Elischer adjustrunqueue( struct thread *td, int newpri) 2791f955e2dSJulian Elischer { 2801f955e2dSJulian Elischer struct ksegrp *kg; 2811f955e2dSJulian Elischer struct kse *ke; 2821f955e2dSJulian Elischer 2831f955e2dSJulian Elischer mtx_assert(&sched_lock, MA_OWNED); 2841f955e2dSJulian Elischer KASSERT((TD_ON_RUNQ(td)), ("adjustrunqueue: Bad state on run queue")); 2855215b187SJeff Roberson 2861f955e2dSJulian Elischer ke = td->td_kse; 2871f955e2dSJulian Elischer CTR1(KTR_RUNQ, "adjustrunqueue: td%p", td); 2885215b187SJeff Roberson /* 2895215b187SJeff Roberson * If it is not a threaded process, take the shortcut. 2905215b187SJeff Roberson */ 291ac2e4153SJulian Elischer if ((td->td_proc->p_flag & P_THREADED) == 0) { 2921f955e2dSJulian Elischer /* We only care about the kse in the run queue. */ 29324c5baaeSJulian Elischer td->td_priority = newpri; 2941f955e2dSJulian Elischer if (ke->ke_rqindex != (newpri / RQ_PPQ)) { 2951f955e2dSJulian Elischer sched_rem(ke); 2961f955e2dSJulian Elischer sched_add(ke); 2971f955e2dSJulian Elischer } 2981f955e2dSJulian Elischer return; 2991f955e2dSJulian Elischer } 3005215b187SJeff Roberson 3015215b187SJeff Roberson /* It is a threaded process */ 3021f955e2dSJulian Elischer kg = td->td_ksegrp; 3031f955e2dSJulian Elischer kg->kg_runnable--; 3041f955e2dSJulian Elischer TD_SET_CAN_RUN(td); 3051f955e2dSJulian Elischer if (ke) { 3061f955e2dSJulian Elischer if (kg->kg_last_assigned == td) { 3071f955e2dSJulian Elischer kg->kg_last_assigned = 3081f955e2dSJulian Elischer TAILQ_PREV(td, threadqueue, td_runq); 3091f955e2dSJulian Elischer } 3101f955e2dSJulian Elischer sched_rem(ke); 3111f955e2dSJulian Elischer } 3121f955e2dSJulian Elischer TAILQ_REMOVE(&kg->kg_runq, td, td_runq); 3131f955e2dSJulian Elischer td->td_priority = newpri; 3141f955e2dSJulian Elischer setrunqueue(td); 3151f955e2dSJulian Elischer } 316e602ba25SJulian Elischer 317d5a08a60SJake Burkholder void 318b40ce416SJulian Elischer setrunqueue(struct thread *td) 319d5a08a60SJake Burkholder { 320e602ba25SJulian Elischer struct kse *ke; 321e602ba25SJulian Elischer struct ksegrp *kg; 322e602ba25SJulian Elischer struct thread *td2; 323e602ba25SJulian Elischer struct thread *tda; 324e602ba25SJulian Elischer 325e602ba25SJulian Elischer CTR1(KTR_RUNQ, "setrunqueue: td%p", td); 326e602ba25SJulian Elischer mtx_assert(&sched_lock, MA_OWNED); 32771fad9fdSJulian Elischer KASSERT((TD_CAN_RUN(td) || TD_IS_RUNNING(td)), 32871fad9fdSJulian Elischer ("setrunqueue: bad thread state")); 32971fad9fdSJulian Elischer TD_SET_RUNQ(td); 330e602ba25SJulian Elischer kg = td->td_ksegrp; 331e602ba25SJulian Elischer kg->kg_runnable++; 332ac2e4153SJulian Elischer if ((td->td_proc->p_flag & P_THREADED) == 0) { 33348bfcdddSJulian Elischer /* 33448bfcdddSJulian Elischer * Common path optimisation: Only one of everything 33548bfcdddSJulian Elischer * and the KSE is always already attached. 33648bfcdddSJulian Elischer * Totally ignore the ksegrp run queue. 33748bfcdddSJulian Elischer */ 338b43179fbSJeff Roberson sched_add(td->td_kse); 33948bfcdddSJulian Elischer return; 34048bfcdddSJulian Elischer } 34148bfcdddSJulian Elischer 342e602ba25SJulian Elischer tda = kg->kg_last_assigned; 343e602ba25SJulian Elischer if ((ke = td->td_kse) == NULL) { 3445215b187SJeff Roberson if (kg->kg_idle_kses) { 345e602ba25SJulian Elischer /* 3465215b187SJeff Roberson * There is a free one so it's ours for the asking.. 347e602ba25SJulian Elischer */ 3485215b187SJeff Roberson ke = TAILQ_FIRST(&kg->kg_iq); 3495215b187SJeff Roberson TAILQ_REMOVE(&kg->kg_iq, ke, ke_kgrlist); 3509eb1fdeaSJulian Elischer ke->ke_state = KES_THREAD; 3515215b187SJeff Roberson kg->kg_idle_kses--; 352e602ba25SJulian Elischer } else if (tda && (tda->td_priority > td->td_priority)) { 353e602ba25SJulian Elischer /* 354e602ba25SJulian Elischer * None free, but there is one we can commandeer. 355e602ba25SJulian Elischer */ 356e602ba25SJulian Elischer ke = tda->td_kse; 357e602ba25SJulian Elischer tda->td_kse = NULL; 358e602ba25SJulian Elischer ke->ke_thread = NULL; 359e602ba25SJulian Elischer tda = kg->kg_last_assigned = 360e602ba25SJulian Elischer TAILQ_PREV(tda, threadqueue, td_runq); 361b43179fbSJeff Roberson sched_rem(ke); 362e602ba25SJulian Elischer } 363e602ba25SJulian Elischer } else { 364c3b98db0SJulian Elischer /* 365c3b98db0SJulian Elischer * Temporarily disassociate so it looks like the other cases. 366c3b98db0SJulian Elischer */ 367e602ba25SJulian Elischer ke->ke_thread = NULL; 368e602ba25SJulian Elischer td->td_kse = NULL; 369d5a08a60SJake Burkholder } 370d5a08a60SJake Burkholder 371e602ba25SJulian Elischer /* 372e602ba25SJulian Elischer * Add the thread to the ksegrp's run queue at 373e602ba25SJulian Elischer * the appropriate place. 374e602ba25SJulian Elischer */ 375e602ba25SJulian Elischer TAILQ_FOREACH(td2, &kg->kg_runq, td_runq) { 376e602ba25SJulian Elischer if (td2->td_priority > td->td_priority) { 377e602ba25SJulian Elischer TAILQ_INSERT_BEFORE(td2, td, td_runq); 378e602ba25SJulian Elischer break; 379e602ba25SJulian Elischer } 380e602ba25SJulian Elischer } 381e602ba25SJulian Elischer if (td2 == NULL) { 382e602ba25SJulian Elischer /* We ran off the end of the TAILQ or it was empty. */ 383e602ba25SJulian Elischer TAILQ_INSERT_TAIL(&kg->kg_runq, td, td_runq); 384e602ba25SJulian Elischer } 385e602ba25SJulian Elischer 386e602ba25SJulian Elischer /* 387e602ba25SJulian Elischer * If we have a ke to use, then put it on the run queue and 388e602ba25SJulian Elischer * If needed, readjust the last_assigned pointer. 389e602ba25SJulian Elischer */ 390e602ba25SJulian Elischer if (ke) { 391e602ba25SJulian Elischer if (tda == NULL) { 392e602ba25SJulian Elischer /* 393e602ba25SJulian Elischer * No pre-existing last assigned so whoever is first 394c3b98db0SJulian Elischer * gets the KSE we brought in.. (maybe us) 395e602ba25SJulian Elischer */ 396e602ba25SJulian Elischer td2 = TAILQ_FIRST(&kg->kg_runq); 397e602ba25SJulian Elischer KASSERT((td2->td_kse == NULL), 398e602ba25SJulian Elischer ("unexpected ke present")); 399e602ba25SJulian Elischer td2->td_kse = ke; 400e602ba25SJulian Elischer ke->ke_thread = td2; 401e602ba25SJulian Elischer kg->kg_last_assigned = td2; 402e602ba25SJulian Elischer } else if (tda->td_priority > td->td_priority) { 403e602ba25SJulian Elischer /* 404e602ba25SJulian Elischer * It's ours, grab it, but last_assigned is past us 405e602ba25SJulian Elischer * so don't change it. 406e602ba25SJulian Elischer */ 407e602ba25SJulian Elischer td->td_kse = ke; 408e602ba25SJulian Elischer ke->ke_thread = td; 409e602ba25SJulian Elischer } else { 410e602ba25SJulian Elischer /* 411e602ba25SJulian Elischer * We are past last_assigned, so 412e602ba25SJulian Elischer * put the new kse on whatever is next, 413e602ba25SJulian Elischer * which may or may not be us. 414e602ba25SJulian Elischer */ 415e602ba25SJulian Elischer td2 = TAILQ_NEXT(tda, td_runq); 416e602ba25SJulian Elischer kg->kg_last_assigned = td2; 417e602ba25SJulian Elischer td2->td_kse = ke; 418e602ba25SJulian Elischer ke->ke_thread = td2; 419e602ba25SJulian Elischer } 420b43179fbSJeff Roberson sched_add(ke); 421e602ba25SJulian Elischer } 422e602ba25SJulian Elischer } 423e602ba25SJulian Elischer 424e602ba25SJulian Elischer /************************************************************************ 425e602ba25SJulian Elischer * Critical section marker functions * 426e602ba25SJulian Elischer ************************************************************************/ 4277e1f6dfeSJohn Baldwin /* Critical sections that prevent preemption. */ 4287e1f6dfeSJohn Baldwin void 4297e1f6dfeSJohn Baldwin critical_enter(void) 4307e1f6dfeSJohn Baldwin { 4317e1f6dfeSJohn Baldwin struct thread *td; 4327e1f6dfeSJohn Baldwin 4337e1f6dfeSJohn Baldwin td = curthread; 4347e1f6dfeSJohn Baldwin if (td->td_critnest == 0) 435d74ac681SMatthew Dillon cpu_critical_enter(); 4367e1f6dfeSJohn Baldwin td->td_critnest++; 4377e1f6dfeSJohn Baldwin } 4387e1f6dfeSJohn Baldwin 4397e1f6dfeSJohn Baldwin void 4407e1f6dfeSJohn Baldwin critical_exit(void) 4417e1f6dfeSJohn Baldwin { 4427e1f6dfeSJohn Baldwin struct thread *td; 4437e1f6dfeSJohn Baldwin 4447e1f6dfeSJohn Baldwin td = curthread; 4457e1f6dfeSJohn Baldwin if (td->td_critnest == 1) { 4467e1f6dfeSJohn Baldwin td->td_critnest = 0; 447d74ac681SMatthew Dillon cpu_critical_exit(); 448d74ac681SMatthew Dillon } else { 4497e1f6dfeSJohn Baldwin td->td_critnest--; 4507e1f6dfeSJohn Baldwin } 451d74ac681SMatthew Dillon } 4527e1f6dfeSJohn Baldwin 453e602ba25SJulian Elischer 454e602ba25SJulian Elischer /************************************************************************ 455e602ba25SJulian Elischer * SYSTEM RUN QUEUE manipulations and tests * 456e602ba25SJulian Elischer ************************************************************************/ 457e602ba25SJulian Elischer /* 458e602ba25SJulian Elischer * Initialize a run structure. 459e602ba25SJulian Elischer */ 460e602ba25SJulian Elischer void 461e602ba25SJulian Elischer runq_init(struct runq *rq) 462e602ba25SJulian Elischer { 463e602ba25SJulian Elischer int i; 464e602ba25SJulian Elischer 465e602ba25SJulian Elischer bzero(rq, sizeof *rq); 466e602ba25SJulian Elischer for (i = 0; i < RQ_NQS; i++) 467e602ba25SJulian Elischer TAILQ_INIT(&rq->rq_queues[i]); 468e602ba25SJulian Elischer } 469e602ba25SJulian Elischer 470d5a08a60SJake Burkholder /* 471d5a08a60SJake Burkholder * Clear the status bit of the queue corresponding to priority level pri, 472d5a08a60SJake Burkholder * indicating that it is empty. 473d5a08a60SJake Burkholder */ 474d5a08a60SJake Burkholder static __inline void 475d5a08a60SJake Burkholder runq_clrbit(struct runq *rq, int pri) 476d5a08a60SJake Burkholder { 477d5a08a60SJake Burkholder struct rqbits *rqb; 478d5a08a60SJake Burkholder 479d5a08a60SJake Burkholder rqb = &rq->rq_status; 480d5a08a60SJake Burkholder CTR4(KTR_RUNQ, "runq_clrbit: bits=%#x %#x bit=%#x word=%d", 481d5a08a60SJake Burkholder rqb->rqb_bits[RQB_WORD(pri)], 482d5a08a60SJake Burkholder rqb->rqb_bits[RQB_WORD(pri)] & ~RQB_BIT(pri), 483d5a08a60SJake Burkholder RQB_BIT(pri), RQB_WORD(pri)); 484d5a08a60SJake Burkholder rqb->rqb_bits[RQB_WORD(pri)] &= ~RQB_BIT(pri); 485d5a08a60SJake Burkholder } 486d5a08a60SJake Burkholder 487d5a08a60SJake Burkholder /* 488d5a08a60SJake Burkholder * Find the index of the first non-empty run queue. This is done by 489d5a08a60SJake Burkholder * scanning the status bits, a set bit indicates a non-empty queue. 490d5a08a60SJake Burkholder */ 491d5a08a60SJake Burkholder static __inline int 492d5a08a60SJake Burkholder runq_findbit(struct runq *rq) 493d5a08a60SJake Burkholder { 494d5a08a60SJake Burkholder struct rqbits *rqb; 495d5a08a60SJake Burkholder int pri; 496d5a08a60SJake Burkholder int i; 497d5a08a60SJake Burkholder 498d5a08a60SJake Burkholder rqb = &rq->rq_status; 499d5a08a60SJake Burkholder for (i = 0; i < RQB_LEN; i++) 500d5a08a60SJake Burkholder if (rqb->rqb_bits[i]) { 5012f9267ecSPeter Wemm pri = RQB_FFS(rqb->rqb_bits[i]) + (i << RQB_L2BPW); 502d5a08a60SJake Burkholder CTR3(KTR_RUNQ, "runq_findbit: bits=%#x i=%d pri=%d", 503d5a08a60SJake Burkholder rqb->rqb_bits[i], i, pri); 504d5a08a60SJake Burkholder return (pri); 505d5a08a60SJake Burkholder } 506d5a08a60SJake Burkholder 507d5a08a60SJake Burkholder return (-1); 508d5a08a60SJake Burkholder } 509d5a08a60SJake Burkholder 510d5a08a60SJake Burkholder /* 511d5a08a60SJake Burkholder * Set the status bit of the queue corresponding to priority level pri, 512d5a08a60SJake Burkholder * indicating that it is non-empty. 513d5a08a60SJake Burkholder */ 514d5a08a60SJake Burkholder static __inline void 515d5a08a60SJake Burkholder runq_setbit(struct runq *rq, int pri) 516d5a08a60SJake Burkholder { 517d5a08a60SJake Burkholder struct rqbits *rqb; 518d5a08a60SJake Burkholder 519d5a08a60SJake Burkholder rqb = &rq->rq_status; 520d5a08a60SJake Burkholder CTR4(KTR_RUNQ, "runq_setbit: bits=%#x %#x bit=%#x word=%d", 521d5a08a60SJake Burkholder rqb->rqb_bits[RQB_WORD(pri)], 522d5a08a60SJake Burkholder rqb->rqb_bits[RQB_WORD(pri)] | RQB_BIT(pri), 523d5a08a60SJake Burkholder RQB_BIT(pri), RQB_WORD(pri)); 524d5a08a60SJake Burkholder rqb->rqb_bits[RQB_WORD(pri)] |= RQB_BIT(pri); 525d5a08a60SJake Burkholder } 526d5a08a60SJake Burkholder 527d5a08a60SJake Burkholder /* 528e602ba25SJulian Elischer * Add the KSE to the queue specified by its priority, and set the 529d5a08a60SJake Burkholder * corresponding status bit. 530d5a08a60SJake Burkholder */ 531d5a08a60SJake Burkholder void 532b40ce416SJulian Elischer runq_add(struct runq *rq, struct kse *ke) 533d5a08a60SJake Burkholder { 534d5a08a60SJake Burkholder struct rqhead *rqh; 535d5a08a60SJake Burkholder int pri; 536dba6c5a6SPeter Wemm 5372c100766SJulian Elischer pri = ke->ke_thread->td_priority / RQ_PPQ; 538b40ce416SJulian Elischer ke->ke_rqindex = pri; 539d5a08a60SJake Burkholder runq_setbit(rq, pri); 540d5a08a60SJake Burkholder rqh = &rq->rq_queues[pri]; 541d5a08a60SJake Burkholder CTR4(KTR_RUNQ, "runq_add: p=%p pri=%d %d rqh=%p", 5422c100766SJulian Elischer ke->ke_proc, ke->ke_thread->td_priority, pri, rqh); 543b40ce416SJulian Elischer TAILQ_INSERT_TAIL(rqh, ke, ke_procq); 544dba6c5a6SPeter Wemm } 545d5a08a60SJake Burkholder 546d5a08a60SJake Burkholder /* 547d5a08a60SJake Burkholder * Return true if there are runnable processes of any priority on the run 548d5a08a60SJake Burkholder * queue, false otherwise. Has no side effects, does not modify the run 549d5a08a60SJake Burkholder * queue structure. 550d5a08a60SJake Burkholder */ 551d5a08a60SJake Burkholder int 552d5a08a60SJake Burkholder runq_check(struct runq *rq) 553d5a08a60SJake Burkholder { 554d5a08a60SJake Burkholder struct rqbits *rqb; 555d5a08a60SJake Burkholder int i; 556d5a08a60SJake Burkholder 557d5a08a60SJake Burkholder rqb = &rq->rq_status; 558d5a08a60SJake Burkholder for (i = 0; i < RQB_LEN; i++) 559d5a08a60SJake Burkholder if (rqb->rqb_bits[i]) { 560d5a08a60SJake Burkholder CTR2(KTR_RUNQ, "runq_check: bits=%#x i=%d", 561d5a08a60SJake Burkholder rqb->rqb_bits[i], i); 562d5a08a60SJake Burkholder return (1); 563dba6c5a6SPeter Wemm } 564d5a08a60SJake Burkholder CTR0(KTR_RUNQ, "runq_check: empty"); 565d5a08a60SJake Burkholder 566d5a08a60SJake Burkholder return (0); 567dba6c5a6SPeter Wemm } 568d5a08a60SJake Burkholder 569d5a08a60SJake Burkholder /* 570b43179fbSJeff Roberson * Find the highest priority process on the run queue. 571d5a08a60SJake Burkholder */ 572b40ce416SJulian Elischer struct kse * 573d5a08a60SJake Burkholder runq_choose(struct runq *rq) 574d5a08a60SJake Burkholder { 575d5a08a60SJake Burkholder struct rqhead *rqh; 576b40ce416SJulian Elischer struct kse *ke; 577d5a08a60SJake Burkholder int pri; 578d5a08a60SJake Burkholder 579d5a08a60SJake Burkholder mtx_assert(&sched_lock, MA_OWNED); 580e602ba25SJulian Elischer while ((pri = runq_findbit(rq)) != -1) { 581d5a08a60SJake Burkholder rqh = &rq->rq_queues[pri]; 582b40ce416SJulian Elischer ke = TAILQ_FIRST(rqh); 583b40ce416SJulian Elischer KASSERT(ke != NULL, ("runq_choose: no proc on busy queue")); 584e602ba25SJulian Elischer CTR3(KTR_RUNQ, 585e602ba25SJulian Elischer "runq_choose: pri=%d kse=%p rqh=%p", pri, ke, rqh); 586b40ce416SJulian Elischer return (ke); 587d5a08a60SJake Burkholder } 588d5a08a60SJake Burkholder CTR1(KTR_RUNQ, "runq_choose: idleproc pri=%d", pri); 589d5a08a60SJake Burkholder 590e602ba25SJulian Elischer return (NULL); 591d5a08a60SJake Burkholder } 592d5a08a60SJake Burkholder 593d5a08a60SJake Burkholder /* 594e602ba25SJulian Elischer * Remove the KSE from the queue specified by its priority, and clear the 595d5a08a60SJake Burkholder * corresponding status bit if the queue becomes empty. 596e602ba25SJulian Elischer * Caller must set ke->ke_state afterwards. 597d5a08a60SJake Burkholder */ 598d5a08a60SJake Burkholder void 599b40ce416SJulian Elischer runq_remove(struct runq *rq, struct kse *ke) 600d5a08a60SJake Burkholder { 601d5a08a60SJake Burkholder struct rqhead *rqh; 602d5a08a60SJake Burkholder int pri; 603d5a08a60SJake Burkholder 6049eb881f8SSeigo Tanimura KASSERT(ke->ke_proc->p_sflag & PS_INMEM, 6059eb881f8SSeigo Tanimura ("runq_remove: process swapped out")); 606b40ce416SJulian Elischer pri = ke->ke_rqindex; 607d5a08a60SJake Burkholder rqh = &rq->rq_queues[pri]; 608d5a08a60SJake Burkholder CTR4(KTR_RUNQ, "runq_remove: p=%p pri=%d %d rqh=%p", 6092c100766SJulian Elischer ke, ke->ke_thread->td_priority, pri, rqh); 610b40ce416SJulian Elischer KASSERT(ke != NULL, ("runq_remove: no proc on busy queue")); 611b40ce416SJulian Elischer TAILQ_REMOVE(rqh, ke, ke_procq); 612d5a08a60SJake Burkholder if (TAILQ_EMPTY(rqh)) { 613d5a08a60SJake Burkholder CTR0(KTR_RUNQ, "runq_remove: empty"); 614d5a08a60SJake Burkholder runq_clrbit(rq, pri); 615d5a08a60SJake Burkholder } 616dba6c5a6SPeter Wemm } 617e602ba25SJulian Elischer 61848bfcdddSJulian Elischer #if 0 619e602ba25SJulian Elischer void 62048bfcdddSJulian Elischer panc(char *string1, char *string2) 62148bfcdddSJulian Elischer { 62248bfcdddSJulian Elischer printf("%s", string1); 62348bfcdddSJulian Elischer Debugger(string2); 62448bfcdddSJulian Elischer } 62548bfcdddSJulian Elischer 62648bfcdddSJulian Elischer void 62748bfcdddSJulian Elischer thread_sanity_check(struct thread *td, char *string) 628e602ba25SJulian Elischer { 629e602ba25SJulian Elischer struct proc *p; 630e602ba25SJulian Elischer struct ksegrp *kg; 631e602ba25SJulian Elischer struct kse *ke; 63248bfcdddSJulian Elischer struct thread *td2 = NULL; 633e602ba25SJulian Elischer unsigned int prevpri; 63448bfcdddSJulian Elischer int saw_lastassigned = 0; 63548bfcdddSJulian Elischer int unassigned = 0; 63648bfcdddSJulian Elischer int assigned = 0; 637e602ba25SJulian Elischer 638e602ba25SJulian Elischer p = td->td_proc; 639e602ba25SJulian Elischer kg = td->td_ksegrp; 640e602ba25SJulian Elischer ke = td->td_kse; 641e602ba25SJulian Elischer 642e602ba25SJulian Elischer 643e602ba25SJulian Elischer if (ke) { 6444f0db5e0SJulian Elischer if (p != ke->ke_proc) { 64548bfcdddSJulian Elischer panc(string, "wrong proc"); 646e602ba25SJulian Elischer } 647e602ba25SJulian Elischer if (ke->ke_thread != td) { 64848bfcdddSJulian Elischer panc(string, "wrong thread"); 649e602ba25SJulian Elischer } 650e602ba25SJulian Elischer } 651e602ba25SJulian Elischer 652ac2e4153SJulian Elischer if ((p->p_flag & P_THREADED) == 0) { 653e602ba25SJulian Elischer if (ke == NULL) { 65448bfcdddSJulian Elischer panc(string, "non KSE thread lost kse"); 655e602ba25SJulian Elischer } 656e602ba25SJulian Elischer } else { 657e602ba25SJulian Elischer prevpri = 0; 658e602ba25SJulian Elischer saw_lastassigned = 0; 659e602ba25SJulian Elischer unassigned = 0; 660e602ba25SJulian Elischer assigned = 0; 661e602ba25SJulian Elischer TAILQ_FOREACH(td2, &kg->kg_runq, td_runq) { 662e602ba25SJulian Elischer if (td2->td_priority < prevpri) { 66348bfcdddSJulian Elischer panc(string, "thread runqueue unosorted"); 66448bfcdddSJulian Elischer } 66548bfcdddSJulian Elischer if ((td2->td_state == TDS_RUNQ) && 66648bfcdddSJulian Elischer td2->td_kse && 66748bfcdddSJulian Elischer (td2->td_kse->ke_state != KES_ONRUNQ)) { 66848bfcdddSJulian Elischer panc(string, "KSE wrong state"); 669e602ba25SJulian Elischer } 670e602ba25SJulian Elischer prevpri = td2->td_priority; 671e602ba25SJulian Elischer if (td2->td_kse) { 672e602ba25SJulian Elischer assigned++; 673e602ba25SJulian Elischer if (unassigned) { 67448bfcdddSJulian Elischer panc(string, "unassigned before assigned"); 675e602ba25SJulian Elischer } 676e602ba25SJulian Elischer if (kg->kg_last_assigned == NULL) { 67748bfcdddSJulian Elischer panc(string, "lastassigned corrupt"); 678e602ba25SJulian Elischer } 679e602ba25SJulian Elischer if (saw_lastassigned) { 68048bfcdddSJulian Elischer panc(string, "last assigned not last"); 681e602ba25SJulian Elischer } 682e602ba25SJulian Elischer if (td2->td_kse->ke_thread != td2) { 68348bfcdddSJulian Elischer panc(string, "mismatched kse/thread"); 684e602ba25SJulian Elischer } 685e602ba25SJulian Elischer } else { 686e602ba25SJulian Elischer unassigned++; 687e602ba25SJulian Elischer } 688e602ba25SJulian Elischer if (td2 == kg->kg_last_assigned) { 689e602ba25SJulian Elischer saw_lastassigned = 1; 690e602ba25SJulian Elischer if (td2->td_kse == NULL) { 69148bfcdddSJulian Elischer panc(string, "last assigned not assigned"); 692e602ba25SJulian Elischer } 693e602ba25SJulian Elischer } 694e602ba25SJulian Elischer } 695e602ba25SJulian Elischer if (kg->kg_last_assigned && (saw_lastassigned == 0)) { 69648bfcdddSJulian Elischer panc(string, "where on earth does lastassigned point?"); 697e602ba25SJulian Elischer } 6985215b187SJeff Roberson #if 0 699e602ba25SJulian Elischer FOREACH_THREAD_IN_GROUP(kg, td2) { 700e602ba25SJulian Elischer if (((td2->td_flags & TDF_UNBOUND) == 0) && 70171fad9fdSJulian Elischer (TD_ON_RUNQ(td2))) { 702e602ba25SJulian Elischer assigned++; 703e602ba25SJulian Elischer if (td2->td_kse == NULL) { 70448bfcdddSJulian Elischer panc(string, "BOUND thread with no KSE"); 705e602ba25SJulian Elischer } 706e602ba25SJulian Elischer } 707e602ba25SJulian Elischer } 7085215b187SJeff Roberson #endif 709e602ba25SJulian Elischer #if 0 710e602ba25SJulian Elischer if ((unassigned + assigned) != kg->kg_runnable) { 71148bfcdddSJulian Elischer panc(string, "wrong number in runnable"); 712e602ba25SJulian Elischer } 713e602ba25SJulian Elischer #endif 714e602ba25SJulian Elischer } 71548bfcdddSJulian Elischer if (assigned == 12345) { 71648bfcdddSJulian Elischer printf("%p %p %p %p %p %d, %d", 71748bfcdddSJulian Elischer td, td2, ke, kg, p, assigned, saw_lastassigned); 71848bfcdddSJulian Elischer } 719e602ba25SJulian Elischer } 7205e3da64eSJulian Elischer #endif 721e602ba25SJulian Elischer 722