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