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> 100182da820SMatthew Dillon #include <machine/critical.h> 101dba6c5a6SPeter Wemm 102d2ac2316SJake Burkholder CTASSERT((RQB_BPW * RQB_LEN) == RQ_NQS); 103d2ac2316SJake Burkholder 104dba6c5a6SPeter Wemm /* 105d5a08a60SJake Burkholder * Global run queue. 106dba6c5a6SPeter Wemm */ 107d5a08a60SJake Burkholder static struct runq runq; 108d5a08a60SJake Burkholder SYSINIT(runq, SI_SUB_RUN_QUEUE, SI_ORDER_FIRST, runq_init, &runq) 109dba6c5a6SPeter Wemm 110e602ba25SJulian Elischer static void runq_readjust(struct runq *rq, struct kse *ke); 111e602ba25SJulian Elischer /************************************************************************ 112e602ba25SJulian Elischer * Functions that manipulate runnability from a thread perspective. * 113e602ba25SJulian Elischer ************************************************************************/ 114dba6c5a6SPeter Wemm 115e602ba25SJulian Elischer /* 116e602ba25SJulian Elischer * Select the KSE that will be run next. From that find the thread, and x 117e602ba25SJulian Elischer * remove it from the KSEGRP's run queue. If there is thread clustering, 118e602ba25SJulian Elischer * this will be what does it. 119e602ba25SJulian Elischer */ 120b40ce416SJulian Elischer struct thread * 121b40ce416SJulian Elischer choosethread(void) 122dba6c5a6SPeter Wemm { 123e602ba25SJulian Elischer struct kse *ke; 124e602ba25SJulian Elischer struct thread *td; 125e602ba25SJulian Elischer struct ksegrp *kg; 126e602ba25SJulian Elischer 127fe799533SAndrew Gallatin retry: 128e602ba25SJulian Elischer if ((ke = runq_choose(&runq))) { 129e602ba25SJulian Elischer td = ke->ke_thread; 130e602ba25SJulian Elischer KASSERT((td->td_kse == ke), ("kse/thread mismatch")); 131e602ba25SJulian Elischer kg = ke->ke_ksegrp; 132e602ba25SJulian Elischer if (td->td_flags & TDF_UNBOUND) { 133e602ba25SJulian Elischer TAILQ_REMOVE(&kg->kg_runq, td, td_runq); 134e602ba25SJulian Elischer if (kg->kg_last_assigned == td) 135e602ba25SJulian Elischer if (TAILQ_PREV(td, threadqueue, td_runq) 136e602ba25SJulian Elischer != NULL) 137e602ba25SJulian Elischer printf("Yo MAMA!\n"); 138e602ba25SJulian Elischer kg->kg_last_assigned = TAILQ_PREV(td, 139e602ba25SJulian Elischer threadqueue, td_runq); 140e602ba25SJulian Elischer /* 141e602ba25SJulian Elischer * If we have started running an upcall, 142e602ba25SJulian Elischer * Then TDF_UNBOUND WAS set because the thread was 143e602ba25SJulian Elischer * created without a KSE. Now that we have one, 144e602ba25SJulian Elischer * and it is our time to run, we make sure 145e602ba25SJulian Elischer * that BOUND semantics apply for the rest of 146e602ba25SJulian Elischer * the journey to userland, and into the UTS. 147e602ba25SJulian Elischer */ 148e602ba25SJulian Elischer #ifdef NOTYET 149e602ba25SJulian Elischer if (td->td_flags & TDF_UPCALLING) 150e602ba25SJulian Elischer tdf->td_flags &= ~TDF_UNBOUND; 151e602ba25SJulian Elischer #endif 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); 159e602ba25SJulian Elischer CTR1(KTR_RUNQ, "choosethread: td=%p (idle)", td); 160e602ba25SJulian Elischer } 161fe799533SAndrew Gallatin if (panicstr && ((td->td_proc->p_flag & P_SYSTEM) == 0 && 162fe799533SAndrew Gallatin (td->td_flags & TDF_INPANIC) == 0)) 163fe799533SAndrew Gallatin goto retry; 16433d7ad1aSJohn Baldwin td->td_state = TDS_RUNNING; 165e602ba25SJulian Elischer return (td); 166e602ba25SJulian Elischer } 167e602ba25SJulian Elischer 168e602ba25SJulian Elischer /* 169e602ba25SJulian Elischer * Given a KSE (now surplus), either assign a new runable thread to it 170e602ba25SJulian Elischer * (and put it in the run queue) or put it in the ksegrp's idle KSE list. 171e602ba25SJulian Elischer * Assumes the kse is not linked to any threads any more. (has been cleaned). 172e602ba25SJulian Elischer */ 173e602ba25SJulian Elischer void 174e602ba25SJulian Elischer kse_reassign(struct kse *ke) 175e602ba25SJulian Elischer { 176e602ba25SJulian Elischer struct ksegrp *kg; 177e602ba25SJulian Elischer struct thread *td; 178e602ba25SJulian Elischer 179e602ba25SJulian Elischer kg = ke->ke_ksegrp; 180e602ba25SJulian Elischer 181e602ba25SJulian Elischer /* 182e602ba25SJulian Elischer * Find the first unassigned thread 183e602ba25SJulian Elischer * If there is a 'last assigned' then see what's next. 184e602ba25SJulian Elischer * otherwise look at what is first. 185e602ba25SJulian Elischer */ 186e602ba25SJulian Elischer if ((td = kg->kg_last_assigned)) { 187e602ba25SJulian Elischer td = TAILQ_NEXT(td, td_runq); 188e602ba25SJulian Elischer } else { 189e602ba25SJulian Elischer td = TAILQ_FIRST(&kg->kg_runq); 190e602ba25SJulian Elischer } 191e602ba25SJulian Elischer 192e602ba25SJulian Elischer /* 193e602ba25SJulian Elischer * If we found one assign it the kse, otherwise idle the kse. 194e602ba25SJulian Elischer */ 195e602ba25SJulian Elischer if (td) { 196e602ba25SJulian Elischer kg->kg_last_assigned = td; 197e602ba25SJulian Elischer td->td_kse = ke; 198e602ba25SJulian Elischer ke->ke_thread = td; 199e602ba25SJulian Elischer runq_add(&runq, ke); 200e602ba25SJulian Elischer CTR2(KTR_RUNQ, "kse_reassign: ke%p -> td%p", ke, td); 201e602ba25SJulian Elischer } else { 202e602ba25SJulian Elischer ke->ke_state = KES_IDLE; 203e602ba25SJulian Elischer ke->ke_thread = NULL; 204e602ba25SJulian Elischer TAILQ_INSERT_HEAD(&kg->kg_iq, ke, ke_kgrlist); 205e602ba25SJulian Elischer kg->kg_idle_kses++; 206e602ba25SJulian Elischer CTR1(KTR_RUNQ, "kse_reassign: ke%p idled", ke); 207e602ba25SJulian Elischer } 208d5a08a60SJake Burkholder } 209d5a08a60SJake Burkholder 210d5a08a60SJake Burkholder int 211e602ba25SJulian Elischer kserunnable(void) 212d5a08a60SJake Burkholder { 213d5a08a60SJake Burkholder return runq_check(&runq); 214d5a08a60SJake Burkholder } 215d5a08a60SJake Burkholder 216e602ba25SJulian Elischer /* 217e602ba25SJulian Elischer * Remove a thread from its KSEGRP's run queue. 218e602ba25SJulian Elischer * This in turn may remove it from a KSE if it was already assigned 219e602ba25SJulian Elischer * to one, possibly causing a new thread to be assigned to the KSE 220e602ba25SJulian Elischer * and the KSE getting a new priority (unless it's a BOUND thread/KSE pair). 221e602ba25SJulian Elischer */ 222d5a08a60SJake Burkholder void 223b40ce416SJulian Elischer remrunqueue(struct thread *td) 224d5a08a60SJake Burkholder { 225e602ba25SJulian Elischer struct thread *td2, *td3; 226e602ba25SJulian Elischer struct ksegrp *kg; 227e602ba25SJulian Elischer struct kse *ke; 228e602ba25SJulian Elischer 229e602ba25SJulian Elischer mtx_assert(&sched_lock, MA_OWNED); 230e602ba25SJulian Elischer KASSERT ((td->td_state == TDS_RUNQ), 231e602ba25SJulian Elischer ("remrunqueue: Bad state on run queue")); 232e602ba25SJulian Elischer kg = td->td_ksegrp; 233e602ba25SJulian Elischer ke = td->td_kse; 234e602ba25SJulian Elischer /* 235e602ba25SJulian Elischer * If it's a bound thread/KSE pair, take the shortcut. All non-KSE 236e602ba25SJulian Elischer * threads are BOUND. 237e602ba25SJulian Elischer */ 238e602ba25SJulian Elischer CTR1(KTR_RUNQ, "remrunqueue: td%p", td); 239e602ba25SJulian Elischer td->td_state = TDS_UNQUEUED; 240e602ba25SJulian Elischer kg->kg_runnable--; 241e602ba25SJulian Elischer if ((td->td_flags & TDF_UNBOUND) == 0) { 242e602ba25SJulian Elischer /* Bring its kse with it, leave the thread attached */ 243e602ba25SJulian Elischer runq_remove(&runq, ke); 244c3b98db0SJulian Elischer ke->ke_state = KES_THREAD; 245e602ba25SJulian Elischer return; 246d5a08a60SJake Burkholder } 247e602ba25SJulian Elischer if (ke) { 248e602ba25SJulian Elischer /* 249e602ba25SJulian Elischer * This thread has been assigned to a KSE. 250e602ba25SJulian Elischer * We need to dissociate it and try assign the 251e602ba25SJulian Elischer * KSE to the next available thread. Then, we should 252e602ba25SJulian Elischer * see if we need to move the KSE in the run queues. 253e602ba25SJulian Elischer */ 254e602ba25SJulian Elischer td2 = kg->kg_last_assigned; 255e602ba25SJulian Elischer KASSERT((td2 != NULL), ("last assigned has wrong value ")); 256e602ba25SJulian Elischer td->td_kse = NULL; 257e602ba25SJulian Elischer if ((td3 = TAILQ_NEXT(td2, td_runq))) { 258e602ba25SJulian Elischer KASSERT(td3 != td, ("td3 somehow matched td")); 259e602ba25SJulian Elischer /* 260e602ba25SJulian Elischer * Give the next unassigned thread to the KSE 261e602ba25SJulian Elischer * so the number of runnable KSEs remains 262e602ba25SJulian Elischer * constant. 263e602ba25SJulian Elischer */ 264e602ba25SJulian Elischer td3->td_kse = ke; 265e602ba25SJulian Elischer ke->ke_thread = td3; 266e602ba25SJulian Elischer kg->kg_last_assigned = td3; 267e602ba25SJulian Elischer runq_readjust(&runq, ke); 268e602ba25SJulian Elischer } else { 269e602ba25SJulian Elischer /* 270e602ba25SJulian Elischer * There is no unassigned thread. 271e602ba25SJulian Elischer * If we were the last assigned one, 272e602ba25SJulian Elischer * adjust the last assigned pointer back 273e602ba25SJulian Elischer * one, which may result in NULL. 274e602ba25SJulian Elischer */ 275e602ba25SJulian Elischer if (td == td2) { 276e602ba25SJulian Elischer kg->kg_last_assigned = 277e602ba25SJulian Elischer TAILQ_PREV(td, threadqueue, td_runq); 278e602ba25SJulian Elischer } 279e602ba25SJulian Elischer runq_remove(&runq, ke); 280e602ba25SJulian Elischer KASSERT((ke->ke_state != KES_IDLE), 281e602ba25SJulian Elischer ("kse already idle")); 282e602ba25SJulian Elischer ke->ke_state = KES_IDLE; 283e602ba25SJulian Elischer ke->ke_thread = NULL; 284e602ba25SJulian Elischer TAILQ_INSERT_HEAD(&kg->kg_iq, ke, ke_kgrlist); 285e602ba25SJulian Elischer kg->kg_idle_kses++; 286e602ba25SJulian Elischer } 287e602ba25SJulian Elischer } 288e602ba25SJulian Elischer TAILQ_REMOVE(&kg->kg_runq, td, td_runq); 289e602ba25SJulian Elischer } 290e602ba25SJulian Elischer 291d5a08a60SJake Burkholder void 292b40ce416SJulian Elischer setrunqueue(struct thread *td) 293d5a08a60SJake Burkholder { 294e602ba25SJulian Elischer struct kse *ke; 295e602ba25SJulian Elischer struct ksegrp *kg; 296e602ba25SJulian Elischer struct thread *td2; 297e602ba25SJulian Elischer struct thread *tda; 298e602ba25SJulian Elischer 299e602ba25SJulian Elischer CTR1(KTR_RUNQ, "setrunqueue: td%p", td); 300e602ba25SJulian Elischer mtx_assert(&sched_lock, MA_OWNED); 301e602ba25SJulian Elischer KASSERT((td->td_state != TDS_RUNQ), ("setrunqueue: bad thread state")); 302e602ba25SJulian Elischer td->td_state = TDS_RUNQ; 303e602ba25SJulian Elischer kg = td->td_ksegrp; 304e602ba25SJulian Elischer kg->kg_runnable++; 305e602ba25SJulian Elischer if ((td->td_flags & TDF_UNBOUND) == 0) { 306e602ba25SJulian Elischer KASSERT((td->td_kse != NULL), 307e602ba25SJulian Elischer ("queueing BAD thread to run queue")); 308e602ba25SJulian Elischer /* 309e602ba25SJulian Elischer * Common path optimisation: Only one of everything 310e602ba25SJulian Elischer * and the KSE is always already attached. 311e602ba25SJulian Elischer * Totally ignore the ksegrp run queue. 312e602ba25SJulian Elischer */ 313b40ce416SJulian Elischer runq_add(&runq, td->td_kse); 314e602ba25SJulian Elischer return; 315e602ba25SJulian Elischer } 316e602ba25SJulian Elischer /* 317e602ba25SJulian Elischer * Ok, so we are threading with this thread. 318e602ba25SJulian Elischer * We don't have a KSE, see if we can get one.. 319e602ba25SJulian Elischer */ 320e602ba25SJulian Elischer tda = kg->kg_last_assigned; 321e602ba25SJulian Elischer if ((ke = td->td_kse) == NULL) { 322e602ba25SJulian Elischer /* 323e602ba25SJulian Elischer * We will need a KSE, see if there is one.. 324e602ba25SJulian Elischer * First look for a free one, before getting desperate. 325e602ba25SJulian Elischer * If we can't get one, our priority is not high enough.. 326e602ba25SJulian Elischer * that's ok.. 327e602ba25SJulian Elischer */ 328e602ba25SJulian Elischer if (kg->kg_idle_kses) { 329e602ba25SJulian Elischer /* 330e602ba25SJulian Elischer * There is a free one so it's ours for the asking.. 331e602ba25SJulian Elischer */ 332e602ba25SJulian Elischer ke = TAILQ_FIRST(&kg->kg_iq); 333e602ba25SJulian Elischer TAILQ_REMOVE(&kg->kg_iq, ke, ke_kgrlist); 334c3b98db0SJulian Elischer ke->ke_state = KES_THREAD; 335e602ba25SJulian Elischer kg->kg_idle_kses--; 336e602ba25SJulian Elischer } else if (tda && (tda->td_priority > td->td_priority)) { 337e602ba25SJulian Elischer /* 338e602ba25SJulian Elischer * None free, but there is one we can commandeer. 339e602ba25SJulian Elischer */ 340e602ba25SJulian Elischer ke = tda->td_kse; 341e602ba25SJulian Elischer tda->td_kse = NULL; 342e602ba25SJulian Elischer ke->ke_thread = NULL; 343e602ba25SJulian Elischer tda = kg->kg_last_assigned = 344e602ba25SJulian Elischer TAILQ_PREV(tda, threadqueue, td_runq); 345e602ba25SJulian Elischer runq_remove(&runq, ke); 346e602ba25SJulian Elischer } 347e602ba25SJulian Elischer } else { 348c3b98db0SJulian Elischer /* 349c3b98db0SJulian Elischer * Temporarily disassociate so it looks like the other cases. 350c3b98db0SJulian Elischer */ 351e602ba25SJulian Elischer ke->ke_thread = NULL; 352e602ba25SJulian Elischer td->td_kse = NULL; 353d5a08a60SJake Burkholder } 354d5a08a60SJake Burkholder 355e602ba25SJulian Elischer /* 356e602ba25SJulian Elischer * Add the thread to the ksegrp's run queue at 357e602ba25SJulian Elischer * the appropriate place. 358e602ba25SJulian Elischer */ 359e602ba25SJulian Elischer TAILQ_FOREACH(td2, &kg->kg_runq, td_runq) { 360e602ba25SJulian Elischer if (td2->td_priority > td->td_priority) { 361e602ba25SJulian Elischer TAILQ_INSERT_BEFORE(td2, td, td_runq); 362e602ba25SJulian Elischer break; 363e602ba25SJulian Elischer } 364e602ba25SJulian Elischer } 365e602ba25SJulian Elischer if (td2 == NULL) { 366e602ba25SJulian Elischer /* We ran off the end of the TAILQ or it was empty. */ 367e602ba25SJulian Elischer TAILQ_INSERT_TAIL(&kg->kg_runq, td, td_runq); 368e602ba25SJulian Elischer } 369e602ba25SJulian Elischer 370e602ba25SJulian Elischer /* 371e602ba25SJulian Elischer * If we have a ke to use, then put it on the run queue and 372e602ba25SJulian Elischer * If needed, readjust the last_assigned pointer. 373e602ba25SJulian Elischer */ 374e602ba25SJulian Elischer if (ke) { 375e602ba25SJulian Elischer if (tda == NULL) { 376e602ba25SJulian Elischer /* 377e602ba25SJulian Elischer * No pre-existing last assigned so whoever is first 378c3b98db0SJulian Elischer * gets the KSE we brought in.. (maybe us) 379e602ba25SJulian Elischer */ 380e602ba25SJulian Elischer td2 = TAILQ_FIRST(&kg->kg_runq); 381e602ba25SJulian Elischer KASSERT((td2->td_kse == NULL), 382e602ba25SJulian Elischer ("unexpected ke present")); 383e602ba25SJulian Elischer td2->td_kse = ke; 384e602ba25SJulian Elischer ke->ke_thread = td2; 385e602ba25SJulian Elischer kg->kg_last_assigned = td2; 386e602ba25SJulian Elischer } else if (tda->td_priority > td->td_priority) { 387e602ba25SJulian Elischer /* 388e602ba25SJulian Elischer * It's ours, grab it, but last_assigned is past us 389e602ba25SJulian Elischer * so don't change it. 390e602ba25SJulian Elischer */ 391e602ba25SJulian Elischer td->td_kse = ke; 392e602ba25SJulian Elischer ke->ke_thread = td; 393e602ba25SJulian Elischer } else { 394e602ba25SJulian Elischer /* 395e602ba25SJulian Elischer * We are past last_assigned, so 396e602ba25SJulian Elischer * put the new kse on whatever is next, 397e602ba25SJulian Elischer * which may or may not be us. 398e602ba25SJulian Elischer */ 399e602ba25SJulian Elischer td2 = TAILQ_NEXT(tda, td_runq); 400e602ba25SJulian Elischer kg->kg_last_assigned = td2; 401e602ba25SJulian Elischer td2->td_kse = ke; 402e602ba25SJulian Elischer ke->ke_thread = td2; 403e602ba25SJulian Elischer } 404e602ba25SJulian Elischer runq_add(&runq, ke); 405e602ba25SJulian Elischer } 406e602ba25SJulian Elischer } 407e602ba25SJulian Elischer 408e602ba25SJulian Elischer /************************************************************************ 409e602ba25SJulian Elischer * Critical section marker functions * 410e602ba25SJulian Elischer ************************************************************************/ 4117e1f6dfeSJohn Baldwin /* Critical sections that prevent preemption. */ 4127e1f6dfeSJohn Baldwin void 4137e1f6dfeSJohn Baldwin critical_enter(void) 4147e1f6dfeSJohn Baldwin { 4157e1f6dfeSJohn Baldwin struct thread *td; 4167e1f6dfeSJohn Baldwin 4177e1f6dfeSJohn Baldwin td = curthread; 4187e1f6dfeSJohn Baldwin if (td->td_critnest == 0) 419d74ac681SMatthew Dillon cpu_critical_enter(); 4207e1f6dfeSJohn Baldwin td->td_critnest++; 4217e1f6dfeSJohn Baldwin } 4227e1f6dfeSJohn Baldwin 4237e1f6dfeSJohn Baldwin void 4247e1f6dfeSJohn Baldwin critical_exit(void) 4257e1f6dfeSJohn Baldwin { 4267e1f6dfeSJohn Baldwin struct thread *td; 4277e1f6dfeSJohn Baldwin 4287e1f6dfeSJohn Baldwin td = curthread; 4297e1f6dfeSJohn Baldwin if (td->td_critnest == 1) { 4307e1f6dfeSJohn Baldwin td->td_critnest = 0; 431d74ac681SMatthew Dillon cpu_critical_exit(); 432d74ac681SMatthew Dillon } else { 4337e1f6dfeSJohn Baldwin td->td_critnest--; 4347e1f6dfeSJohn Baldwin } 435d74ac681SMatthew Dillon } 4367e1f6dfeSJohn Baldwin 437e602ba25SJulian Elischer 438e602ba25SJulian Elischer /************************************************************************ 439e602ba25SJulian Elischer * SYSTEM RUN QUEUE manipulations and tests * 440e602ba25SJulian Elischer ************************************************************************/ 441e602ba25SJulian Elischer /* 442e602ba25SJulian Elischer * Initialize a run structure. 443e602ba25SJulian Elischer */ 444e602ba25SJulian Elischer void 445e602ba25SJulian Elischer runq_init(struct runq *rq) 446e602ba25SJulian Elischer { 447e602ba25SJulian Elischer int i; 448e602ba25SJulian Elischer 449e602ba25SJulian Elischer bzero(rq, sizeof *rq); 450e602ba25SJulian Elischer for (i = 0; i < RQ_NQS; i++) 451e602ba25SJulian Elischer TAILQ_INIT(&rq->rq_queues[i]); 452e602ba25SJulian Elischer } 453e602ba25SJulian Elischer 454d5a08a60SJake Burkholder /* 455d5a08a60SJake Burkholder * Clear the status bit of the queue corresponding to priority level pri, 456d5a08a60SJake Burkholder * indicating that it is empty. 457d5a08a60SJake Burkholder */ 458d5a08a60SJake Burkholder static __inline void 459d5a08a60SJake Burkholder runq_clrbit(struct runq *rq, int pri) 460d5a08a60SJake Burkholder { 461d5a08a60SJake Burkholder struct rqbits *rqb; 462d5a08a60SJake Burkholder 463d5a08a60SJake Burkholder rqb = &rq->rq_status; 464d5a08a60SJake Burkholder CTR4(KTR_RUNQ, "runq_clrbit: bits=%#x %#x bit=%#x word=%d", 465d5a08a60SJake Burkholder rqb->rqb_bits[RQB_WORD(pri)], 466d5a08a60SJake Burkholder rqb->rqb_bits[RQB_WORD(pri)] & ~RQB_BIT(pri), 467d5a08a60SJake Burkholder RQB_BIT(pri), RQB_WORD(pri)); 468d5a08a60SJake Burkholder rqb->rqb_bits[RQB_WORD(pri)] &= ~RQB_BIT(pri); 469d5a08a60SJake Burkholder } 470d5a08a60SJake Burkholder 471d5a08a60SJake Burkholder /* 472d5a08a60SJake Burkholder * Find the index of the first non-empty run queue. This is done by 473d5a08a60SJake Burkholder * scanning the status bits, a set bit indicates a non-empty queue. 474d5a08a60SJake Burkholder */ 475d5a08a60SJake Burkholder static __inline int 476d5a08a60SJake Burkholder runq_findbit(struct runq *rq) 477d5a08a60SJake Burkholder { 478d5a08a60SJake Burkholder struct rqbits *rqb; 479d5a08a60SJake Burkholder int pri; 480d5a08a60SJake Burkholder int i; 481d5a08a60SJake Burkholder 482d5a08a60SJake Burkholder rqb = &rq->rq_status; 483d5a08a60SJake Burkholder for (i = 0; i < RQB_LEN; i++) 484d5a08a60SJake Burkholder if (rqb->rqb_bits[i]) { 4852f9267ecSPeter Wemm pri = RQB_FFS(rqb->rqb_bits[i]) + (i << RQB_L2BPW); 486d5a08a60SJake Burkholder CTR3(KTR_RUNQ, "runq_findbit: bits=%#x i=%d pri=%d", 487d5a08a60SJake Burkholder rqb->rqb_bits[i], i, pri); 488d5a08a60SJake Burkholder return (pri); 489d5a08a60SJake Burkholder } 490d5a08a60SJake Burkholder 491d5a08a60SJake Burkholder return (-1); 492d5a08a60SJake Burkholder } 493d5a08a60SJake Burkholder 494d5a08a60SJake Burkholder /* 495d5a08a60SJake Burkholder * Set the status bit of the queue corresponding to priority level pri, 496d5a08a60SJake Burkholder * indicating that it is non-empty. 497d5a08a60SJake Burkholder */ 498d5a08a60SJake Burkholder static __inline void 499d5a08a60SJake Burkholder runq_setbit(struct runq *rq, int pri) 500d5a08a60SJake Burkholder { 501d5a08a60SJake Burkholder struct rqbits *rqb; 502d5a08a60SJake Burkholder 503d5a08a60SJake Burkholder rqb = &rq->rq_status; 504d5a08a60SJake Burkholder CTR4(KTR_RUNQ, "runq_setbit: bits=%#x %#x bit=%#x word=%d", 505d5a08a60SJake Burkholder rqb->rqb_bits[RQB_WORD(pri)], 506d5a08a60SJake Burkholder rqb->rqb_bits[RQB_WORD(pri)] | RQB_BIT(pri), 507d5a08a60SJake Burkholder RQB_BIT(pri), RQB_WORD(pri)); 508d5a08a60SJake Burkholder rqb->rqb_bits[RQB_WORD(pri)] |= RQB_BIT(pri); 509d5a08a60SJake Burkholder } 510d5a08a60SJake Burkholder 511d5a08a60SJake Burkholder /* 512e602ba25SJulian Elischer * Add the KSE to the queue specified by its priority, and set the 513d5a08a60SJake Burkholder * corresponding status bit. 514d5a08a60SJake Burkholder */ 515d5a08a60SJake Burkholder void 516b40ce416SJulian Elischer runq_add(struct runq *rq, struct kse *ke) 517d5a08a60SJake Burkholder { 518d5a08a60SJake Burkholder struct rqhead *rqh; 519d5a08a60SJake Burkholder int pri; 520dba6c5a6SPeter Wemm 5210384fff8SJason Evans mtx_assert(&sched_lock, MA_OWNED); 522e602ba25SJulian Elischer KASSERT((ke->ke_thread != NULL), ("runq_add: No thread on KSE")); 523c3b98db0SJulian Elischer KASSERT((ke->ke_thread->td_kse != NULL), 524c3b98db0SJulian Elischer ("runq_add: No KSE on thread")); 525e602ba25SJulian Elischer KASSERT(ke->ke_state != KES_ONRUNQ, 526e602ba25SJulian Elischer ("runq_add: kse %p (%s) already in run queue", ke, 527e602ba25SJulian Elischer ke->ke_proc->p_comm)); 5282c100766SJulian Elischer pri = ke->ke_thread->td_priority / RQ_PPQ; 529b40ce416SJulian Elischer ke->ke_rqindex = pri; 530d5a08a60SJake Burkholder runq_setbit(rq, pri); 531d5a08a60SJake Burkholder rqh = &rq->rq_queues[pri]; 532d5a08a60SJake Burkholder CTR4(KTR_RUNQ, "runq_add: p=%p pri=%d %d rqh=%p", 5332c100766SJulian Elischer ke->ke_proc, ke->ke_thread->td_priority, pri, rqh); 534b40ce416SJulian Elischer TAILQ_INSERT_TAIL(rqh, ke, ke_procq); 535e602ba25SJulian Elischer ke->ke_ksegrp->kg_runq_kses++; 536e602ba25SJulian Elischer ke->ke_state = KES_ONRUNQ; 537dba6c5a6SPeter Wemm } 538d5a08a60SJake Burkholder 539d5a08a60SJake Burkholder /* 540d5a08a60SJake Burkholder * Return true if there are runnable processes of any priority on the run 541d5a08a60SJake Burkholder * queue, false otherwise. Has no side effects, does not modify the run 542d5a08a60SJake Burkholder * queue structure. 543d5a08a60SJake Burkholder */ 544d5a08a60SJake Burkholder int 545d5a08a60SJake Burkholder runq_check(struct runq *rq) 546d5a08a60SJake Burkholder { 547d5a08a60SJake Burkholder struct rqbits *rqb; 548d5a08a60SJake Burkholder int i; 549d5a08a60SJake Burkholder 550d5a08a60SJake Burkholder rqb = &rq->rq_status; 551d5a08a60SJake Burkholder for (i = 0; i < RQB_LEN; i++) 552d5a08a60SJake Burkholder if (rqb->rqb_bits[i]) { 553d5a08a60SJake Burkholder CTR2(KTR_RUNQ, "runq_check: bits=%#x i=%d", 554d5a08a60SJake Burkholder rqb->rqb_bits[i], i); 555d5a08a60SJake Burkholder return (1); 556dba6c5a6SPeter Wemm } 557d5a08a60SJake Burkholder CTR0(KTR_RUNQ, "runq_check: empty"); 558d5a08a60SJake Burkholder 559d5a08a60SJake Burkholder return (0); 560dba6c5a6SPeter Wemm } 561d5a08a60SJake Burkholder 562d5a08a60SJake Burkholder /* 563d5a08a60SJake Burkholder * Find and remove the highest priority process from the run queue. 564d5a08a60SJake Burkholder * If there are no runnable processes, the per-cpu idle process is 565d5a08a60SJake Burkholder * returned. Will not return NULL under any circumstances. 566d5a08a60SJake Burkholder */ 567b40ce416SJulian Elischer struct kse * 568d5a08a60SJake Burkholder runq_choose(struct runq *rq) 569d5a08a60SJake Burkholder { 570d5a08a60SJake Burkholder struct rqhead *rqh; 571b40ce416SJulian Elischer struct kse *ke; 572d5a08a60SJake Burkholder int pri; 573d5a08a60SJake Burkholder 574d5a08a60SJake Burkholder mtx_assert(&sched_lock, MA_OWNED); 575e602ba25SJulian Elischer while ((pri = runq_findbit(rq)) != -1) { 576d5a08a60SJake Burkholder rqh = &rq->rq_queues[pri]; 577b40ce416SJulian Elischer ke = TAILQ_FIRST(rqh); 578b40ce416SJulian Elischer KASSERT(ke != NULL, ("runq_choose: no proc on busy queue")); 579e602ba25SJulian Elischer CTR3(KTR_RUNQ, 580e602ba25SJulian Elischer "runq_choose: pri=%d kse=%p rqh=%p", pri, ke, rqh); 581b40ce416SJulian Elischer TAILQ_REMOVE(rqh, ke, ke_procq); 582e602ba25SJulian Elischer ke->ke_ksegrp->kg_runq_kses--; 583d5a08a60SJake Burkholder if (TAILQ_EMPTY(rqh)) { 584d5a08a60SJake Burkholder CTR0(KTR_RUNQ, "runq_choose: empty"); 585d5a08a60SJake Burkholder runq_clrbit(rq, pri); 586d5a08a60SJake Burkholder } 587e602ba25SJulian Elischer 588c3b98db0SJulian Elischer ke->ke_state = KES_THREAD; 589e602ba25SJulian Elischer KASSERT((ke->ke_thread != NULL), 590e602ba25SJulian Elischer ("runq_choose: No thread on KSE")); 591e602ba25SJulian Elischer KASSERT((ke->ke_thread->td_kse != NULL), 592e602ba25SJulian Elischer ("runq_choose: No KSE on thread")); 593b40ce416SJulian Elischer return (ke); 594d5a08a60SJake Burkholder } 595d5a08a60SJake Burkholder CTR1(KTR_RUNQ, "runq_choose: idleproc pri=%d", pri); 596d5a08a60SJake Burkholder 597e602ba25SJulian Elischer return (NULL); 598d5a08a60SJake Burkholder } 599d5a08a60SJake Burkholder 600d5a08a60SJake Burkholder /* 601e602ba25SJulian Elischer * Remove the KSE from the queue specified by its priority, and clear the 602d5a08a60SJake Burkholder * corresponding status bit if the queue becomes empty. 603e602ba25SJulian Elischer * Caller must set ke->ke_state afterwards. 604d5a08a60SJake Burkholder */ 605d5a08a60SJake Burkholder void 606b40ce416SJulian Elischer runq_remove(struct runq *rq, struct kse *ke) 607d5a08a60SJake Burkholder { 608d5a08a60SJake Burkholder struct rqhead *rqh; 609d5a08a60SJake Burkholder int pri; 610d5a08a60SJake Burkholder 611e602ba25SJulian Elischer KASSERT((ke->ke_state == KES_ONRUNQ), ("KSE not on run queue")); 612d5a08a60SJake Burkholder mtx_assert(&sched_lock, MA_OWNED); 613b40ce416SJulian Elischer pri = ke->ke_rqindex; 614d5a08a60SJake Burkholder rqh = &rq->rq_queues[pri]; 615d5a08a60SJake Burkholder CTR4(KTR_RUNQ, "runq_remove: p=%p pri=%d %d rqh=%p", 6162c100766SJulian Elischer ke, ke->ke_thread->td_priority, pri, rqh); 617b40ce416SJulian Elischer KASSERT(ke != NULL, ("runq_remove: no proc on busy queue")); 618b40ce416SJulian Elischer TAILQ_REMOVE(rqh, ke, ke_procq); 619d5a08a60SJake Burkholder if (TAILQ_EMPTY(rqh)) { 620d5a08a60SJake Burkholder CTR0(KTR_RUNQ, "runq_remove: empty"); 621d5a08a60SJake Burkholder runq_clrbit(rq, pri); 622d5a08a60SJake Burkholder } 623c3b98db0SJulian Elischer ke->ke_state = KES_THREAD; 624e602ba25SJulian Elischer ke->ke_ksegrp->kg_runq_kses--; 625dba6c5a6SPeter Wemm } 626e602ba25SJulian Elischer 627e602ba25SJulian Elischer static void 628e602ba25SJulian Elischer runq_readjust(struct runq *rq, struct kse *ke) 629e602ba25SJulian Elischer { 630e602ba25SJulian Elischer 631e602ba25SJulian Elischer if (ke->ke_rqindex != (ke->ke_thread->td_priority / RQ_PPQ)) { 632e602ba25SJulian Elischer runq_remove(rq, ke); 633e602ba25SJulian Elischer runq_add(rq, ke); 634e602ba25SJulian Elischer } 635e602ba25SJulian Elischer } 636e602ba25SJulian Elischer 6375e3da64eSJulian Elischer #if 0 638e602ba25SJulian Elischer void 639e602ba25SJulian Elischer thread_sanity_check(struct thread *td) 640e602ba25SJulian Elischer { 641e602ba25SJulian Elischer struct proc *p; 642e602ba25SJulian Elischer struct ksegrp *kg; 643e602ba25SJulian Elischer struct kse *ke; 644e602ba25SJulian Elischer struct thread *td2; 645e602ba25SJulian Elischer unsigned int prevpri; 646e602ba25SJulian Elischer int saw_lastassigned; 647e602ba25SJulian Elischer int unassigned; 648e602ba25SJulian Elischer int assigned; 649e602ba25SJulian Elischer 650e602ba25SJulian Elischer p = td->td_proc; 651e602ba25SJulian Elischer kg = td->td_ksegrp; 652e602ba25SJulian Elischer ke = td->td_kse; 653e602ba25SJulian Elischer 654e602ba25SJulian Elischer if (kg != &p->p_ksegrp) { 655e602ba25SJulian Elischer panic ("wrong ksegrp"); 656e602ba25SJulian Elischer } 657e602ba25SJulian Elischer 658e602ba25SJulian Elischer if (ke) { 659e602ba25SJulian Elischer if (ke != &p->p_kse) { 660e602ba25SJulian Elischer panic("wrong kse"); 661e602ba25SJulian Elischer } 662e602ba25SJulian Elischer if (ke->ke_thread != td) { 663e602ba25SJulian Elischer panic("wrong thread"); 664e602ba25SJulian Elischer } 665e602ba25SJulian Elischer } 666e602ba25SJulian Elischer 667e602ba25SJulian Elischer if ((p->p_flag & P_KSES) == 0) { 668e602ba25SJulian Elischer if (ke == NULL) { 669e602ba25SJulian Elischer panic("non KSE thread lost kse"); 670e602ba25SJulian Elischer } 671e602ba25SJulian Elischer } else { 672e602ba25SJulian Elischer prevpri = 0; 673e602ba25SJulian Elischer saw_lastassigned = 0; 674e602ba25SJulian Elischer unassigned = 0; 675e602ba25SJulian Elischer assigned = 0; 676e602ba25SJulian Elischer TAILQ_FOREACH(td2, &kg->kg_runq, td_runq) { 677e602ba25SJulian Elischer if (td2->td_priority < prevpri) { 678e602ba25SJulian Elischer panic("thread runqueue unosorted"); 679e602ba25SJulian Elischer } 680e602ba25SJulian Elischer prevpri = td2->td_priority; 681e602ba25SJulian Elischer if (td2->td_kse) { 682e602ba25SJulian Elischer assigned++; 683e602ba25SJulian Elischer if (unassigned) { 684e602ba25SJulian Elischer panic("unassigned before assigned"); 685e602ba25SJulian Elischer } 686e602ba25SJulian Elischer if (kg->kg_last_assigned == NULL) { 687e602ba25SJulian Elischer panic("lastassigned corrupt"); 688e602ba25SJulian Elischer } 689e602ba25SJulian Elischer if (saw_lastassigned) { 690e602ba25SJulian Elischer panic("last assigned not last"); 691e602ba25SJulian Elischer } 692e602ba25SJulian Elischer if (td2->td_kse->ke_thread != td2) { 693e602ba25SJulian Elischer panic("mismatched kse/thread"); 694e602ba25SJulian Elischer } 695e602ba25SJulian Elischer } else { 696e602ba25SJulian Elischer unassigned++; 697e602ba25SJulian Elischer } 698e602ba25SJulian Elischer if (td2 == kg->kg_last_assigned) { 699e602ba25SJulian Elischer saw_lastassigned = 1; 700e602ba25SJulian Elischer if (td2->td_kse == NULL) { 701e602ba25SJulian Elischer panic("last assigned not assigned"); 702e602ba25SJulian Elischer } 703e602ba25SJulian Elischer } 704e602ba25SJulian Elischer } 705e602ba25SJulian Elischer if (kg->kg_last_assigned && (saw_lastassigned == 0)) { 706e602ba25SJulian Elischer panic("where on earth does lastassigned point?"); 707e602ba25SJulian Elischer } 708e602ba25SJulian Elischer FOREACH_THREAD_IN_GROUP(kg, td2) { 709e602ba25SJulian Elischer if (((td2->td_flags & TDF_UNBOUND) == 0) && 710e602ba25SJulian Elischer (td2->td_state == TDS_RUNQ)) { 711e602ba25SJulian Elischer assigned++; 712e602ba25SJulian Elischer if (td2->td_kse == NULL) { 713e602ba25SJulian Elischer panic ("BOUND thread with no KSE"); 714e602ba25SJulian Elischer } 715e602ba25SJulian Elischer } 716e602ba25SJulian Elischer } 717e602ba25SJulian Elischer #if 0 718e602ba25SJulian Elischer if ((unassigned + assigned) != kg->kg_runnable) { 719e602ba25SJulian Elischer panic("wrong number in runnable"); 720e602ba25SJulian Elischer } 721e602ba25SJulian Elischer #endif 722e602ba25SJulian Elischer } 723e602ba25SJulian Elischer } 7245e3da64eSJulian Elischer #endif 725e602ba25SJulian Elischer 726