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