|
|
1.1 ! root 1: /* ! 2: * Mach Operating System ! 3: * Copyright (c) 1993-1987 Carnegie Mellon University ! 4: * All Rights Reserved. ! 5: * ! 6: * Permission to use, copy, modify and distribute this software and its ! 7: * documentation is hereby granted, provided that both the copyright ! 8: * notice and this permission notice appear in all copies of the ! 9: * software, derivative works or modified versions, and any portions ! 10: * thereof, and that both notices appear in supporting documentation. ! 11: * ! 12: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" ! 13: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR ! 14: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 15: * ! 16: * Carnegie Mellon requests users of this software to return to ! 17: * ! 18: * Software Distribution Coordinator or [email protected] ! 19: * School of Computer Science ! 20: * Carnegie Mellon University ! 21: * Pittsburgh PA 15213-3890 ! 22: * ! 23: * any improvements or extensions that they make and grant Carnegie Mellon ! 24: * the rights to redistribute these changes. ! 25: */ ! 26: /* ! 27: * File: sched_prim.c ! 28: * Author: Avadis Tevanian, Jr. ! 29: * Date: 1986 ! 30: * ! 31: * Scheduling primitives ! 32: * ! 33: */ ! 34: ! 35: #include <cpus.h> ! 36: #include <simple_clock.h> ! 37: #include <mach_fixpri.h> ! 38: #include <mach_host.h> ! 39: #include <hw_footprint.h> ! 40: #include <fast_tas.h> ! 41: #include <power_save.h> ! 42: ! 43: #include <mach/machine.h> ! 44: #include <kern/ast.h> ! 45: #include <kern/counters.h> ! 46: #include <kern/cpu_number.h> ! 47: #include <kern/lock.h> ! 48: #include <kern/macro_help.h> ! 49: #include <kern/processor.h> ! 50: #include <kern/queue.h> ! 51: #include <kern/sched.h> ! 52: #include <kern/sched_prim.h> ! 53: #include <kern/syscall_subr.h> ! 54: #include <kern/thread.h> ! 55: #include <kern/thread_swap.h> ! 56: #include <kern/time_out.h> ! 57: #include <vm/pmap.h> ! 58: #include <vm/vm_kern.h> ! 59: #include <vm/vm_map.h> ! 60: #include <machine/machspl.h> /* For def'n of splsched() */ ! 61: ! 62: #if MACH_FIXPRI ! 63: #include <mach/policy.h> ! 64: #endif /* MACH_FIXPRI */ ! 65: ! 66: ! 67: extern int hz; ! 68: ! 69: int min_quantum; /* defines max context switch rate */ ! 70: ! 71: unsigned sched_tick; ! 72: ! 73: #if SIMPLE_CLOCK ! 74: int sched_usec; ! 75: #endif /* SIMPLE_CLOCK */ ! 76: ! 77: thread_t sched_thread_id; ! 78: ! 79: void recompute_priorities(void); /* forward */ ! 80: void update_priority(thread_t); ! 81: void set_pri(thread_t, int, boolean_t); ! 82: void do_thread_scan(void); ! 83: ! 84: thread_t choose_pset_thread(); ! 85: ! 86: timer_elt_data_t recompute_priorities_timer; ! 87: ! 88: #if DEBUG ! 89: void checkrq(run_queue_t, char *); ! 90: void thread_check(thread_t, run_queue_t); ! 91: #endif ! 92: ! 93: /* ! 94: * State machine ! 95: * ! 96: * states are combinations of: ! 97: * R running ! 98: * W waiting (or on wait queue) ! 99: * S suspended (or will suspend) ! 100: * N non-interruptible ! 101: * ! 102: * init action ! 103: * assert_wait thread_block clear_wait suspend resume ! 104: * ! 105: * R RW, RWN R; setrun - RS - ! 106: * RS RWS, RWNS S; wake_active - - R ! 107: * RN RWN RN; setrun - RNS - ! 108: * RNS RWNS RNS; setrun - - RN ! 109: * ! 110: * RW W R RWS - ! 111: * RWN WN RN RWNS - ! 112: * RWS WS; wake_active RS - RW ! 113: * RWNS WNS RNS - RWN ! 114: * ! 115: * W R; setrun WS - ! 116: * WN RN; setrun WNS - ! 117: * WNS RNS; setrun - WN ! 118: * ! 119: * S - - R ! 120: * WS S - W ! 121: * ! 122: */ ! 123: ! 124: /* ! 125: * Waiting protocols and implementation: ! 126: * ! 127: * Each thread may be waiting for exactly one event; this event ! 128: * is set using assert_wait(). That thread may be awakened either ! 129: * by performing a thread_wakeup_prim() on its event, ! 130: * or by directly waking that thread up with clear_wait(). ! 131: * ! 132: * The implementation of wait events uses a hash table. Each ! 133: * bucket is queue of threads having the same hash function ! 134: * value; the chain for the queue (linked list) is the run queue ! 135: * field. [It is not possible to be waiting and runnable at the ! 136: * same time.] ! 137: * ! 138: * Locks on both the thread and on the hash buckets govern the ! 139: * wait event field and the queue chain field. Because wakeup ! 140: * operations only have the event as an argument, the event hash ! 141: * bucket must be locked before any thread. ! 142: * ! 143: * Scheduling operations may also occur at interrupt level; therefore, ! 144: * interrupts below splsched() must be prevented when holding ! 145: * thread or hash bucket locks. ! 146: * ! 147: * The wait event hash table declarations are as follows: ! 148: */ ! 149: ! 150: #define NUMQUEUES 59 ! 151: ! 152: queue_head_t wait_queue[NUMQUEUES]; ! 153: decl_simple_lock_data(, wait_lock[NUMQUEUES]) ! 154: ! 155: #include <oskit/types.h> ! 156: ! 157: /* NOTE: we want a small positive integer out of this */ ! 158: static inline int ! 159: wait_hash(event_t arg) ! 160: { ! 161: oskit_sreg_t event = (oskit_sreg_t)arg; ! 162: return ((event < 0 ? ~event : event) % NUMQUEUES); ! 163: } ! 164: ! 165: void wait_queue_init(void) ! 166: { ! 167: register int i; ! 168: ! 169: for (i = 0; i < NUMQUEUES; i++) { ! 170: queue_init(&wait_queue[i]); ! 171: simple_lock_init(&wait_lock[i]); ! 172: } ! 173: } ! 174: ! 175: void sched_init(void) ! 176: { ! 177: recompute_priorities_timer.fcn = (int (*)())recompute_priorities; ! 178: recompute_priorities_timer.param = (char *)0; ! 179: ! 180: min_quantum = hz / 10; /* context switch 10 times/second */ ! 181: wait_queue_init(); ! 182: pset_sys_bootstrap(); /* initialize processer mgmt. */ ! 183: queue_init(&action_queue); ! 184: simple_lock_init(&action_lock); ! 185: sched_tick = 0; ! 186: #if SIMPLE_CLOCK ! 187: sched_usec = 0; ! 188: #endif /* SIMPLE_CLOCK */ ! 189: ast_init(); ! 190: } ! 191: ! 192: /* ! 193: * Thread timeout routine, called when timer expires. ! 194: * Called at splsoftclock. ! 195: */ ! 196: void thread_timeout( ! 197: thread_t thread) ! 198: { ! 199: assert(thread->timer.set == TELT_UNSET); ! 200: ! 201: clear_wait(thread, THREAD_TIMED_OUT, FALSE); ! 202: } ! 203: ! 204: /* ! 205: * thread_set_timeout: ! 206: * ! 207: * Set a timer for the current thread, if the thread ! 208: * is ready to wait. Must be called between assert_wait() ! 209: * and thread_block(). ! 210: */ ! 211: ! 212: void thread_set_timeout( ! 213: int t) /* timeout interval in ticks */ ! 214: { ! 215: register thread_t thread = current_thread(); ! 216: register spl_t s; ! 217: ! 218: s = splsched(); ! 219: thread_lock(thread); ! 220: if ((thread->state & TH_WAIT) != 0) { ! 221: set_timeout(&thread->timer, t); ! 222: } ! 223: thread_unlock(thread); ! 224: splx(s); ! 225: } ! 226: ! 227: /* ! 228: * Set up thread timeout element when thread is created. ! 229: */ ! 230: void thread_timeout_setup( ! 231: register thread_t thread) ! 232: { ! 233: thread->timer.fcn = (int (*)())thread_timeout; ! 234: thread->timer.param = (char *)thread; ! 235: thread->depress_timer.fcn = (int (*)())thread_depress_timeout; ! 236: thread->depress_timer.param = (char *)thread; ! 237: } ! 238: ! 239: /* ! 240: * assert_wait: ! 241: * ! 242: * Assert that the current thread is about to go to ! 243: * sleep until the specified event occurs. ! 244: */ ! 245: void assert_wait( ! 246: event_t event, ! 247: boolean_t interruptible) ! 248: { ! 249: register queue_t q; ! 250: register int index; ! 251: register thread_t thread; ! 252: #if MACH_SLOCKS ! 253: register simple_lock_t lock; ! 254: #endif /* MACH_SLOCKS */ ! 255: spl_t s; ! 256: ! 257: thread = current_thread(); ! 258: if (thread->wait_event != 0) { ! 259: panic("assert_wait: already asserted event %#x\n", ! 260: thread->wait_event); ! 261: } ! 262: s = splsched(); ! 263: if (event != 0) { ! 264: index = wait_hash(event); ! 265: q = &wait_queue[index]; ! 266: #if MACH_SLOCKS ! 267: lock = &wait_lock[index]; ! 268: #endif /* MACH_SLOCKS */ ! 269: simple_lock(lock); ! 270: thread_lock(thread); ! 271: enqueue_tail(q, (queue_entry_t) thread); ! 272: thread->wait_event = event; ! 273: if (interruptible) ! 274: thread->state |= TH_WAIT; ! 275: else ! 276: thread->state |= TH_WAIT | TH_UNINT; ! 277: thread_unlock(thread); ! 278: simple_unlock(lock); ! 279: } ! 280: else { ! 281: thread_lock(thread); ! 282: if (interruptible) ! 283: thread->state |= TH_WAIT; ! 284: else ! 285: thread->state |= TH_WAIT | TH_UNINT; ! 286: thread_unlock(thread); ! 287: } ! 288: splx(s); ! 289: } ! 290: ! 291: /* ! 292: * clear_wait: ! 293: * ! 294: * Clear the wait condition for the specified thread. Start the thread ! 295: * executing if that is appropriate. ! 296: * ! 297: * parameters: ! 298: * thread thread to awaken ! 299: * result Wakeup result the thread should see ! 300: * interrupt_only Don't wake up the thread if it isn't ! 301: * interruptible. ! 302: */ ! 303: void clear_wait( ! 304: register thread_t thread, ! 305: int result, ! 306: boolean_t interrupt_only) ! 307: { ! 308: register int index; ! 309: register queue_t q; ! 310: #if MACH_SLOCKS ! 311: register simple_lock_t lock; ! 312: #endif /* MACH_SLOCKS */ ! 313: register event_t event; ! 314: spl_t s; ! 315: ! 316: s = splsched(); ! 317: thread_lock(thread); ! 318: if (interrupt_only && (thread->state & TH_UNINT)) { ! 319: /* ! 320: * can`t interrupt thread ! 321: */ ! 322: thread_unlock(thread); ! 323: splx(s); ! 324: return; ! 325: } ! 326: ! 327: event = thread->wait_event; ! 328: if (event != 0) { ! 329: thread_unlock(thread); ! 330: index = wait_hash(event); ! 331: q = &wait_queue[index]; ! 332: #if MACH_SLOCKS ! 333: lock = &wait_lock[index]; ! 334: #endif /* MACH_SLOCKS */ ! 335: simple_lock(lock); ! 336: /* ! 337: * If the thread is still waiting on that event, ! 338: * then remove it from the list. If it is waiting ! 339: * on a different event, or no event at all, then ! 340: * someone else did our job for us. ! 341: */ ! 342: thread_lock(thread); ! 343: if (thread->wait_event == event) { ! 344: remqueue(q, (queue_entry_t)thread); ! 345: thread->wait_event = 0; ! 346: event = 0; /* cause to run below */ ! 347: } ! 348: simple_unlock(lock); ! 349: } ! 350: if (event == 0) { ! 351: register int state = thread->state; ! 352: ! 353: reset_timeout_check(&thread->timer); ! 354: ! 355: switch (state & TH_SCHED_STATE) { ! 356: case TH_WAIT | TH_SUSP | TH_UNINT: ! 357: case TH_WAIT | TH_UNINT: ! 358: case TH_WAIT: ! 359: /* ! 360: * Sleeping and not suspendable - put ! 361: * on run queue. ! 362: */ ! 363: thread->state = (state &~ TH_WAIT) | TH_RUN; ! 364: thread->wait_result = result; ! 365: thread_setrun(thread, TRUE); ! 366: break; ! 367: ! 368: case TH_WAIT | TH_SUSP: ! 369: case TH_RUN | TH_WAIT: ! 370: case TH_RUN | TH_WAIT | TH_SUSP: ! 371: case TH_RUN | TH_WAIT | TH_UNINT: ! 372: case TH_RUN | TH_WAIT | TH_SUSP | TH_UNINT: ! 373: /* ! 374: * Either already running, or suspended. ! 375: */ ! 376: thread->state = state &~ TH_WAIT; ! 377: thread->wait_result = result; ! 378: break; ! 379: ! 380: default: ! 381: /* ! 382: * Not waiting. ! 383: */ ! 384: break; ! 385: } ! 386: } ! 387: thread_unlock(thread); ! 388: splx(s); ! 389: } ! 390: ! 391: static inline void __attribute__((noreturn)) ! 392: state_panic(thread_t thread, const char *caller) ! 393: { ! 394: panic ("%s: thread %x has unexpected state %x", ! 395: caller, thread, thread->state); ! 396: } ! 397: ! 398: /* ! 399: * thread_wakeup_prim: ! 400: * ! 401: * Common routine for thread_wakeup, thread_wakeup_with_result, ! 402: * and thread_wakeup_one. ! 403: * ! 404: */ ! 405: void thread_wakeup_prim( ! 406: event_t event, ! 407: boolean_t one_thread, ! 408: int result) ! 409: { ! 410: register queue_t q; ! 411: register int index; ! 412: register thread_t thread, next_th; ! 413: #if MACH_SLOCKS ! 414: register simple_lock_t lock; ! 415: #endif /* MACH_SLOCKS */ ! 416: spl_t s; ! 417: register int state; ! 418: ! 419: index = wait_hash(event); ! 420: q = &wait_queue[index]; ! 421: s = splsched(); ! 422: #if MACH_SLOCKS ! 423: lock = &wait_lock[index]; ! 424: #endif /* MACH_SLOCKS */ ! 425: simple_lock(lock); ! 426: thread = (thread_t) queue_first(q); ! 427: while (!queue_end(q, (queue_entry_t)thread)) { ! 428: next_th = (thread_t) queue_next((queue_t) thread); ! 429: ! 430: if (thread->wait_event == event) { ! 431: thread_lock(thread); ! 432: remqueue(q, (queue_entry_t) thread); ! 433: thread->wait_event = 0; ! 434: reset_timeout_check(&thread->timer); ! 435: ! 436: state = thread->state; ! 437: switch (state & TH_SCHED_STATE) { ! 438: ! 439: case TH_WAIT | TH_SUSP | TH_UNINT: ! 440: case TH_WAIT | TH_UNINT: ! 441: case TH_WAIT: ! 442: /* ! 443: * Sleeping and not suspendable - put ! 444: * on run queue. ! 445: */ ! 446: thread->state = (state &~ TH_WAIT) | TH_RUN; ! 447: thread->wait_result = result; ! 448: thread_setrun(thread, TRUE); ! 449: break; ! 450: ! 451: case TH_WAIT | TH_SUSP: ! 452: case TH_RUN | TH_WAIT: ! 453: case TH_RUN | TH_WAIT | TH_SUSP: ! 454: case TH_RUN | TH_WAIT | TH_UNINT: ! 455: case TH_RUN | TH_WAIT | TH_SUSP | TH_UNINT: ! 456: /* ! 457: * Either already running, or suspended. ! 458: */ ! 459: thread->state = state &~ TH_WAIT; ! 460: thread->wait_result = result; ! 461: break; ! 462: ! 463: default: ! 464: state_panic(thread, "thread_wakeup"); ! 465: break; ! 466: } ! 467: thread_unlock(thread); ! 468: if (one_thread) ! 469: break; ! 470: } ! 471: thread = next_th; ! 472: } ! 473: simple_unlock(lock); ! 474: splx(s); ! 475: } ! 476: ! 477: /* ! 478: * thread_sleep: ! 479: * ! 480: * Cause the current thread to wait until the specified event ! 481: * occurs. The specified lock is unlocked before releasing ! 482: * the cpu. (This is a convenient way to sleep without manually ! 483: * calling assert_wait). ! 484: */ ! 485: void thread_sleep( ! 486: event_t event, ! 487: simple_lock_t lock, ! 488: boolean_t interruptible) ! 489: { ! 490: assert_wait(event, interruptible); /* assert event */ ! 491: simple_unlock(lock); /* release the lock */ ! 492: thread_block((void (*)()) 0); /* block ourselves */ ! 493: } ! 494: ! 495: /* ! 496: * thread_bind: ! 497: * ! 498: * Force a thread to execute on the specified processor. ! 499: * If the thread is currently executing, it may wait until its ! 500: * time slice is up before switching onto the specified processor. ! 501: * ! 502: * A processor of PROCESSOR_NULL causes the thread to be unbound. ! 503: * xxx - DO NOT export this to users. ! 504: */ ! 505: void thread_bind( ! 506: register thread_t thread, ! 507: processor_t processor) ! 508: { ! 509: spl_t s; ! 510: ! 511: s = splsched(); ! 512: thread_lock(thread); ! 513: thread->bound_processor = processor; ! 514: thread_unlock(thread); ! 515: (void) splx(s); ! 516: } ! 517: ! 518: /* ! 519: * Select a thread for this processor (the current processor) to run. ! 520: * May select the current thread. ! 521: * Assumes splsched. ! 522: */ ! 523: ! 524: thread_t thread_select( ! 525: register processor_t myprocessor) ! 526: { ! 527: register thread_t thread; ! 528: ! 529: myprocessor->first_quantum = TRUE; ! 530: /* ! 531: * Check for obvious simple case; local runq is ! 532: * empty and global runq has entry at hint. ! 533: */ ! 534: if (myprocessor->runq.count > 0) { ! 535: thread = choose_thread(myprocessor); ! 536: myprocessor->quantum = min_quantum; ! 537: } ! 538: else { ! 539: register processor_set_t pset; ! 540: ! 541: #if MACH_HOST ! 542: pset = myprocessor->processor_set; ! 543: #else /* MACH_HOST */ ! 544: pset = &default_pset; ! 545: #endif /* MACH_HOST */ ! 546: simple_lock(&pset->runq.lock); ! 547: #if DEBUG ! 548: checkrq(&pset->runq, "thread_select"); ! 549: #endif /* DEBUG */ ! 550: if (pset->runq.count == 0) { ! 551: /* ! 552: * Nothing else runnable. Return if this ! 553: * thread is still runnable on this processor. ! 554: * Check for priority update if required. ! 555: */ ! 556: thread = current_thread(); ! 557: if ((thread->state == TH_RUN) && ! 558: #if MACH_HOST ! 559: (thread->processor_set == pset) && ! 560: #endif /* MACH_HOST */ ! 561: ((thread->bound_processor == PROCESSOR_NULL) || ! 562: (thread->bound_processor == myprocessor))) { ! 563: ! 564: simple_unlock(&pset->runq.lock); ! 565: thread_lock(thread); ! 566: if (thread->sched_stamp != sched_tick) ! 567: update_priority(thread); ! 568: thread_unlock(thread); ! 569: } ! 570: else { ! 571: thread = choose_pset_thread(myprocessor, pset); ! 572: } ! 573: } ! 574: else { ! 575: register queue_t q; ! 576: ! 577: /* ! 578: * If there is a thread at hint, grab it, ! 579: * else call choose_pset_thread. ! 580: */ ! 581: q = pset->runq.runq + pset->runq.low; ! 582: ! 583: if (queue_empty(q)) { ! 584: pset->runq.low++; ! 585: thread = choose_pset_thread(myprocessor, pset); ! 586: } ! 587: else { ! 588: thread = (thread_t) dequeue_head(q); ! 589: thread->runq = RUN_QUEUE_NULL; ! 590: pset->runq.count--; ! 591: #if MACH_FIXPRI ! 592: /* ! 593: * Cannot lazy evaluate pset->runq.low for ! 594: * fixed priority policy ! 595: */ ! 596: if ((pset->runq.count > 0) && ! 597: (pset->policies & POLICY_FIXEDPRI)) { ! 598: while (queue_empty(q)) { ! 599: pset->runq.low++; ! 600: q++; ! 601: } ! 602: } ! 603: #endif /* MACH_FIXPRI */ ! 604: #if DEBUG ! 605: checkrq(&pset->runq, "thread_select: after"); ! 606: #endif /* DEBUG */ ! 607: simple_unlock(&pset->runq.lock); ! 608: } ! 609: } ! 610: ! 611: #if MACH_FIXPRI ! 612: if (thread->policy == POLICY_TIMESHARE) { ! 613: #endif /* MACH_FIXPRI */ ! 614: myprocessor->quantum = pset->set_quantum; ! 615: #if MACH_FIXPRI ! 616: } ! 617: else { ! 618: /* ! 619: * POLICY_FIXEDPRI ! 620: */ ! 621: myprocessor->quantum = thread->sched_data; ! 622: } ! 623: #endif /* MACH_FIXPRI */ ! 624: } ! 625: ! 626: return thread; ! 627: } ! 628: ! 629: /* ! 630: * Stop running the current thread and start running the new thread. ! 631: * If continuation is non-zero, and the current thread is blocked, ! 632: * then it will resume by executing continuation on a new stack. ! 633: * Returns TRUE if the hand-off succeeds. ! 634: * Assumes splsched. ! 635: */ ! 636: ! 637: boolean_t thread_invoke( ! 638: register thread_t old_thread, ! 639: continuation_t continuation, ! 640: register thread_t new_thread) ! 641: { ! 642: /* ! 643: * Check for invoking the same thread. ! 644: */ ! 645: if (old_thread == new_thread) { ! 646: /* ! 647: * Mark thread interruptible. ! 648: * Run continuation if there is one. ! 649: */ ! 650: thread_lock(new_thread); ! 651: new_thread->state &= ~TH_UNINT; ! 652: thread_unlock(new_thread); ! 653: ! 654: if (continuation != (void (*)()) 0) { ! 655: (void) spl0(); ! 656: call_continuation(continuation); ! 657: /*NOTREACHED*/ ! 658: } ! 659: return TRUE; ! 660: } ! 661: ! 662: /* ! 663: * Check for stack-handoff. ! 664: */ ! 665: thread_lock(new_thread); ! 666: if ((old_thread->stack_privilege != current_stack()) && ! 667: (continuation != (void (*)()) 0)) ! 668: { ! 669: switch (new_thread->state & TH_SWAP_STATE) { ! 670: case TH_SWAPPED: ! 671: ! 672: new_thread->state &= ~(TH_SWAPPED | TH_UNINT); ! 673: thread_unlock(new_thread); ! 674: ! 675: #if NCPUS > 1 ! 676: new_thread->last_processor = current_processor(); ! 677: #endif /* NCPUS > 1 */ ! 678: ! 679: /* ! 680: * Set up ast context of new thread and ! 681: * switch to its timer. ! 682: */ ! 683: ast_context(new_thread, cpu_number()); ! 684: timer_switch(&new_thread->system_timer); ! 685: ! 686: stack_handoff(old_thread, new_thread); ! 687: ! 688: /* ! 689: * We can dispatch the old thread now. ! 690: * This is like thread_dispatch, except ! 691: * that the old thread is left swapped ! 692: * *without* freeing its stack. ! 693: * This path is also much more frequent ! 694: * than actual calls to thread_dispatch. ! 695: */ ! 696: ! 697: thread_lock(old_thread); ! 698: old_thread->swap_func = continuation; ! 699: ! 700: switch (old_thread->state) { ! 701: case TH_RUN | TH_SUSP: ! 702: case TH_RUN | TH_SUSP | TH_HALTED: ! 703: case TH_RUN | TH_WAIT | TH_SUSP: ! 704: /* ! 705: * Suspend the thread ! 706: */ ! 707: old_thread->state = (old_thread->state & ~TH_RUN) ! 708: | TH_SWAPPED; ! 709: if (old_thread->wake_active) { ! 710: old_thread->wake_active = FALSE; ! 711: thread_unlock(old_thread); ! 712: thread_wakeup((event_t)&old_thread->wake_active); ! 713: ! 714: goto after_old_thread; ! 715: } ! 716: break; ! 717: ! 718: case TH_RUN | TH_SUSP | TH_UNINT: ! 719: case TH_RUN | TH_UNINT: ! 720: case TH_RUN: ! 721: /* ! 722: * We can`t suspend the thread yet, ! 723: * or it`s still running. ! 724: * Put back on a run queue. ! 725: */ ! 726: old_thread->state |= TH_SWAPPED; ! 727: thread_setrun(old_thread, FALSE); ! 728: break; ! 729: ! 730: case TH_RUN | TH_WAIT | TH_SUSP | TH_UNINT: ! 731: case TH_RUN | TH_WAIT | TH_UNINT: ! 732: case TH_RUN | TH_WAIT: ! 733: /* ! 734: * Waiting, and not suspendable. ! 735: */ ! 736: old_thread->state = (old_thread->state & ~TH_RUN) ! 737: | TH_SWAPPED; ! 738: break; ! 739: ! 740: case TH_RUN | TH_IDLE: ! 741: /* ! 742: * Drop idle thread -- it is already in ! 743: * idle_thread_array. ! 744: */ ! 745: old_thread->state = TH_RUN | TH_IDLE | TH_SWAPPED; ! 746: break; ! 747: ! 748: default: ! 749: state_panic(old_thread, "thread_invoke"); ! 750: } ! 751: thread_unlock(old_thread); ! 752: after_old_thread: ! 753: ! 754: /* ! 755: * call_continuation calls the continuation ! 756: * after resetting the current stack pointer ! 757: * to recover stack space. If we called ! 758: * the continuation directly, we would risk ! 759: * running out of stack. ! 760: */ ! 761: ! 762: counter_always(c_thread_invoke_hits++); ! 763: (void) spl0(); ! 764: call_continuation(new_thread->swap_func); ! 765: /*NOTREACHED*/ ! 766: return TRUE; /* help for the compiler */ ! 767: ! 768: case TH_SW_COMING_IN: ! 769: /* ! 770: * Waiting for a stack ! 771: */ ! 772: thread_swapin(new_thread); ! 773: thread_unlock(new_thread); ! 774: counter_always(c_thread_invoke_misses++); ! 775: return FALSE; ! 776: ! 777: case 0: ! 778: /* ! 779: * Already has a stack - can`t handoff. ! 780: */ ! 781: break; ! 782: } ! 783: } ! 784: ! 785: else { ! 786: /* ! 787: * Check that the thread is swapped-in. ! 788: */ ! 789: if (new_thread->state & TH_SWAPPED) { ! 790: if ((new_thread->state & TH_SW_COMING_IN) || ! 791: !stack_alloc_try(new_thread, thread_continue)) ! 792: { ! 793: thread_swapin(new_thread); ! 794: thread_unlock(new_thread); ! 795: counter_always(c_thread_invoke_misses++); ! 796: return FALSE; ! 797: } ! 798: } ! 799: } ! 800: ! 801: new_thread->state &= ~(TH_SWAPPED | TH_UNINT); ! 802: thread_unlock(new_thread); ! 803: ! 804: /* ! 805: * Thread is now interruptible. ! 806: */ ! 807: #if NCPUS > 1 ! 808: new_thread->last_processor = current_processor(); ! 809: #endif /* NCPUS > 1 */ ! 810: ! 811: /* ! 812: * Set up ast context of new thread and switch to its timer. ! 813: */ ! 814: ast_context(new_thread, cpu_number()); ! 815: timer_switch(&new_thread->system_timer); ! 816: ! 817: /* ! 818: * switch_context is machine-dependent. It does the ! 819: * machine-dependent components of a context-switch, like ! 820: * changing address spaces. It updates active_threads. ! 821: * It returns only if a continuation is not supplied. ! 822: */ ! 823: counter_always(c_thread_invoke_csw++); ! 824: old_thread = switch_context(old_thread, continuation, new_thread); ! 825: ! 826: /* ! 827: * We're back. Now old_thread is the thread that resumed ! 828: * us, and we have to dispatch it. ! 829: */ ! 830: thread_dispatch(old_thread); ! 831: ! 832: return TRUE; ! 833: } ! 834: ! 835: /* ! 836: * thread_continue: ! 837: * ! 838: * Called when the current thread is given a new stack. ! 839: * Called at splsched. ! 840: */ ! 841: void thread_continue( ! 842: register thread_t old_thread) ! 843: { ! 844: register continuation_t continuation = current_thread()->swap_func; ! 845: ! 846: /* ! 847: * We must dispatch the old thread and then ! 848: * call the current thread's continuation. ! 849: * There might not be an old thread, if we are ! 850: * the first thread to run on this processor. ! 851: */ ! 852: ! 853: if (old_thread != THREAD_NULL) ! 854: thread_dispatch(old_thread); ! 855: (void) spl0(); ! 856: (*continuation)(); ! 857: /*NOTREACHED*/ ! 858: } ! 859: ! 860: ! 861: /* ! 862: * thread_block: ! 863: * ! 864: * Block the current thread. If the thread is runnable ! 865: * then someone must have woken it up between its request ! 866: * to sleep and now. In this case, it goes back on a ! 867: * run queue. ! 868: * ! 869: * If a continuation is specified, then thread_block will ! 870: * attempt to discard the thread's kernel stack. When the ! 871: * thread resumes, it will execute the continuation function ! 872: * on a new kernel stack. ! 873: */ ! 874: ! 875: void thread_block( ! 876: continuation_t continuation) ! 877: { ! 878: register thread_t thread = current_thread(); ! 879: register processor_t myprocessor = cpu_to_processor(cpu_number()); ! 880: register thread_t new_thread; ! 881: spl_t s; ! 882: ! 883: check_simple_locks(); ! 884: ! 885: s = splsched(); ! 886: ! 887: #if FAST_TAS ! 888: { ! 889: extern void recover_ras(); ! 890: ! 891: if (csw_needed(thread, myprocessor)) ! 892: recover_ras(thread); ! 893: } ! 894: #endif /* FAST_TAS */ ! 895: ! 896: ast_off(cpu_number(), AST_BLOCK); ! 897: ! 898: do ! 899: new_thread = thread_select(myprocessor); ! 900: while (!thread_invoke(thread, continuation, new_thread)); ! 901: ! 902: splx(s); ! 903: } ! 904: ! 905: /* ! 906: * thread_run: ! 907: * ! 908: * Switch directly from the current thread to a specified ! 909: * thread. Both the current and new threads must be ! 910: * runnable. ! 911: * ! 912: * If a continuation is specified, then thread_block will ! 913: * attempt to discard the current thread's kernel stack. When the ! 914: * thread resumes, it will execute the continuation function ! 915: * on a new kernel stack. ! 916: */ ! 917: void thread_run( ! 918: continuation_t continuation, ! 919: register thread_t new_thread) ! 920: { ! 921: register thread_t thread = current_thread(); ! 922: register processor_t myprocessor = cpu_to_processor(cpu_number()); ! 923: spl_t s; ! 924: ! 925: check_simple_locks(); ! 926: ! 927: s = splsched(); ! 928: ! 929: while (!thread_invoke(thread, continuation, new_thread)) ! 930: new_thread = thread_select(myprocessor); ! 931: ! 932: splx(s); ! 933: } ! 934: ! 935: /* ! 936: * Dispatches a running thread that is not on a runq. ! 937: * Called at splsched. ! 938: */ ! 939: ! 940: void thread_dispatch( ! 941: register thread_t thread) ! 942: { ! 943: /* ! 944: * If we are discarding the thread's stack, we must do it ! 945: * before the thread has a chance to run. ! 946: */ ! 947: ! 948: thread_lock(thread); ! 949: ! 950: if (thread->swap_func != (void (*)()) 0) { ! 951: assert((thread->state & TH_SWAP_STATE) == 0); ! 952: thread->state |= TH_SWAPPED; ! 953: stack_free(thread); ! 954: } ! 955: ! 956: switch (thread->state &~ TH_SWAP_STATE) { ! 957: case TH_RUN | TH_SUSP: ! 958: case TH_RUN | TH_SUSP | TH_HALTED: ! 959: case TH_RUN | TH_WAIT | TH_SUSP: ! 960: /* ! 961: * Suspend the thread ! 962: */ ! 963: thread->state &= ~TH_RUN; ! 964: if (thread->wake_active) { ! 965: thread->wake_active = FALSE; ! 966: thread_unlock(thread); ! 967: thread_wakeup((event_t)&thread->wake_active); ! 968: return; ! 969: } ! 970: break; ! 971: ! 972: case TH_RUN | TH_SUSP | TH_UNINT: ! 973: case TH_RUN | TH_UNINT: ! 974: case TH_RUN: ! 975: /* ! 976: * No reason to stop. Put back on a run queue. ! 977: */ ! 978: thread_setrun(thread, FALSE); ! 979: break; ! 980: ! 981: case TH_RUN | TH_WAIT | TH_SUSP | TH_UNINT: ! 982: case TH_RUN | TH_WAIT | TH_UNINT: ! 983: case TH_RUN | TH_WAIT: ! 984: /* ! 985: * Waiting, and not suspended. ! 986: */ ! 987: thread->state &= ~TH_RUN; ! 988: break; ! 989: ! 990: case TH_RUN | TH_IDLE: ! 991: /* ! 992: * Drop idle thread -- it is already in ! 993: * idle_thread_array. ! 994: */ ! 995: break; ! 996: ! 997: default: ! 998: state_panic(thread, "thread_dispatch"); ! 999: } ! 1000: thread_unlock(thread); ! 1001: } ! 1002: ! 1003: ! 1004: /* ! 1005: * Define shifts for simulating (5/8)**n ! 1006: */ ! 1007: ! 1008: shift_data_t wait_shift[32] = { ! 1009: {1,1},{1,3},{1,-3},{2,-7},{3,5},{3,-5},{4,-8},{5,7}, ! 1010: {5,-7},{6,-10},{7,10},{7,-9},{8,-11},{9,12},{9,-11},{10,-13}, ! 1011: {11,14},{11,-13},{12,-15},{13,17},{13,-15},{14,-17},{15,19},{16,18}, ! 1012: {16,-19},{17,22},{18,20},{18,-20},{19,26},{20,22},{20,-22},{21,-27}}; ! 1013: ! 1014: /* ! 1015: * do_priority_computation: ! 1016: * ! 1017: * Calculate new priority for thread based on its base priority plus ! 1018: * accumulated usage. PRI_SHIFT and PRI_SHIFT_2 convert from ! 1019: * usage to priorities. SCHED_SHIFT converts for the scaling ! 1020: * of the sched_usage field by SCHED_SCALE. This scaling comes ! 1021: * from the multiplication by sched_load (thread_timer_delta) ! 1022: * in sched.h. sched_load is calculated as a scaled overload ! 1023: * factor in compute_mach_factor (mach_factor.c). ! 1024: */ ! 1025: ! 1026: #ifdef PRI_SHIFT_2 ! 1027: #if PRI_SHIFT_2 > 0 ! 1028: #define do_priority_computation(th, pri) \ ! 1029: MACRO_BEGIN \ ! 1030: (pri) = (th)->priority /* start with base priority */ \ ! 1031: + ((th)->sched_usage >> (PRI_SHIFT + SCHED_SHIFT)) \ ! 1032: + ((th)->sched_usage >> (PRI_SHIFT_2 + SCHED_SHIFT)); \ ! 1033: if ((pri) > 31) (pri) = 31; \ ! 1034: MACRO_END ! 1035: #else /* PRI_SHIFT_2 */ ! 1036: #define do_priority_computation(th, pri) \ ! 1037: MACRO_BEGIN \ ! 1038: (pri) = (th)->priority /* start with base priority */ \ ! 1039: + ((th)->sched_usage >> (PRI_SHIFT + SCHED_SHIFT)) \ ! 1040: - ((th)->sched_usage >> (SCHED_SHIFT - PRI_SHIFT_2)); \ ! 1041: if ((pri) > 31) (pri) = 31; \ ! 1042: MACRO_END ! 1043: #endif /* PRI_SHIFT_2 */ ! 1044: #else /* defined(PRI_SHIFT_2) */ ! 1045: #define do_priority_computation(th, pri) \ ! 1046: MACRO_BEGIN \ ! 1047: (pri) = (th)->priority /* start with base priority */ \ ! 1048: + ((th)->sched_usage >> (PRI_SHIFT + SCHED_SHIFT)); \ ! 1049: if ((pri) > 31) (pri) = 31; \ ! 1050: MACRO_END ! 1051: #endif /* defined(PRI_SHIFT_2) */ ! 1052: ! 1053: /* ! 1054: * compute_priority: ! 1055: * ! 1056: * Compute the effective priority of the specified thread. ! 1057: * The effective priority computation is as follows: ! 1058: * ! 1059: * Take the base priority for this thread and add ! 1060: * to it an increment derived from its cpu_usage. ! 1061: * ! 1062: * The thread *must* be locked by the caller. ! 1063: */ ! 1064: ! 1065: void compute_priority( ! 1066: register thread_t thread, ! 1067: boolean_t resched) ! 1068: { ! 1069: register int pri; ! 1070: ! 1071: #if MACH_FIXPRI ! 1072: if (thread->policy == POLICY_TIMESHARE) { ! 1073: #endif /* MACH_FIXPRI */ ! 1074: do_priority_computation(thread, pri); ! 1075: if (thread->depress_priority < 0) ! 1076: set_pri(thread, pri, resched); ! 1077: else ! 1078: thread->depress_priority = pri; ! 1079: #if MACH_FIXPRI ! 1080: } ! 1081: else { ! 1082: set_pri(thread, thread->priority, resched); ! 1083: } ! 1084: #endif /* MACH_FIXPRI */ ! 1085: } ! 1086: ! 1087: /* ! 1088: * compute_my_priority: ! 1089: * ! 1090: * Version of compute priority for current thread or thread ! 1091: * being manipulated by scheduler (going on or off a runq). ! 1092: * Only used for priority updates. Policy or priority changes ! 1093: * must call compute_priority above. Caller must have thread ! 1094: * locked and know it is timesharing and not depressed. ! 1095: */ ! 1096: ! 1097: void compute_my_priority( ! 1098: register thread_t thread) ! 1099: { ! 1100: register int temp_pri; ! 1101: ! 1102: do_priority_computation(thread,temp_pri); ! 1103: thread->sched_pri = temp_pri; ! 1104: } ! 1105: ! 1106: /* ! 1107: * recompute_priorities: ! 1108: * ! 1109: * Update the priorities of all threads periodically. ! 1110: */ ! 1111: void recompute_priorities(void) ! 1112: { ! 1113: #if SIMPLE_CLOCK ! 1114: int new_usec; ! 1115: #endif /* SIMPLE_CLOCK */ ! 1116: ! 1117: sched_tick++; /* age usage one more time */ ! 1118: set_timeout(&recompute_priorities_timer, hz); ! 1119: #if SIMPLE_CLOCK ! 1120: /* ! 1121: * Compensate for clock drift. sched_usec is an ! 1122: * exponential average of the number of microseconds in ! 1123: * a second. It decays in the same fashion as cpu_usage. ! 1124: */ ! 1125: new_usec = sched_usec_elapsed(); ! 1126: sched_usec = (5*sched_usec + 3*new_usec)/8; ! 1127: #endif /* SIMPLE_CLOCK */ ! 1128: /* ! 1129: * Wakeup scheduler thread. ! 1130: */ ! 1131: if (sched_thread_id != THREAD_NULL) { ! 1132: clear_wait(sched_thread_id, THREAD_AWAKENED, FALSE); ! 1133: } ! 1134: } ! 1135: ! 1136: /* ! 1137: * update_priority ! 1138: * ! 1139: * Cause the priority computation of a thread that has been ! 1140: * sleeping or suspended to "catch up" with the system. Thread ! 1141: * *MUST* be locked by caller. If thread is running, then this ! 1142: * can only be called by the thread on itself. ! 1143: */ ! 1144: void update_priority( ! 1145: register thread_t thread) ! 1146: { ! 1147: register unsigned int ticks; ! 1148: register shift_t shiftp; ! 1149: register int temp_pri; ! 1150: ! 1151: ticks = sched_tick - thread->sched_stamp; ! 1152: ! 1153: assert(ticks != 0); ! 1154: ! 1155: /* ! 1156: * If asleep for more than 30 seconds forget all ! 1157: * cpu_usage, else catch up on missed aging. ! 1158: * 5/8 ** n is approximated by the two shifts ! 1159: * in the wait_shift array. ! 1160: */ ! 1161: thread->sched_stamp += ticks; ! 1162: thread_timer_delta(thread); ! 1163: if (ticks > 30) { ! 1164: thread->cpu_usage = 0; ! 1165: thread->sched_usage = 0; ! 1166: } ! 1167: else { ! 1168: thread->cpu_usage += thread->cpu_delta; ! 1169: thread->sched_usage += thread->sched_delta; ! 1170: shiftp = &wait_shift[ticks]; ! 1171: if (shiftp->shift2 > 0) { ! 1172: thread->cpu_usage = ! 1173: (thread->cpu_usage >> shiftp->shift1) + ! 1174: (thread->cpu_usage >> shiftp->shift2); ! 1175: thread->sched_usage = ! 1176: (thread->sched_usage >> shiftp->shift1) + ! 1177: (thread->sched_usage >> shiftp->shift2); ! 1178: } ! 1179: else { ! 1180: thread->cpu_usage = ! 1181: (thread->cpu_usage >> shiftp->shift1) - ! 1182: (thread->cpu_usage >> -(shiftp->shift2)); ! 1183: thread->sched_usage = ! 1184: (thread->sched_usage >> shiftp->shift1) - ! 1185: (thread->sched_usage >> -(shiftp->shift2)); ! 1186: } ! 1187: } ! 1188: thread->cpu_delta = 0; ! 1189: thread->sched_delta = 0; ! 1190: /* ! 1191: * Recompute priority if appropriate. ! 1192: */ ! 1193: if ( ! 1194: #if MACH_FIXPRI ! 1195: (thread->policy == POLICY_TIMESHARE) && ! 1196: #endif /* MACH_FIXPRI */ ! 1197: (thread->depress_priority < 0)) { ! 1198: do_priority_computation(thread, temp_pri); ! 1199: thread->sched_pri = temp_pri; ! 1200: } ! 1201: } ! 1202: ! 1203: /* ! 1204: * run_queue_enqueue macro for thread_setrun(). ! 1205: */ ! 1206: #if DEBUG ! 1207: #define run_queue_enqueue(rq, th) \ ! 1208: MACRO_BEGIN \ ! 1209: register unsigned int whichq; \ ! 1210: \ ! 1211: whichq = (th)->sched_pri; \ ! 1212: if (whichq >= NRQS) { \ ! 1213: printf("thread_setrun: pri too high (%d)\n", (th)->sched_pri); \ ! 1214: whichq = NRQS - 1; \ ! 1215: } \ ! 1216: \ ! 1217: simple_lock(&(rq)->lock); /* lock the run queue */ \ ! 1218: checkrq((rq), "thread_setrun: before adding thread"); \ ! 1219: enqueue_tail(&(rq)->runq[whichq], (queue_entry_t) (th)); \ ! 1220: \ ! 1221: if (whichq < (rq)->low || (rq)->count == 0) \ ! 1222: (rq)->low = whichq; /* minimize */ \ ! 1223: \ ! 1224: (rq)->count++; \ ! 1225: (th)->runq = (rq); \ ! 1226: thread_check((th), (rq)); \ ! 1227: checkrq((rq), "thread_setrun: after adding thread"); \ ! 1228: simple_unlock(&(rq)->lock); \ ! 1229: MACRO_END ! 1230: #else /* DEBUG */ ! 1231: #define run_queue_enqueue(rq, th) \ ! 1232: MACRO_BEGIN \ ! 1233: register unsigned int whichq; \ ! 1234: \ ! 1235: whichq = (th)->sched_pri; \ ! 1236: if (whichq >= NRQS) { \ ! 1237: printf("thread_setrun: pri too high (%d)\n", (th)->sched_pri); \ ! 1238: whichq = NRQS - 1; \ ! 1239: } \ ! 1240: \ ! 1241: simple_lock(&(rq)->lock); /* lock the run queue */ \ ! 1242: enqueue_tail(&(rq)->runq[whichq], (queue_entry_t) (th)); \ ! 1243: \ ! 1244: if (whichq < (rq)->low || (rq)->count == 0) \ ! 1245: (rq)->low = whichq; /* minimize */ \ ! 1246: \ ! 1247: (rq)->count++; \ ! 1248: (th)->runq = (rq); \ ! 1249: simple_unlock(&(rq)->lock); \ ! 1250: MACRO_END ! 1251: #endif /* DEBUG */ ! 1252: /* ! 1253: * thread_setrun: ! 1254: * ! 1255: * Make thread runnable; dispatch directly onto an idle processor ! 1256: * if possible. Else put on appropriate run queue (processor ! 1257: * if bound, else processor set. Caller must have lock on thread. ! 1258: * This is always called at splsched. ! 1259: */ ! 1260: ! 1261: void thread_setrun( ! 1262: register thread_t th, ! 1263: boolean_t may_preempt) ! 1264: { ! 1265: register processor_t processor; ! 1266: register run_queue_t rq; ! 1267: #if NCPUS > 1 ! 1268: register processor_set_t pset; ! 1269: #endif /* NCPUS > 1 */ ! 1270: ! 1271: /* ! 1272: * Update priority if needed. ! 1273: */ ! 1274: if (th->sched_stamp != sched_tick) { ! 1275: update_priority(th); ! 1276: } ! 1277: ! 1278: assert(th->runq == RUN_QUEUE_NULL); ! 1279: ! 1280: #if NCPUS > 1 ! 1281: /* ! 1282: * Try to dispatch the thread directly onto an idle processor. ! 1283: */ ! 1284: if ((processor = th->bound_processor) == PROCESSOR_NULL) { ! 1285: /* ! 1286: * Not bound, any processor in the processor set is ok. ! 1287: */ ! 1288: pset = th->processor_set; ! 1289: #if HW_FOOTPRINT ! 1290: /* ! 1291: * But first check the last processor it ran on. ! 1292: */ ! 1293: processor = th->last_processor; ! 1294: if (processor->state == PROCESSOR_IDLE) { ! 1295: simple_lock(&processor->lock); ! 1296: simple_lock(&pset->idle_lock); ! 1297: if ((processor->state == PROCESSOR_IDLE) ! 1298: #if MACH_HOST ! 1299: && (processor->processor_set == pset) ! 1300: #endif /* MACH_HOST */ ! 1301: ) { ! 1302: queue_remove(&pset->idle_queue, processor, ! 1303: processor_t, processor_queue); ! 1304: pset->idle_count--; ! 1305: processor->next_thread = th; ! 1306: processor->state = PROCESSOR_DISPATCHING; ! 1307: simple_unlock(&pset->idle_lock); ! 1308: simple_unlock(&processor->lock); ! 1309: return; ! 1310: } ! 1311: simple_unlock(&pset->idle_lock); ! 1312: simple_unlock(&processor->lock); ! 1313: } ! 1314: #endif /* HW_FOOTPRINT */ ! 1315: ! 1316: if (pset->idle_count > 0) { ! 1317: simple_lock(&pset->idle_lock); ! 1318: if (pset->idle_count > 0) { ! 1319: processor = (processor_t) queue_first(&pset->idle_queue); ! 1320: queue_remove(&(pset->idle_queue), processor, processor_t, ! 1321: processor_queue); ! 1322: pset->idle_count--; ! 1323: processor->next_thread = th; ! 1324: processor->state = PROCESSOR_DISPATCHING; ! 1325: simple_unlock(&pset->idle_lock); ! 1326: return; ! 1327: } ! 1328: simple_unlock(&pset->idle_lock); ! 1329: } ! 1330: rq = &(pset->runq); ! 1331: run_queue_enqueue(rq,th); ! 1332: /* ! 1333: * Preempt check ! 1334: */ ! 1335: if (may_preempt && ! 1336: #if MACH_HOST ! 1337: (pset == current_processor()->processor_set) && ! 1338: #endif /* MACH_HOST */ ! 1339: (current_thread()->sched_pri > th->sched_pri)) { ! 1340: /* ! 1341: * Turn off first_quantum to allow csw. ! 1342: */ ! 1343: current_processor()->first_quantum = FALSE; ! 1344: ast_on(cpu_number(), AST_BLOCK); ! 1345: } ! 1346: } ! 1347: else { ! 1348: /* ! 1349: * Bound, can only run on bound processor. Have to lock ! 1350: * processor here because it may not be the current one. ! 1351: */ ! 1352: if (processor->state == PROCESSOR_IDLE) { ! 1353: simple_lock(&processor->lock); ! 1354: pset = processor->processor_set; ! 1355: simple_lock(&pset->idle_lock); ! 1356: if (processor->state == PROCESSOR_IDLE) { ! 1357: queue_remove(&pset->idle_queue, processor, ! 1358: processor_t, processor_queue); ! 1359: pset->idle_count--; ! 1360: processor->next_thread = th; ! 1361: processor->state = PROCESSOR_DISPATCHING; ! 1362: simple_unlock(&pset->idle_lock); ! 1363: simple_unlock(&processor->lock); ! 1364: return; ! 1365: } ! 1366: simple_unlock(&pset->idle_lock); ! 1367: simple_unlock(&processor->lock); ! 1368: } ! 1369: rq = &(processor->runq); ! 1370: run_queue_enqueue(rq,th); ! 1371: ! 1372: /* ! 1373: * Cause ast on processor if processor is on line. ! 1374: * ! 1375: * XXX Don't do this remotely to master because this will ! 1376: * XXX send an interprocessor interrupt, and that's too ! 1377: * XXX expensive for all the unparallelized U*x code. ! 1378: */ ! 1379: if (processor == current_processor()) { ! 1380: ast_on(cpu_number(), AST_BLOCK); ! 1381: } ! 1382: else if ((processor != master_processor) && ! 1383: (processor->state != PROCESSOR_OFF_LINE)) { ! 1384: cause_ast_check(processor); ! 1385: } ! 1386: } ! 1387: #else /* NCPUS > 1 */ ! 1388: /* ! 1389: * XXX should replace queue with a boolean in this case. ! 1390: */ ! 1391: if (default_pset.idle_count > 0) { ! 1392: processor = (processor_t) queue_first(&default_pset.idle_queue); ! 1393: queue_remove(&default_pset.idle_queue, processor, ! 1394: processor_t, processor_queue); ! 1395: default_pset.idle_count--; ! 1396: processor->next_thread = th; ! 1397: processor->state = PROCESSOR_DISPATCHING; ! 1398: return; ! 1399: } ! 1400: if (th->bound_processor == PROCESSOR_NULL) { ! 1401: rq = &(default_pset.runq); ! 1402: } ! 1403: else { ! 1404: rq = &(master_processor->runq); ! 1405: ast_on(cpu_number(), AST_BLOCK); ! 1406: } ! 1407: run_queue_enqueue(rq,th); ! 1408: ! 1409: /* ! 1410: * Preempt check ! 1411: */ ! 1412: if (may_preempt && (current_thread()->sched_pri > th->sched_pri)) { ! 1413: /* ! 1414: * Turn off first_quantum to allow context switch. ! 1415: */ ! 1416: current_processor()->first_quantum = FALSE; ! 1417: ast_on(cpu_number(), AST_BLOCK); ! 1418: } ! 1419: #endif /* NCPUS > 1 */ ! 1420: } ! 1421: ! 1422: /* ! 1423: * set_pri: ! 1424: * ! 1425: * Set the priority of the specified thread to the specified ! 1426: * priority. This may cause the thread to change queues. ! 1427: * ! 1428: * The thread *must* be locked by the caller. ! 1429: */ ! 1430: ! 1431: void set_pri( ! 1432: thread_t th, ! 1433: int pri, ! 1434: boolean_t resched) ! 1435: { ! 1436: register struct run_queue *rq; ! 1437: ! 1438: rq = rem_runq(th); ! 1439: th->sched_pri = pri; ! 1440: if (rq != RUN_QUEUE_NULL) { ! 1441: if (resched) ! 1442: thread_setrun(th, TRUE); ! 1443: else ! 1444: run_queue_enqueue(rq, th); ! 1445: } ! 1446: } ! 1447: ! 1448: /* ! 1449: * rem_runq: ! 1450: * ! 1451: * Remove a thread from its run queue. ! 1452: * The run queue that the process was on is returned ! 1453: * (or RUN_QUEUE_NULL if not on a run queue). Thread *must* be locked ! 1454: * before calling this routine. Unusual locking protocol on runq ! 1455: * field in thread structure makes this code interesting; see thread.h. ! 1456: */ ! 1457: ! 1458: struct run_queue *rem_runq( ! 1459: thread_t th) ! 1460: { ! 1461: register struct run_queue *rq; ! 1462: ! 1463: rq = th->runq; ! 1464: /* ! 1465: * If rq is RUN_QUEUE_NULL, the thread will stay out of the ! 1466: * run_queues because the caller locked the thread. Otherwise ! 1467: * the thread is on a runq, but could leave. ! 1468: */ ! 1469: if (rq != RUN_QUEUE_NULL) { ! 1470: simple_lock(&rq->lock); ! 1471: #if DEBUG ! 1472: checkrq(rq, "rem_runq: at entry"); ! 1473: #endif /* DEBUG */ ! 1474: if (rq == th->runq) { ! 1475: /* ! 1476: * Thread is in a runq and we have a lock on ! 1477: * that runq. ! 1478: */ ! 1479: #if DEBUG ! 1480: checkrq(rq, "rem_runq: before removing thread"); ! 1481: thread_check(th, rq); ! 1482: #endif /* DEBUG */ ! 1483: remqueue(&rq->runq[0], (queue_entry_t) th); ! 1484: rq->count--; ! 1485: #if DEBUG ! 1486: checkrq(rq, "rem_runq: after removing thread"); ! 1487: #endif /* DEBUG */ ! 1488: th->runq = RUN_QUEUE_NULL; ! 1489: simple_unlock(&rq->lock); ! 1490: } ! 1491: else { ! 1492: /* ! 1493: * The thread left the runq before we could ! 1494: * lock the runq. It is not on a runq now, and ! 1495: * can't move again because this routine's ! 1496: * caller locked the thread. ! 1497: */ ! 1498: simple_unlock(&rq->lock); ! 1499: rq = RUN_QUEUE_NULL; ! 1500: } ! 1501: } ! 1502: ! 1503: return rq; ! 1504: } ! 1505: ! 1506: ! 1507: /* ! 1508: * choose_thread: ! 1509: * ! 1510: * Choose a thread to execute. The thread chosen is removed ! 1511: * from its run queue. Note that this requires only that the runq ! 1512: * lock be held. ! 1513: * ! 1514: * Strategy: ! 1515: * Check processor runq first; if anything found, run it. ! 1516: * Else check pset runq; if nothing found, return idle thread. ! 1517: * ! 1518: * Second line of strategy is implemented by choose_pset_thread. ! 1519: * This is only called on processor startup and when thread_block ! 1520: * thinks there's something in the processor runq. ! 1521: */ ! 1522: ! 1523: thread_t choose_thread( ! 1524: processor_t myprocessor) ! 1525: { ! 1526: thread_t th; ! 1527: register queue_t q; ! 1528: register run_queue_t runq; ! 1529: register int i; ! 1530: register processor_set_t pset; ! 1531: ! 1532: runq = &myprocessor->runq; ! 1533: ! 1534: simple_lock(&runq->lock); ! 1535: if (runq->count > 0) { ! 1536: q = runq->runq + runq->low; ! 1537: for (i = runq->low; i < NRQS ; i++, q++) { ! 1538: if (!queue_empty(q)) { ! 1539: th = (thread_t) dequeue_head(q); ! 1540: th->runq = RUN_QUEUE_NULL; ! 1541: runq->count--; ! 1542: runq->low = i; ! 1543: simple_unlock(&runq->lock); ! 1544: return th; ! 1545: } ! 1546: } ! 1547: panic("choose_thread"); ! 1548: /*NOTREACHED*/ ! 1549: } ! 1550: simple_unlock(&runq->lock); ! 1551: ! 1552: pset = myprocessor->processor_set; ! 1553: ! 1554: simple_lock(&pset->runq.lock); ! 1555: return choose_pset_thread(myprocessor,pset); ! 1556: } ! 1557: ! 1558: /* ! 1559: * choose_pset_thread: choose a thread from processor_set runq or ! 1560: * set processor idle and choose its idle thread. ! 1561: * ! 1562: * Caller must be at splsched and have a lock on the runq. This ! 1563: * lock is released by this routine. myprocessor is always the current ! 1564: * processor, and pset must be its processor set. ! 1565: * This routine chooses and removes a thread from the runq if there ! 1566: * is one (and returns it), else it sets the processor idle and ! 1567: * returns its idle thread. ! 1568: */ ! 1569: ! 1570: thread_t choose_pset_thread( ! 1571: register processor_t myprocessor, ! 1572: processor_set_t pset) ! 1573: { ! 1574: register run_queue_t runq; ! 1575: register thread_t th; ! 1576: register queue_t q; ! 1577: register int i; ! 1578: ! 1579: runq = &pset->runq; ! 1580: ! 1581: if (runq->count > 0) { ! 1582: q = runq->runq + runq->low; ! 1583: for (i = runq->low; i < NRQS ; i++, q++) { ! 1584: if (!queue_empty(q)) { ! 1585: th = (thread_t) dequeue_head(q); ! 1586: th->runq = RUN_QUEUE_NULL; ! 1587: runq->count--; ! 1588: /* ! 1589: * For POLICY_FIXEDPRI, runq->low must be ! 1590: * accurate! ! 1591: */ ! 1592: #if MACH_FIXPRI ! 1593: if ((runq->count > 0) && ! 1594: (pset->policies & POLICY_FIXEDPRI)) { ! 1595: while (queue_empty(q)) { ! 1596: q++; ! 1597: i++; ! 1598: } ! 1599: } ! 1600: #endif /* MACH_FIXPRI */ ! 1601: runq->low = i; ! 1602: #if DEBUG ! 1603: checkrq(runq, "choose_pset_thread"); ! 1604: #endif /* DEBUG */ ! 1605: simple_unlock(&runq->lock); ! 1606: return th; ! 1607: } ! 1608: } ! 1609: panic("choose_pset_thread"); ! 1610: /*NOTREACHED*/ ! 1611: } ! 1612: simple_unlock(&runq->lock); ! 1613: ! 1614: /* ! 1615: * Nothing is runnable, so set this processor idle if it ! 1616: * was running. If it was in an assignment or shutdown, ! 1617: * leave it alone. Return its idle thread. ! 1618: */ ! 1619: simple_lock(&pset->idle_lock); ! 1620: if (myprocessor->state == PROCESSOR_RUNNING) { ! 1621: myprocessor->state = PROCESSOR_IDLE; ! 1622: /* ! 1623: * XXX Until it goes away, put master on end of queue, others ! 1624: * XXX on front so master gets used last. ! 1625: */ ! 1626: if (myprocessor == master_processor) { ! 1627: queue_enter(&(pset->idle_queue), myprocessor, ! 1628: processor_t, processor_queue); ! 1629: } ! 1630: else { ! 1631: queue_enter_first(&(pset->idle_queue), myprocessor, ! 1632: processor_t, processor_queue); ! 1633: } ! 1634: ! 1635: pset->idle_count++; ! 1636: } ! 1637: simple_unlock(&pset->idle_lock); ! 1638: ! 1639: return myprocessor->idle_thread; ! 1640: } ! 1641: ! 1642: /* ! 1643: * no_dispatch_count counts number of times processors go non-idle ! 1644: * without being dispatched. This should be very rare. ! 1645: */ ! 1646: int no_dispatch_count = 0; ! 1647: ! 1648: /* ! 1649: * This is the idle thread, which just looks for other threads ! 1650: * to execute. ! 1651: */ ! 1652: ! 1653: void idle_thread_continue(void) ! 1654: { ! 1655: register processor_t myprocessor; ! 1656: register volatile thread_t *threadp; ! 1657: register volatile int *gcount; ! 1658: register volatile int *lcount; ! 1659: register thread_t new_thread; ! 1660: register int state; ! 1661: int mycpu; ! 1662: spl_t s; ! 1663: ! 1664: mycpu = cpu_number(); ! 1665: myprocessor = current_processor(); ! 1666: threadp = (volatile thread_t *) &myprocessor->next_thread; ! 1667: lcount = (volatile int *) &myprocessor->runq.count; ! 1668: ! 1669: while (TRUE) { ! 1670: #ifdef MARK_CPU_IDLE ! 1671: MARK_CPU_IDLE(mycpu); ! 1672: #endif /* MARK_CPU_IDLE */ ! 1673: ! 1674: #if MACH_HOST ! 1675: gcount = (volatile int *) ! 1676: &myprocessor->processor_set->runq.count; ! 1677: #else /* MACH_HOST */ ! 1678: gcount = (volatile int *) &default_pset.runq.count; ! 1679: #endif /* MACH_HOST */ ! 1680: ! 1681: /* ! 1682: * This cpu will be dispatched (by thread_setrun) by setting next_thread ! 1683: * to the value of the thread to run next. Also check runq counts. ! 1684: */ ! 1685: while ((*threadp == (volatile thread_t)THREAD_NULL) && ! 1686: (*gcount == 0) && (*lcount == 0)) { ! 1687: ! 1688: /* check for ASTs while we wait */ ! 1689: ! 1690: if (need_ast[mycpu] &~ AST_SCHEDULING) { ! 1691: (void) splsched(); ! 1692: /* don't allow scheduling ASTs */ ! 1693: need_ast[mycpu] &= ~AST_SCHEDULING; ! 1694: ast_taken(); ! 1695: /* back at spl0 */ ! 1696: } ! 1697: ! 1698: /* ! 1699: * machine_idle is a machine dependent function, ! 1700: * to conserve power. ! 1701: */ ! 1702: #if POWER_SAVE ! 1703: machine_idle(mycpu); ! 1704: #endif /* POWER_SAVE */ ! 1705: } ! 1706: ! 1707: #ifdef MARK_CPU_ACTIVE ! 1708: MARK_CPU_ACTIVE(mycpu); ! 1709: #endif /* MARK_CPU_ACTIVE */ ! 1710: ! 1711: s = splsched(); ! 1712: ! 1713: /* ! 1714: * This is not a switch statement to avoid the ! 1715: * bounds checking code in the common case. ! 1716: */ ! 1717: retry: ! 1718: state = myprocessor->state; ! 1719: if (state == PROCESSOR_DISPATCHING) { ! 1720: /* ! 1721: * Commmon case -- cpu dispatched. ! 1722: */ ! 1723: new_thread = (thread_t) *threadp; ! 1724: *threadp = (volatile thread_t) THREAD_NULL; ! 1725: myprocessor->state = PROCESSOR_RUNNING; ! 1726: /* ! 1727: * set up quantum for new thread. ! 1728: */ ! 1729: #if MACH_FIXPRI ! 1730: if (new_thread->policy == POLICY_TIMESHARE) { ! 1731: #endif /* MACH_FIXPRI */ ! 1732: /* ! 1733: * Just use set quantum. No point in ! 1734: * checking for shorter local runq quantum; ! 1735: * csw_needed will handle correctly. ! 1736: */ ! 1737: #if MACH_HOST ! 1738: myprocessor->quantum = new_thread-> ! 1739: processor_set->set_quantum; ! 1740: #else /* MACH_HOST */ ! 1741: myprocessor->quantum = ! 1742: default_pset.set_quantum; ! 1743: #endif /* MACH_HOST */ ! 1744: ! 1745: #if MACH_FIXPRI ! 1746: } ! 1747: else { ! 1748: /* ! 1749: * POLICY_FIXEDPRI ! 1750: */ ! 1751: myprocessor->quantum = new_thread->sched_data; ! 1752: } ! 1753: #endif /* MACH_FIXPRI */ ! 1754: myprocessor->first_quantum = TRUE; ! 1755: counter(c_idle_thread_handoff++); ! 1756: thread_run(idle_thread_continue, new_thread); ! 1757: } ! 1758: else if (state == PROCESSOR_IDLE) { ! 1759: register processor_set_t pset; ! 1760: ! 1761: pset = myprocessor->processor_set; ! 1762: simple_lock(&pset->idle_lock); ! 1763: if (myprocessor->state != PROCESSOR_IDLE) { ! 1764: /* ! 1765: * Something happened, try again. ! 1766: */ ! 1767: simple_unlock(&pset->idle_lock); ! 1768: goto retry; ! 1769: } ! 1770: /* ! 1771: * Processor was not dispatched (Rare). ! 1772: * Set it running again. ! 1773: */ ! 1774: no_dispatch_count++; ! 1775: pset->idle_count--; ! 1776: queue_remove(&pset->idle_queue, myprocessor, ! 1777: processor_t, processor_queue); ! 1778: myprocessor->state = PROCESSOR_RUNNING; ! 1779: simple_unlock(&pset->idle_lock); ! 1780: counter(c_idle_thread_block++); ! 1781: thread_block(idle_thread_continue); ! 1782: } ! 1783: else if ((state == PROCESSOR_ASSIGN) || ! 1784: (state == PROCESSOR_SHUTDOWN)) { ! 1785: /* ! 1786: * Changing processor sets, or going off-line. ! 1787: * Release next_thread if there is one. Actual ! 1788: * thread to run is on a runq. ! 1789: */ ! 1790: if ((new_thread = (thread_t)*threadp)!= THREAD_NULL) { ! 1791: *threadp = (volatile thread_t) THREAD_NULL; ! 1792: thread_setrun(new_thread, FALSE); ! 1793: } ! 1794: ! 1795: counter(c_idle_thread_block++); ! 1796: thread_block(idle_thread_continue); ! 1797: } ! 1798: else { ! 1799: printf(" Bad processor state %d (Cpu %d)\n", ! 1800: cpu_state(mycpu), mycpu); ! 1801: panic("idle_thread"); ! 1802: } ! 1803: ! 1804: (void) splx(s); ! 1805: } ! 1806: } ! 1807: ! 1808: void idle_thread(void) ! 1809: { ! 1810: register thread_t self = current_thread(); ! 1811: spl_t s; ! 1812: ! 1813: stack_privilege(self); ! 1814: ! 1815: s = splsched(); ! 1816: self->priority = 31; ! 1817: self->sched_pri = 31; ! 1818: ! 1819: /* ! 1820: * Set the idle flag to indicate that this is an idle thread, ! 1821: * enter ourselves in the idle array, and thread_block() to get ! 1822: * out of the run queues (and set the processor idle when we ! 1823: * run next time). ! 1824: */ ! 1825: thread_lock(self); ! 1826: self->state |= TH_IDLE; ! 1827: thread_unlock(self); ! 1828: current_processor()->idle_thread = self; ! 1829: (void) splx(s); ! 1830: ! 1831: counter(c_idle_thread_block++); ! 1832: thread_block(idle_thread_continue); ! 1833: idle_thread_continue(); ! 1834: /*NOTREACHED*/ ! 1835: } ! 1836: ! 1837: /* ! 1838: * sched_thread: scheduler thread. ! 1839: * ! 1840: * This thread handles periodic calculations in the scheduler that ! 1841: * we don't want to do at interrupt level. This allows us to ! 1842: * avoid blocking. ! 1843: */ ! 1844: void sched_thread_continue(void) ! 1845: { ! 1846: while (TRUE) { ! 1847: (void) compute_mach_factor(); ! 1848: ! 1849: /* ! 1850: * Check for stuck threads. This can't be done off of ! 1851: * the callout queue because it requires operations that ! 1852: * can't be used from interrupt level. ! 1853: */ ! 1854: if (sched_tick & 1) ! 1855: do_thread_scan(); ! 1856: ! 1857: assert_wait((event_t) 0, FALSE); ! 1858: counter(c_sched_thread_block++); ! 1859: thread_block(sched_thread_continue); ! 1860: } ! 1861: } ! 1862: ! 1863: void sched_thread(void) ! 1864: { ! 1865: sched_thread_id = current_thread(); ! 1866: ! 1867: /* ! 1868: * Sleep on event 0, recompute_priorities() will awaken ! 1869: * us by calling clear_wait(). ! 1870: */ ! 1871: assert_wait((event_t) 0, FALSE); ! 1872: counter(c_sched_thread_block++); ! 1873: thread_block(sched_thread_continue); ! 1874: sched_thread_continue(); ! 1875: /*NOTREACHED*/ ! 1876: } ! 1877: ! 1878: #define MAX_STUCK_THREADS 16 ! 1879: ! 1880: /* ! 1881: * do_thread_scan: scan for stuck threads. A thread is stuck if ! 1882: * it is runnable but its priority is so low that it has not ! 1883: * run for several seconds. Its priority should be higher, but ! 1884: * won't be until it runs and calls update_priority. The scanner ! 1885: * finds these threads and does the updates. ! 1886: * ! 1887: * Scanner runs in two passes. Pass one squirrels likely ! 1888: * thread ids away in an array, and removes them from the run queue. ! 1889: * Pass two does the priority updates. This is necessary because ! 1890: * the run queue lock is required for the candidate scan, but ! 1891: * cannot be held during updates [set_pri will deadlock]. ! 1892: * ! 1893: * Array length should be enough so that restart isn't necessary, ! 1894: * but restart logic is included. Does not scan processor runqs. ! 1895: * ! 1896: */ ! 1897: ! 1898: boolean_t do_thread_scan_debug = FALSE; ! 1899: ! 1900: thread_t stuck_threads[MAX_STUCK_THREADS]; ! 1901: int stuck_count = 0; ! 1902: ! 1903: /* ! 1904: * do_runq_scan is the guts of pass 1. It scans a runq for ! 1905: * stuck threads. A boolean is returned indicating whether ! 1906: * it ran out of space. ! 1907: */ ! 1908: ! 1909: boolean_t ! 1910: do_runq_scan( ! 1911: run_queue_t runq) ! 1912: { ! 1913: register spl_t s; ! 1914: register queue_t q; ! 1915: register thread_t thread; ! 1916: register int count; ! 1917: ! 1918: s = splsched(); ! 1919: simple_lock(&runq->lock); ! 1920: if((count = runq->count) > 0) { ! 1921: q = runq->runq + runq->low; ! 1922: while (count > 0) { ! 1923: thread = (thread_t) queue_first(q); ! 1924: while (!queue_end(q, (queue_entry_t) thread)) { ! 1925: /* ! 1926: * Get the next thread now, since we may ! 1927: * remove this thread from the run queue. ! 1928: */ ! 1929: thread_t next = (thread_t) queue_next(&thread->links); ! 1930: ! 1931: if ((thread->state & TH_SCHED_STATE) == TH_RUN && ! 1932: sched_tick - thread->sched_stamp > 1) { ! 1933: /* ! 1934: * Stuck, save its id for later. ! 1935: */ ! 1936: if (stuck_count == MAX_STUCK_THREADS) { ! 1937: /* ! 1938: * !@#$% No more room. ! 1939: */ ! 1940: simple_unlock(&runq->lock); ! 1941: splx(s); ! 1942: return TRUE; ! 1943: } ! 1944: /* ! 1945: * We can`t take the thread_lock here, ! 1946: * since we already have the runq lock. ! 1947: * So we can`t grab a reference to the ! 1948: * thread. However, a thread that is ! 1949: * in RUN state cannot be deallocated ! 1950: * until it stops running. If it isn`t ! 1951: * on the runq, then thread_halt cannot ! 1952: * see it. So we remove the thread ! 1953: * from the runq to make it safe. ! 1954: */ ! 1955: remqueue(q, (queue_entry_t) thread); ! 1956: runq->count--; ! 1957: thread->runq = RUN_QUEUE_NULL; ! 1958: ! 1959: stuck_threads[stuck_count++] = thread; ! 1960: if (do_thread_scan_debug) ! 1961: printf("do_runq_scan: adding thread %#x\n", thread); ! 1962: } ! 1963: count--; ! 1964: thread = next; ! 1965: } ! 1966: q++; ! 1967: } ! 1968: } ! 1969: simple_unlock(&runq->lock); ! 1970: splx(s); ! 1971: ! 1972: return FALSE; ! 1973: } ! 1974: ! 1975: void do_thread_scan(void) ! 1976: { ! 1977: register spl_t s; ! 1978: register boolean_t restart_needed = 0; ! 1979: register thread_t thread; ! 1980: #if MACH_HOST ! 1981: register processor_set_t pset; ! 1982: #endif /* MACH_HOST */ ! 1983: ! 1984: do { ! 1985: #if MACH_HOST ! 1986: simple_lock(&all_psets_lock); ! 1987: queue_iterate(&all_psets, pset, processor_set_t, all_psets) { ! 1988: if (restart_needed = do_runq_scan(&pset->runq)) ! 1989: break; ! 1990: } ! 1991: simple_unlock(&all_psets_lock); ! 1992: #else /* MACH_HOST */ ! 1993: restart_needed = do_runq_scan(&default_pset.runq); ! 1994: #endif /* MACH_HOST */ ! 1995: if (!restart_needed) ! 1996: restart_needed = do_runq_scan(&master_processor->runq); ! 1997: ! 1998: /* ! 1999: * Ok, we now have a collection of candidates -- fix them. ! 2000: */ ! 2001: ! 2002: while (stuck_count > 0) { ! 2003: thread = stuck_threads[--stuck_count]; ! 2004: stuck_threads[stuck_count] = THREAD_NULL; ! 2005: s = splsched(); ! 2006: thread_lock(thread); ! 2007: if ((thread->state & TH_SCHED_STATE) == TH_RUN) { ! 2008: /* ! 2009: * Do the priority update. Call ! 2010: * thread_setrun because thread is ! 2011: * off the run queues. ! 2012: */ ! 2013: update_priority(thread); ! 2014: thread_setrun(thread, TRUE); ! 2015: } ! 2016: thread_unlock(thread); ! 2017: splx(s); ! 2018: } ! 2019: } while (restart_needed); ! 2020: } ! 2021: ! 2022: #if DEBUG ! 2023: void checkrq( ! 2024: run_queue_t rq, ! 2025: char *msg) ! 2026: { ! 2027: register queue_t q1; ! 2028: register int i, j; ! 2029: register queue_entry_t e; ! 2030: register int low; ! 2031: ! 2032: low = -1; ! 2033: j = 0; ! 2034: q1 = rq->runq; ! 2035: for (i = 0; i < NRQS; i++) { ! 2036: if (q1->next == q1) { ! 2037: if (q1->prev != q1) ! 2038: panic("checkrq: empty at %s", msg); ! 2039: } ! 2040: else { ! 2041: if (low == -1) ! 2042: low = i; ! 2043: ! 2044: for (e = q1->next; e != q1; e = e->next) { ! 2045: j++; ! 2046: if (e->next->prev != e) ! 2047: panic("checkrq-2 at %s", msg); ! 2048: if (e->prev->next != e) ! 2049: panic("checkrq-3 at %s", msg); ! 2050: } ! 2051: } ! 2052: q1++; ! 2053: } ! 2054: if (j != rq->count) ! 2055: panic("checkrq: count wrong at %s", msg); ! 2056: if (rq->count != 0 && low < rq->low) ! 2057: panic("checkrq: low wrong at %s", msg); ! 2058: } ! 2059: ! 2060: void thread_check( ! 2061: register thread_t th, ! 2062: register run_queue_t rq) ! 2063: { ! 2064: register unsigned int whichq; ! 2065: ! 2066: whichq = th->sched_pri; ! 2067: if (whichq >= NRQS) { ! 2068: printf("thread_check: priority too high\n"); ! 2069: whichq = NRQS-1; ! 2070: } ! 2071: if ((th->links.next == &rq->runq[whichq]) && ! 2072: (rq->runq[whichq].prev != (queue_entry_t)th)) ! 2073: panic("thread_check"); ! 2074: } ! 2075: #endif /* DEBUG */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.