|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * @OSF_FREE_COPYRIGHT@ ! 24: */ ! 25: /* ! 26: * Mach Operating System ! 27: * Copyright (c) 1991,1990,1989,1988,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: */ ! 52: /* ! 53: * File: sched_prim.c ! 54: * Author: Avadis Tevanian, Jr. ! 55: * Date: 1986 ! 56: * ! 57: * Scheduling primitives ! 58: * ! 59: */ ! 60: ! 61: #include <debug.h> ! 62: #include <cpus.h> ! 63: #include <mach_kdb.h> ! 64: #include <simple_clock.h> ! 65: #include <mach_host.h> ! 66: #include <power_save.h> ! 67: #include <task_swapper.h> ! 68: ! 69: #include <ddb/db_output.h> ! 70: #include <mach/machine.h> ! 71: #include <machine/machine_routines.h> ! 72: #include <machine/sched_param.h> ! 73: #include <kern/ast.h> ! 74: #include <kern/clock.h> ! 75: #include <kern/counters.h> ! 76: #include <kern/cpu_number.h> ! 77: #include <kern/cpu_data.h> ! 78: #include <kern/etap_macros.h> ! 79: #include <kern/lock.h> ! 80: #include <kern/macro_help.h> ! 81: #include <kern/machine.h> ! 82: #include <kern/misc_protos.h> ! 83: #include <kern/processor.h> ! 84: #include <kern/queue.h> ! 85: #include <kern/sched.h> ! 86: #include <kern/sched_prim.h> ! 87: #include <kern/syscall_subr.h> ! 88: #include <kern/task.h> ! 89: #include <kern/thread.h> ! 90: #include <kern/thread_swap.h> ! 91: #include <vm/pmap.h> ! 92: #include <vm/vm_kern.h> ! 93: #include <vm/vm_map.h> ! 94: #include <mach/policy.h> ! 95: #include <mach/sync_policy.h> ! 96: #include <kern/sf.h> ! 97: #include <kern/mk_sp.h> /*** ??? fix so this can be removed ***/ ! 98: #include <sys/kdebug.h> ! 99: ! 100: #if TASK_SWAPPER ! 101: #include <kern/task_swap.h> ! 102: extern int task_swap_on; ! 103: #endif /* TASK_SWAPPER */ ! 104: ! 105: extern int hz; ! 106: ! 107: #define DEFAULT_PREEMPTION_RATE 100 /* (1/s) */ ! 108: int default_preemption_rate = DEFAULT_PREEMPTION_RATE; ! 109: int min_quantum; ! 110: ! 111: unsigned sched_tick; ! 112: ! 113: #if SIMPLE_CLOCK ! 114: int sched_usec; ! 115: #endif /* SIMPLE_CLOCK */ ! 116: ! 117: /* Forwards */ ! 118: void thread_continue(thread_t); ! 119: ! 120: void wait_queues_init(void); ! 121: ! 122: void set_pri( ! 123: thread_t thread, ! 124: int pri, ! 125: int resched); ! 126: ! 127: thread_t choose_pset_thread( ! 128: processor_t myprocessor, ! 129: processor_set_t pset); ! 130: ! 131: thread_t choose_thread( ! 132: processor_t myprocessor); ! 133: ! 134: int run_queue_enqueue( ! 135: run_queue_t runq, ! 136: thread_t thread, ! 137: boolean_t tail); ! 138: ! 139: void idle_thread_continue(void); ! 140: void do_thread_scan(void); ! 141: ! 142: static ! 143: void clear_wait_internal( ! 144: thread_t thread, ! 145: int result); ! 146: ! 147: ! 148: void dump_run_queues(run_queue_t); ! 149: void dump_run_queue_struct( run_queue_t ); ! 150: void dump_processor( processor_t ); ! 151: void dump_processor_set( processor_set_t ); ! 152: ! 153: #if DEBUG ! 154: void checkrq( ! 155: run_queue_t rq, ! 156: char *msg); ! 157: ! 158: void thread_check( ! 159: thread_t thread, ! 160: run_queue_t runq); ! 161: #endif /*DEBUG*/ ! 162: ! 163: boolean_t thread_runnable( ! 164: thread_t thread); ! 165: ! 166: /* ! 167: * State machine ! 168: * ! 169: * states are combinations of: ! 170: * R running ! 171: * W waiting (or on wait queue) ! 172: * N non-interruptible ! 173: * O swapped out ! 174: * I being swapped in ! 175: * ! 176: * init action ! 177: * assert_wait thread_block clear_wait swapout swapin ! 178: * ! 179: * R RW, RWN R; setrun - - ! 180: * RN RWN RN; setrun - - ! 181: * ! 182: * RW W R - ! 183: * RWN WN RN - ! 184: * ! 185: * W R; setrun WO ! 186: * WN RN; setrun - ! 187: * ! 188: * RO - - R ! 189: * ! 190: */ ! 191: ! 192: /* ! 193: * Waiting protocols and implementation: ! 194: * ! 195: * Each thread may be waiting for exactly one event; this event ! 196: * is set using assert_wait(). That thread may be awakened either ! 197: * by performing a thread_wakeup_prim() on its event, ! 198: * or by directly waking that thread up with clear_wait(). ! 199: * ! 200: * The implementation of wait events uses a hash table. Each ! 201: * bucket is queue of threads having the same hash function ! 202: * value; the chain for the queue (linked list) is the run queue ! 203: * field. [It is not possible to be waiting and runnable at the ! 204: * same time.] ! 205: * ! 206: * Locks on both the thread and on the hash buckets govern the ! 207: * wait event field and the queue chain field. Because wakeup ! 208: * operations only have the event as an argument, the event hash ! 209: * bucket must be locked before any thread. ! 210: * ! 211: * Scheduling operations may also occur at interrupt level; therefore, ! 212: * interrupts below splsched() must be prevented when holding ! 213: * thread or hash bucket locks. ! 214: * ! 215: * The wait event hash table declarations are as follows: ! 216: */ ! 217: ! 218: #define NUMQUEUES 59 ! 219: ! 220: struct wait_queue wait_queues[NUMQUEUES]; ! 221: ! 222: #define wait_hash(event) \ ! 223: ((((int)(event) < 0)? ~(int)(event): (int)(event)) % NUMQUEUES) ! 224: ! 225: void ! 226: sched_init(void) ! 227: { ! 228: /* ! 229: * Calculate the minimum quantum ! 230: * in ticks. ! 231: */ ! 232: if (default_preemption_rate < 1) ! 233: default_preemption_rate = DEFAULT_PREEMPTION_RATE; ! 234: min_quantum = hz / default_preemption_rate; ! 235: /* ! 236: * Round up result (4/5) to an ! 237: * integral number of ticks. ! 238: */ ! 239: if (((hz * 10) / default_preemption_rate) - (min_quantum * 10) >= 5) ! 240: min_quantum++; ! 241: if (min_quantum < 1) ! 242: min_quantum = 1; ! 243: printf("minimum scheduling quantum is %d ms\n", (1000 / hz) * min_quantum); ! 244: ! 245: wait_queues_init(); ! 246: pset_sys_bootstrap(); /* initialize processer mgmt. */ ! 247: queue_init(&action_queue); ! 248: simple_lock_init(&action_lock, ETAP_THREAD_ACTION); ! 249: sched_tick = 0; ! 250: #if SIMPLE_CLOCK ! 251: sched_usec = 0; ! 252: #endif /* SIMPLE_CLOCK */ ! 253: ast_init(); ! 254: /*** ??? is this the right place?***/ ! 255: sf_init(); ! 256: } ! 257: ! 258: void ! 259: wait_queues_init(void) ! 260: { ! 261: register int i; ! 262: ! 263: for (i = 0; i < NUMQUEUES; i++) { ! 264: wait_queue_init(&wait_queues[i], SYNC_POLICY_FIFO); ! 265: } ! 266: } ! 267: ! 268: /* ! 269: * Thread timeout routine, called when timer expires. ! 270: */ ! 271: void ! 272: thread_timer_expire( ! 273: thread_t thread) ! 274: { ! 275: spl_t s; ! 276: ! 277: s = splsched(); ! 278: thread_lock(thread); ! 279: if ( thread->wait_timer_is_set && ! 280: !thread_call_is_delayed(&thread->wait_timer, NULL) ) { ! 281: thread->wait_timer_is_set = FALSE; ! 282: if (thread->active) ! 283: clear_wait_internal(thread, THREAD_TIMED_OUT); ! 284: } ! 285: thread_unlock(thread); ! 286: splx(s); ! 287: ! 288: thread_deallocate(thread); ! 289: } ! 290: ! 291: /* ! 292: * thread_set_timer: ! 293: * ! 294: * Set a timer for the current thread, if the thread ! 295: * is ready to wait. Must be called between assert_wait() ! 296: * and thread_block(). ! 297: */ ! 298: void ! 299: thread_set_timer( ! 300: natural_t interval, ! 301: natural_t scale_factor) ! 302: { ! 303: thread_t thread = current_thread(); ! 304: AbsoluteTime deadline; ! 305: spl_t s; ! 306: ! 307: s = splsched(); ! 308: thread_lock(thread); ! 309: if ((thread->state & TH_WAIT) != 0) { ! 310: clock_interval_to_deadline(interval, scale_factor, &deadline); ! 311: thread_call_enter_delayed(&thread->wait_timer, deadline); ! 312: assert(!thread->wait_timer_is_set); ! 313: thread->ref_count++; ! 314: thread->wait_timer_is_set = TRUE; ! 315: } ! 316: thread_unlock(thread); ! 317: splx(s); ! 318: } ! 319: ! 320: void ! 321: thread_set_timer_deadline( ! 322: AbsoluteTime deadline) ! 323: { ! 324: thread_t thread = current_thread(); ! 325: spl_t s; ! 326: ! 327: s = splsched(); ! 328: thread_lock(thread); ! 329: if ((thread->state & TH_WAIT) != 0) { ! 330: thread_call_enter_delayed(&thread->wait_timer, deadline); ! 331: assert(!thread->wait_timer_is_set); ! 332: thread->ref_count++; ! 333: thread->wait_timer_is_set = TRUE; ! 334: } ! 335: thread_unlock(thread); ! 336: splx(s); ! 337: } ! 338: ! 339: void ! 340: thread_cancel_timer(void) ! 341: { ! 342: thread_t thread = current_thread(); ! 343: boolean_t release = FALSE; ! 344: spl_t s; ! 345: ! 346: s = splsched(); ! 347: thread_lock(thread); ! 348: if (thread->wait_timer_is_set) { ! 349: if (thread_call_cancel(&thread->wait_timer)) ! 350: release = TRUE; ! 351: thread->wait_timer_is_set = FALSE; ! 352: } ! 353: thread_unlock(thread); ! 354: splx(s); ! 355: ! 356: if (release) ! 357: thread_deallocate(thread); ! 358: } ! 359: ! 360: /* ! 361: * thread_depress_timeout: ! 362: * ! 363: * Timeout routine for priority depression. ! 364: */ ! 365: void ! 366: thread_depress_timeout( ! 367: thread_t thread) ! 368: { ! 369: sched_policy_t *policy; ! 370: spl_t s; ! 371: ! 372: s = splsched(); ! 373: thread_lock(thread); ! 374: policy = policy_id_to_sched_policy(thread->policy); ! 375: thread_unlock(thread); ! 376: splx(s); ! 377: ! 378: if (policy != SCHED_POLICY_NULL) ! 379: policy->sp_ops.sp_thread_depress_timeout(policy, thread); ! 380: ! 381: thread_deallocate(thread); ! 382: } ! 383: ! 384: /* ! 385: * Set up thread timeout element when thread is created. ! 386: */ ! 387: void ! 388: thread_timer_setup( ! 389: thread_t thread) ! 390: { ! 391: thread_call_setup(&thread->wait_timer, thread_timer_expire, thread); ! 392: thread->wait_timer_is_set = FALSE; ! 393: thread_call_setup(&thread->depress_timer, thread_depress_timeout, thread); ! 394: } ! 395: ! 396: /* ! 397: * Routine: thread_go_locked ! 398: * Purpose: ! 399: * Start a thread running. ! 400: * Conditions: ! 401: * thread lock held, IPC locks may be held. ! 402: * thread must have been pulled from wait queue under same lock hold. ! 403: */ ! 404: void ! 405: thread_go_locked( ! 406: thread_t thread, ! 407: int result) ! 408: { ! 409: int state; ! 410: sched_policy_t *policy; ! 411: sf_return_t sfr; ! 412: ! 413: assert(thread->at_safe_point == FALSE); ! 414: assert(thread->wait_event == NO_EVENT); ! 415: assert(thread->wait_queue == WAIT_QUEUE_NULL); ! 416: ! 417: if (thread->state & TH_WAIT) { ! 418: ! 419: thread->state &= ~TH_WAIT; ! 420: if (!(thread->state & TH_RUN)) { ! 421: thread->state |= TH_RUN; ! 422: #if THREAD_SWAPPER ! 423: if (thread->state & TH_SWAPPED_OUT) ! 424: thread_swapin(thread->top_act, FALSE); ! 425: else ! 426: #endif /* THREAD_SWAPPER */ ! 427: { ! 428: policy = &sched_policy[thread->policy]; ! 429: sfr = policy->sp_ops.sp_thread_unblock(policy, thread); ! 430: assert(sfr == SF_SUCCESS); ! 431: } ! 432: } ! 433: thread->wait_result = result; ! 434: } ! 435: ! 436: ! 437: /* ! 438: * The next few lines are a major hack. Hopefully this will get us ! 439: * around all of the scheduling framework hooha. We can't call ! 440: * sp_thread_unblock yet because we could still be finishing up the ! 441: * durn two stage block on another processor and thread_setrun ! 442: * could be called by s_t_u and we'll really be messed up then. ! 443: */ ! 444: /* Don't mess with this if we are still swapped out */ ! 445: if (!(thread->state & TH_SWAPPED_OUT)) ! 446: ((mk_sp_info_t)thread->sp_info)->th_state = MK_SP_RUNNABLE; ! 447: ! 448: } ! 449: ! 450: void ! 451: thread_mark_wait_locked( ! 452: thread_t thread, ! 453: int interruptible) ! 454: { ! 455: ! 456: assert(thread == current_thread()); ! 457: ! 458: thread->wait_result = -1; /* JMM - Needed for non-assert kernel */ ! 459: thread->state |= (interruptible) ? TH_WAIT : (TH_WAIT | TH_UNINT); ! 460: thread->at_safe_point = (interruptible == THREAD_ABORTSAFE); ! 461: thread->sleep_stamp = sched_tick; ! 462: } ! 463: ! 464: ! 465: ! 466: /* ! 467: * Routine: assert_wait_timeout ! 468: * Purpose: ! 469: * Assert that the thread intends to block, ! 470: * waiting for a timeout (no user known event). ! 471: */ ! 472: unsigned int assert_wait_timeout_event; ! 473: ! 474: void ! 475: assert_wait_timeout( ! 476: mach_msg_timeout_t msecs, ! 477: int interruptible) ! 478: { ! 479: spl_t s; ! 480: ! 481: assert_wait((event_t)&assert_wait_timeout_event, interruptible); ! 482: thread_set_timer(msecs, 1000*NSEC_PER_USEC); ! 483: } ! 484: ! 485: /* ! 486: * Check to see if an assert wait is possible, without actually doing one. ! 487: * This is used by debug code in locks and elsewhere to verify that it is ! 488: * always OK to block when trying to take a blocking lock (since waiting ! 489: * for the actual assert_wait to catch the case may make it hard to detect ! 490: * this case. ! 491: */ ! 492: boolean_t ! 493: assert_wait_possible(void) ! 494: { ! 495: thread_t thread = current_thread(); ! 496: ! 497: return (thread == NULL || wait_queue_assert_possible(thread)); ! 498: } ! 499: ! 500: /* ! 501: * assert_wait: ! 502: * ! 503: * Assert that the current thread is about to go to ! 504: * sleep until the specified event occurs. ! 505: */ ! 506: void ! 507: assert_wait( ! 508: event_t event, ! 509: int interruptible) ! 510: { ! 511: register wait_queue_t wq; ! 512: register int index; ! 513: ! 514: assert(event != NO_EVENT); ! 515: assert(assert_wait_possible()); ! 516: ! 517: index = wait_hash(event); ! 518: wq = &wait_queues[index]; ! 519: wait_queue_assert_wait(wq, ! 520: event, ! 521: interruptible); ! 522: } ! 523: ! 524: ! 525: /* ! 526: * thread_[un]stop(thread) ! 527: * Once a thread has blocked interruptibly (via assert_wait) prevent ! 528: * it from running until thread_unstop. ! 529: * ! 530: * If someone else has already stopped the thread, wait for the ! 531: * stop to be cleared, and then stop it again. ! 532: * ! 533: * Return FALSE if interrupted. ! 534: * ! 535: * NOTE: thread_hold/thread_suspend should be called on the activation ! 536: * before calling thread_stop. TH_SUSP is only recognized when ! 537: * a thread blocks and only prevents clear_wait/thread_wakeup ! 538: * from restarting an interruptible wait. The wake_active flag is ! 539: * used to indicate that someone is waiting on the thread. ! 540: */ ! 541: boolean_t ! 542: thread_stop( ! 543: thread_t thread) ! 544: { ! 545: spl_t s; ! 546: ! 547: s = splsched(); ! 548: wake_lock(thread); ! 549: ! 550: while (thread->state & TH_SUSP) { ! 551: thread->wake_active = TRUE; ! 552: assert_wait((event_t)&thread->wake_active, THREAD_ABORTSAFE); ! 553: wake_unlock(thread); ! 554: splx(s); ! 555: ! 556: thread_block((void (*)(void)) 0); ! 557: if (current_thread()->wait_result != THREAD_AWAKENED) ! 558: return (FALSE); ! 559: ! 560: s = splsched(); ! 561: wake_lock(thread); ! 562: } ! 563: thread_lock(thread); ! 564: thread->state |= TH_SUSP; ! 565: thread_unlock(thread); ! 566: ! 567: wake_unlock(thread); ! 568: splx(s); ! 569: ! 570: return (TRUE); ! 571: } ! 572: ! 573: /* ! 574: * Clear TH_SUSP and if the thread has been stopped and is now runnable, ! 575: * put it back on the run queue. ! 576: */ ! 577: void ! 578: thread_unstop( ! 579: thread_t thread) ! 580: { ! 581: sched_policy_t *policy; ! 582: sf_return_t sfr; ! 583: spl_t s; ! 584: ! 585: s = splsched(); ! 586: wake_lock(thread); ! 587: thread_lock(thread); ! 588: ! 589: if ((thread->state & (TH_RUN|TH_WAIT|TH_SUSP/*|TH_UNINT*/)) == TH_SUSP) { ! 590: thread->state = (thread->state & ~TH_SUSP) | TH_RUN; ! 591: #if THREAD_SWAPPER ! 592: if (thread->state & TH_SWAPPED_OUT) ! 593: thread_swapin(thread->top_act, FALSE); ! 594: else ! 595: #endif /* THREAD_SWAPPER */ ! 596: { ! 597: policy = &sched_policy[thread->policy]; ! 598: sfr = policy->sp_ops.sp_thread_unblock(policy, thread); ! 599: assert(sfr == SF_SUCCESS); ! 600: } ! 601: } ! 602: else ! 603: if (thread->state & TH_SUSP) { ! 604: thread->state &= ~TH_SUSP; ! 605: ! 606: if (thread->wake_active) { ! 607: thread->wake_active = FALSE; ! 608: thread_unlock(thread); ! 609: wake_unlock(thread); ! 610: splx(s); ! 611: thread_wakeup((event_t)&thread->wake_active); ! 612: ! 613: return; ! 614: } ! 615: } ! 616: ! 617: thread_unlock(thread); ! 618: wake_unlock(thread); ! 619: splx(s); ! 620: } ! 621: ! 622: /* ! 623: * Wait for the thread's RUN bit to clear ! 624: */ ! 625: boolean_t ! 626: thread_wait( ! 627: thread_t thread) ! 628: { ! 629: spl_t s; ! 630: ! 631: s = splsched(); ! 632: wake_lock(thread); ! 633: ! 634: while (thread->state & (TH_RUN/*|TH_UNINT*/)) { ! 635: if (thread->last_processor != PROCESSOR_NULL) ! 636: cause_ast_check(thread->last_processor); ! 637: ! 638: thread->wake_active = TRUE; ! 639: assert_wait((event_t)&thread->wake_active, THREAD_ABORTSAFE); ! 640: wake_unlock(thread); ! 641: splx(s); ! 642: ! 643: thread_block((void (*)(void))0); ! 644: if (current_thread()->wait_result != THREAD_AWAKENED) ! 645: return (FALSE); ! 646: ! 647: s = splsched(); ! 648: wake_lock(thread); ! 649: } ! 650: ! 651: wake_unlock(thread); ! 652: splx(s); ! 653: ! 654: return (TRUE); ! 655: } ! 656: ! 657: ! 658: /* ! 659: * thread_stop_wait(thread) ! 660: * Stop the thread then wait for it to block interruptibly ! 661: */ ! 662: boolean_t ! 663: thread_stop_wait( ! 664: thread_t thread) ! 665: { ! 666: if (thread_stop(thread)) { ! 667: if (thread_wait(thread)) ! 668: return (TRUE); ! 669: ! 670: thread_unstop(thread); ! 671: } ! 672: ! 673: return (FALSE); ! 674: } ! 675: ! 676: ! 677: static ! 678: void ! 679: clear_wait_internal( ! 680: thread_t thread, ! 681: int result) ! 682: { ! 683: register int index; ! 684: register queue_t q; ! 685: register event_t event; ! 686: register simple_lock_t lock; ! 687: sched_policy_t *policy; ! 688: sf_return_t sfr; ! 689: ! 690: /* ! 691: * If the thread isn't in a wait queue, just set it running. Otherwise, ! 692: * try to remove it from the queue and, if successful, then set it ! 693: * running. ! 694: */ ! 695: if (wait_queue_assert_possible(thread) || ! 696: (wait_queue_remove(thread) == KERN_SUCCESS)) { ! 697: thread_go_locked(thread, result); ! 698: } ! 699: } ! 700: ! 701: /* ! 702: * clear_wait: ! 703: * ! 704: * Clear the wait condition for the specified thread. Start the thread ! 705: * executing if that is appropriate. ! 706: * ! 707: * parameters: ! 708: * thread thread to awaken ! 709: * result Wakeup result the thread should see ! 710: * interruptible Don't wake up the thread if it isn't interruptible. ! 711: */ ! 712: void ! 713: clear_wait( ! 714: thread_t thread, ! 715: int result, ! 716: boolean_t interruptible) ! 717: { ! 718: spl_t s; ! 719: ! 720: s = splsched(); ! 721: thread_lock(thread); ! 722: if (!interruptible || !(thread->state & TH_UNINT)) ! 723: clear_wait_internal(thread, result); ! 724: thread_unlock(thread); ! 725: splx(s); ! 726: } ! 727: ! 728: ! 729: /* ! 730: * thread_wakeup_prim: ! 731: * ! 732: * Common routine for thread_wakeup, thread_wakeup_with_result, ! 733: * and thread_wakeup_one. ! 734: * ! 735: */ ! 736: void ! 737: thread_wakeup_prim( ! 738: event_t event, ! 739: boolean_t one_thread, ! 740: int result) ! 741: { ! 742: register wait_queue_t wq; ! 743: register int index; ! 744: ! 745: index = wait_hash(event); ! 746: wq = &wait_queues[index]; ! 747: if (one_thread) ! 748: wait_queue_wakeup_one(wq, event, result); ! 749: else ! 750: wait_queue_wakeup_all(wq, event, result); ! 751: } ! 752: ! 753: /* ! 754: * thread_bind: ! 755: * ! 756: * Force a thread to execute on the specified processor. ! 757: * If the thread is currently executing, it may wait until its ! 758: * time slice is up before switching onto the specified processor. ! 759: * ! 760: * A processor of PROCESSOR_NULL causes the thread to be unbound. ! 761: * xxx - DO NOT export this to users. ! 762: */ ! 763: void ! 764: thread_bind( ! 765: register thread_t thread, ! 766: processor_t processor) ! 767: { ! 768: spl_t s; ! 769: ! 770: s = splsched(); ! 771: thread_lock(thread); ! 772: thread_bind_locked(thread, processor); ! 773: thread_unlock(thread); ! 774: splx(s); ! 775: } ! 776: ! 777: /* ! 778: * Select a thread for this processor (the current processor) to run. ! 779: * May select the current thread. ! 780: * Assumes splsched. ! 781: */ ! 782: thread_t ! 783: thread_select( ! 784: register processor_t myprocessor) ! 785: { ! 786: register thread_t thread; ! 787: processor_set_t pset; ! 788: register run_queue_t runq = &myprocessor->runq; ! 789: boolean_t other_runnable; ! 790: sched_policy_t *policy; ! 791: sf_return_t sfr; ! 792: ! 793: /* ! 794: * Check for other non-idle runnable threads. ! 795: */ ! 796: myprocessor->first_quantum = TRUE; ! 797: pset = myprocessor->processor_set; ! 798: thread = current_thread(); ! 799: ! 800: #if 0 /* CHECKME! */ ! 801: thread->unconsumed_quantum = myprocessor->quantum; ! 802: #endif ! 803: ! 804: simple_lock(&runq->lock); ! 805: simple_lock(&pset->runq.lock); ! 806: ! 807: other_runnable = runq->count > 0 || pset->runq.count > 0; ! 808: ! 809: if ( (!other_runnable || ! 810: (runq->highq < thread->sched_pri && ! 811: pset->runq.highq < thread->sched_pri)) && ! 812: #if MACH_HOST ! 813: thread->processor_set == pset && ! 814: #endif /* MACH_HOST */ ! 815: (thread->bound_processor == PROCESSOR_NULL || ! 816: thread->bound_processor == myprocessor) && ! 817: thread->state == TH_RUN && ! 818: thread->pending_policy == POLICY_NULL ) { ! 819: ! 820: /* I am the highest priority runnable thread: */ ! 821: simple_unlock(&pset->runq.lock); ! 822: simple_unlock(&runq->lock); ! 823: ! 824: /* Update the thread's meta-priority */ ! 825: policy = &sched_policy[thread->policy]; ! 826: /*** ??? maybe use a macro ***/ ! 827: sfr = policy->sp_ops.sp_thread_update_mpri(policy, thread); ! 828: assert(sfr == SF_SUCCESS); ! 829: } ! 830: else if (other_runnable) { ! 831: simple_unlock(&pset->runq.lock); ! 832: simple_unlock(&runq->lock); ! 833: thread = choose_thread(myprocessor); ! 834: } ! 835: else { ! 836: simple_unlock(&runq->lock); ! 837: ! 838: /* ! 839: * Nothing non-idle runnable, including myself. ! 840: * Return if this ! 841: * thread is still runnable on this processor. ! 842: * Check for priority update if required. ! 843: */ ! 844: /* get an idle thread to run */ ! 845: thread = choose_pset_thread(myprocessor, pset); ! 846: } ! 847: ! 848: if (thread->policy & (POLICY_RR|POLICY_FIFO)) ! 849: #if 1 /* CHECKME! */ ! 850: myprocessor->quantum = pset->set_quantum; ! 851: #else ! 852: myprocessor->quantum = thread->unconsumed_quantum; ! 853: #endif ! 854: else ! 855: myprocessor->quantum = thread->bound_processor? ! 856: min_quantum : pset->set_quantum; ! 857: ! 858: return (thread); ! 859: } ! 860: ! 861: ! 862: /* ! 863: * Stop running the current thread and start running the new thread. ! 864: * If continuation is non-zero, and the current thread is blocked, ! 865: * then it will resume by executing continuation on a new stack. ! 866: * Returns TRUE if the hand-off succeeds. ! 867: * The reason parameter == AST_QUANTUM if the thread blocked ! 868: * because its quantum expired. ! 869: * Assumes splsched. ! 870: */ ! 871: ! 872: ! 873: static thread_t ! 874: __current_thread(void) ! 875: { ! 876: return (current_thread()); ! 877: } ! 878: ! 879: ! 880: boolean_t ! 881: thread_invoke( ! 882: register thread_t old_thread, ! 883: register thread_t new_thread, ! 884: int reason, ! 885: void (*continuation)(void)) ! 886: { ! 887: sched_policy_t *policy; ! 888: sf_return_t sfr; ! 889: thread_t old_thread_hold; ! 890: void (*lcont)(void); ! 891: ! 892: /* ! 893: * Mark thread interruptible. ! 894: */ ! 895: thread_lock(new_thread); ! 896: new_thread->state &= ~TH_UNINT; ! 897: ! 898: assert(thread_runnable(new_thread)); ! 899: ! 900: /* ! 901: * Check for invoking the same thread. ! 902: */ ! 903: if (old_thread == new_thread) { ! 904: counter(++c_thread_invoke_same); ! 905: thread_unlock(new_thread); ! 906: if (continuation != (void (*)()) 0) { ! 907: if (old_thread->funnel_state & TH_FN_REFUNNEL) { ! 908: kern_return_t save_wait_result; ! 909: old_thread->funnel_state = 0; ! 910: save_wait_result = old_thread->wait_result; ! 911: mutex_lock(&funnel_lock); ! 912: old_thread->funnel_state = TH_FN_OWNED; ! 913: old_thread->wait_result = save_wait_result; ! 914: } ! 915: (void) spllo(); ! 916: call_continuation(continuation); ! 917: /*NOTREACHED*/ ! 918: } ! 919: return TRUE; ! 920: } ! 921: ! 922: if ((old_thread->stack_privilege != current_stack()) && ! 923: (continuation != (void (*)()) 0)) ! 924: { ! 925: switch (new_thread->state & TH_STACK_STATE) { ! 926: case TH_STACK_HANDOFF: ! 927: new_thread->state &= ~(TH_STACK_HANDOFF|TH_UNINT); ! 928: thread_unlock(new_thread); ! 929: ! 930: mp_disable_preemption(); ! 931: new_thread->last_processor = current_processor(); ! 932: mp_enable_preemption(); ! 933: ! 934: /* ! 935: * Set up ast context of new thread and switch to its timer. ! 936: */ ! 937: mp_disable_preemption(); ! 938: ast_context(new_thread->top_act, cpu_number()); ! 939: mp_enable_preemption(); ! 940: timer_switch(&new_thread->system_timer); ! 941: ! 942: old_thread->continuation = continuation; ! 943: stack_handoff(old_thread, new_thread); ! 944: act_machine_sv_free(old_thread->top_act); ! 945: ! 946: thread_lock(old_thread); ! 947: ! 948: /* ! 949: * inline thread_dispatch but don't free stack ! 950: */ ! 951: ! 952: switch (old_thread->state & (TH_RUN|TH_WAIT|TH_UNINT|TH_IDLE)) { ! 953: sched_policy_t *policy; ! 954: sf_return_t sfr; ! 955: ! 956: case TH_RUN | TH_UNINT: ! 957: case TH_RUN: ! 958: /* ! 959: * No reason to stop. Put back on a run queue. ! 960: */ ! 961: old_thread->state |= TH_STACK_HANDOFF; ! 962: ! 963: /* Get pointer to scheduling policy "object" */ ! 964: policy = &sched_policy[old_thread->policy]; ! 965: ! 966: /* Leave enqueueing thread up to scheduling policy */ ! 967: sfr = policy->sp_ops.sp_thread_dispatch(policy, ! 968: old_thread); ! 969: assert(sfr == SF_SUCCESS); ! 970: ! 971: break; ! 972: ! 973: case TH_RUN | TH_WAIT | TH_UNINT: ! 974: case TH_RUN | TH_WAIT: ! 975: old_thread->sleep_stamp = sched_tick; ! 976: ! 977: /* fallthrough */ ! 978: case TH_WAIT: /* this happens! */ ! 979: ! 980: /* ! 981: * Waiting ! 982: */ ! 983: old_thread->state |= TH_STACK_HANDOFF; ! 984: old_thread->state &= ~TH_RUN; ! 985: if (old_thread->state & TH_TERMINATE) ! 986: thread_reaper_enqueue(old_thread); ! 987: ! 988: if (old_thread->wake_active) { ! 989: old_thread->wake_active = FALSE; ! 990: thread_unlock(old_thread); ! 991: thread_wakeup((event_t)&old_thread->wake_active); ! 992: goto after_old_thread; ! 993: } ! 994: break; ! 995: ! 996: case TH_RUN | TH_IDLE: ! 997: /* ! 998: * Drop idle thread -- it is already in ! 999: * idle_thread_array. ! 1000: */ ! 1001: old_thread->state |= TH_STACK_HANDOFF; ! 1002: ! 1003: break; ! 1004: ! 1005: default: ! 1006: panic("State 0x%x \n",old_thread->state); ! 1007: } ! 1008: ! 1009: thread_unlock(old_thread); ! 1010: after_old_thread: ! 1011: /* ! 1012: * call_continuation calls the continuation after ! 1013: resetting the current stack pointer to recover ! 1014: stack space. without this we could stack overflow ! 1015: */ ! 1016: disable_preemption(); ! 1017: ! 1018: thread_lock(old_thread); ! 1019: ! 1020: /* Get pointer to scheduling policy "object" */ ! 1021: policy = &sched_policy[old_thread->policy]; ! 1022: ! 1023: /* Indicate to sched policy that old thread has stopped execution */ ! 1024: /*** ??? maybe use a macro -- rkc, 1/4/96 ***/ ! 1025: sfr = policy->sp_ops.sp_thread_done(policy, ! 1026: old_thread); ! 1027: assert(sfr == SF_SUCCESS); ! 1028: ! 1029: /* Process any pending scheduling policy change */ ! 1030: if (old_thread->pending_policy != POLICY_NULL) { ! 1031: sched_policy_t *policy; ! 1032: sf_return_t sfr; ! 1033: if (old_thread->policy != old_thread->pending_policy) { ! 1034: /* Detach thread from current scheduling policy */ ! 1035: sfr = policy->sp_ops.sp_thread_detach( ! 1036: policy, ! 1037: old_thread); ! 1038: assert(sfr == SF_SUCCESS); ! 1039: ! 1040: /* Attach to the pending policy */ ! 1041: policy = &sched_policy[old_thread->pending_policy]; ! 1042: sfr = policy->sp_ops.sp_thread_attach( ! 1043: policy, ! 1044: old_thread); ! 1045: ! 1046: /* Save result for issuer of policy change */ ! 1047: old_thread->change_sfr = (kern_return_t)sfr; ! 1048: ! 1049: /* If successful so far, set up sched attributes */ ! 1050: if (sfr == SF_SUCCESS) { ! 1051: sfr = policy->sp_ops.sp_thread_set( ! 1052: policy, ! 1053: old_thread, ! 1054: old_thread->pending_sched_attr); ! 1055: ! 1056: /* Save result for issuer of policy change */ ! 1057: old_thread->change_sfr = (kern_return_t)sfr; ! 1058: } ! 1059: } ! 1060: ! 1061: /* Indicate change has been done */ ! 1062: old_thread->pending_policy = POLICY_NULL; ! 1063: } ! 1064: thread_unlock(old_thread); ! 1065: thread_lock(new_thread); ! 1066: ! 1067: assert(thread_runnable(new_thread)); ! 1068: ! 1069: /* Get pointer to scheduling policy "object" */ ! 1070: policy = &sched_policy[new_thread->policy]; ! 1071: ! 1072: /* Indicate to sched policy that new thread has started execution */ ! 1073: /*** ??? maybe use a macro ***/ ! 1074: sfr = policy->sp_ops.sp_thread_begin(policy, new_thread); ! 1075: assert(sfr == SF_SUCCESS); ! 1076: thread_unlock(new_thread); ! 1077: enable_preemption(); ! 1078: ! 1079: counter_always(c_thread_invoke_hits++); ! 1080: (void) spllo(); ! 1081: lcont = new_thread->continuation; ! 1082: assert(lcont); ! 1083: if (new_thread->funnel_state & TH_FN_REFUNNEL) { ! 1084: kern_return_t save_wait_result; ! 1085: new_thread->funnel_state = 0; ! 1086: save_wait_result = new_thread->wait_result; ! 1087: mutex_lock(&funnel_lock); ! 1088: new_thread->funnel_state = TH_FN_OWNED; ! 1089: new_thread->wait_result = save_wait_result; ! 1090: } ! 1091: assert(lcont); ! 1092: call_continuation(lcont); ! 1093: /*NOTREACHED*/ ! 1094: return TRUE; ! 1095: ! 1096: case TH_STACK_COMING_IN: ! 1097: /* ! 1098: * waiting for a stack ! 1099: */ ! 1100: thread_swapin(new_thread); ! 1101: thread_unlock(new_thread); ! 1102: counter_always(c_thread_invoke_misses++); ! 1103: return FALSE; ! 1104: ! 1105: case 0: ! 1106: /* ! 1107: * already has a stack - can't handoff ! 1108: */ ! 1109: ! 1110: break; ! 1111: } ! 1112: } ! 1113: else ! 1114: { ! 1115: /* ! 1116: * check that the new thread has a stack ! 1117: */ ! 1118: if (new_thread->state & TH_STACK_HANDOFF) { ! 1119: /* has no stack. if not already waiting for one try to get one */ ! 1120: if ((new_thread->state & TH_STACK_COMING_IN) || ! 1121: /* not already waiting. nonblocking try to get one */ ! 1122: !stack_alloc_try(new_thread, thread_continue)) ! 1123: { ! 1124: /* couldn't get one. schedule new thread to get a stack and ! 1125: return failure so we can try another thread. */ ! 1126: thread_swapin(new_thread); ! 1127: thread_unlock(new_thread); ! 1128: counter_always(c_thread_invoke_misses++); ! 1129: return FALSE; ! 1130: } ! 1131: } ! 1132: /* new thread now has a stack. it has been setup to resume in ! 1133: thread_continue so it can dispatch the old thread, deal with ! 1134: funnelling and then go to it's true continuation point */ ! 1135: } ! 1136: ! 1137: new_thread->state &= ~(TH_STACK_HANDOFF | TH_UNINT); ! 1138: ! 1139: /* ! 1140: * Thread is now interruptible. ! 1141: */ ! 1142: mp_disable_preemption(); ! 1143: new_thread->last_processor = current_processor(); ! 1144: mp_enable_preemption(); ! 1145: ! 1146: thread_unlock(new_thread); ! 1147: ! 1148: /* ! 1149: * Set up ast context of new thread and switch to its timer. ! 1150: */ ! 1151: mp_disable_preemption(); ! 1152: ast_context(new_thread->top_act, cpu_number()); ! 1153: mp_enable_preemption(); ! 1154: timer_switch(&new_thread->system_timer); ! 1155: ! 1156: /* ! 1157: * switch_context is machine-dependent. It does the ! 1158: * machine-dependent components of a context-switch, like ! 1159: * changing address spaces. It updates active_threads. ! 1160: */ ! 1161: old_thread->reason = reason; ! 1162: counter_always(c_thread_invoke_csw++); ! 1163: current_task()->csw++; ! 1164: ! 1165: /* ! 1166: * N.B. On return from the call to switch_context, 'old_thread' ! 1167: * points at the thread that yielded to us. Unfortunately, at ! 1168: * this point, there are no simple_locks held, so if we are preempted ! 1169: * before the call to thread_dispatch blocks preemption, it is ! 1170: * possible for 'old_thread' to terminate, leaving us with a ! 1171: * stale thread pointer. ! 1172: */ ! 1173: assert(thread_runnable(new_thread)); ! 1174: assert(old_thread->runq == RUN_QUEUE_NULL); ! 1175: ! 1176: disable_preemption(); ! 1177: ! 1178: thread_lock(old_thread); ! 1179: ! 1180: /* Indicate to sched policy that old thread has stopped execution */ ! 1181: policy = &sched_policy[old_thread->policy]; ! 1182: /*** ??? maybe use a macro -- ***/ ! 1183: sfr = policy->sp_ops.sp_thread_done(policy, old_thread); ! 1184: assert(sfr == SF_SUCCESS); ! 1185: ! 1186: /* Process any pending scheduling policy change */ ! 1187: if (old_thread->pending_policy != POLICY_NULL) { ! 1188: if (old_thread->policy != old_thread->pending_policy) { ! 1189: /* Detach thread from current scheduling policy */ ! 1190: sfr = policy->sp_ops.sp_thread_detach(policy, old_thread); ! 1191: assert(sfr == SF_SUCCESS); ! 1192: ! 1193: /* Attach to the pending policy */ ! 1194: policy = &sched_policy[old_thread->pending_policy]; ! 1195: sfr = policy->sp_ops.sp_thread_attach(policy, old_thread); ! 1196: ! 1197: /* Save result for issuer of policy change */ ! 1198: old_thread->change_sfr = (kern_return_t)sfr; ! 1199: ! 1200: /* If successful so far, set up sched attributes */ ! 1201: if (sfr == SF_SUCCESS) { ! 1202: sfr = policy->sp_ops.sp_thread_set(policy, old_thread, ! 1203: old_thread->pending_sched_attr); ! 1204: ! 1205: /* Save result for issuer of policy change */ ! 1206: old_thread->change_sfr = (kern_return_t)sfr; ! 1207: } ! 1208: } ! 1209: ! 1210: /* Indicate change has been done */ ! 1211: old_thread->pending_policy = POLICY_NULL; ! 1212: } ! 1213: ! 1214: thread_unlock(old_thread); ! 1215: old_thread_hold = old_thread; ! 1216: ! 1217: /* SWITCH CONTEXT HERE */ ! 1218: ! 1219: old_thread = switch_context(old_thread, continuation, new_thread); ! 1220: ! 1221: /* Now on new thread's stack. Set a local variable to refer to it. */ ! 1222: new_thread = __current_thread(); ! 1223: assert(old_thread != new_thread); ! 1224: ! 1225: assert(thread_runnable(new_thread)); ! 1226: ! 1227: thread_lock(new_thread); ! 1228: assert(thread_runnable(new_thread)); ! 1229: /* Indicate to sched policy that new thread has started execution */ ! 1230: policy = &sched_policy[new_thread->policy]; ! 1231: /*** ??? maybe use a macro -- rkc, 1/4/96 ***/ ! 1232: sfr = policy->sp_ops.sp_thread_begin(policy, new_thread); ! 1233: assert(sfr == SF_SUCCESS); ! 1234: thread_unlock(new_thread); ! 1235: ! 1236: /* ! 1237: * We're back. Now old_thread is the thread that resumed ! 1238: * us, and we have to dispatch it. ! 1239: */ ! 1240: /* CHECKME! */ ! 1241: // Code from OSF in Grenoble deleted the following fields. They were ! 1242: // used in HPPA and 386 code, but not in the PPC for other than ! 1243: // just setting and resetting. They didn't delete these lines from ! 1244: // the MACH_RT builds, though, causing compile errors. I'm going ! 1245: // to make a wild guess and assume we can just delete these. ! 1246: #if 0 ! 1247: if (old_thread->preempt == TH_NOT_PREEMPTABLE) { ! 1248: /* ! 1249: * Mark that we have been really preempted ! 1250: */ ! 1251: old_thread->preempt = TH_PREEMPTED; ! 1252: } ! 1253: #endif ! 1254: thread_dispatch(old_thread); ! 1255: enable_preemption(); ! 1256: return TRUE; ! 1257: } ! 1258: ! 1259: /* ! 1260: * thread_continue: ! 1261: * ! 1262: * Called when the launching a new thread, at splsched(); ! 1263: */ ! 1264: void ! 1265: thread_continue( ! 1266: register thread_t old_thread) ! 1267: { ! 1268: register thread_t self; ! 1269: register void (*continuation)(); ! 1270: sched_policy_t *policy; ! 1271: sf_return_t sfr; ! 1272: ! 1273: self = current_thread(); ! 1274: continuation = self->continuation; ! 1275: ! 1276: /* ! 1277: * We must dispatch the old thread and then ! 1278: * call the current thread's continuation. ! 1279: * There might not be an old thread, if we are ! 1280: * the first thread to run on this processor. ! 1281: */ ! 1282: if (old_thread != THREAD_NULL) { ! 1283: thread_dispatch(old_thread); ! 1284: thread_lock(self); ! 1285: ! 1286: /* Get pointer to scheduling policy "object" */ ! 1287: policy = &sched_policy[self->policy]; ! 1288: ! 1289: /* Indicate to sched policy that new thread has started execution */ ! 1290: /*** ??? maybe use a macro -- rkc, 1/4/96 ***/ ! 1291: sfr = policy->sp_ops.sp_thread_begin(policy,self); ! 1292: assert(sfr == SF_SUCCESS); ! 1293: thread_unlock(self); ! 1294: } ! 1295: ! 1296: /* ! 1297: * N.B. - the following is necessary, since thread_invoke() ! 1298: * inhibits preemption on entry and reenables before it ! 1299: * returns. Unfortunately, the first time a newly-created ! 1300: * thread executes, it magically appears here, and never ! 1301: * executes the enable_preemption() call in thread_invoke(). ! 1302: */ ! 1303: enable_preemption(); ! 1304: if (self->funnel_state & TH_FN_REFUNNEL) { ! 1305: kern_return_t save_wait_result; ! 1306: self->funnel_state = 0; ! 1307: save_wait_result = self->wait_result; ! 1308: mutex_lock(&funnel_lock); ! 1309: self->wait_result = save_wait_result; ! 1310: self->funnel_state = TH_FN_OWNED; ! 1311: } ! 1312: spllo(); ! 1313: ! 1314: assert(continuation); ! 1315: (*continuation)(); ! 1316: /*NOTREACHED*/ ! 1317: } ! 1318: ! 1319: #if MACH_LDEBUG || MACH_KDB ! 1320: ! 1321: #define THREAD_LOG_SIZE 300 ! 1322: ! 1323: struct t64 { ! 1324: unsigned long h; ! 1325: unsigned long l; ! 1326: }; ! 1327: ! 1328: struct { ! 1329: struct t64 stamp; ! 1330: thread_t thread; ! 1331: long info1; ! 1332: long info2; ! 1333: long info3; ! 1334: char * action; ! 1335: } thread_log[THREAD_LOG_SIZE]; ! 1336: ! 1337: int thread_log_index; ! 1338: ! 1339: void check_thread_time(long n); ! 1340: ! 1341: ! 1342: int check_thread_time_crash; ! 1343: ! 1344: #if 0 ! 1345: void ! 1346: check_thread_time(long us) ! 1347: { ! 1348: struct t64 temp; ! 1349: ! 1350: if (!check_thread_time_crash) ! 1351: return; ! 1352: ! 1353: temp = thread_log[0].stamp; ! 1354: cyctm05_diff (&thread_log[1].stamp, &thread_log[0].stamp, &temp); ! 1355: ! 1356: if (temp.l >= us && thread_log[1].info != 0x49) /* HACK!!! */ ! 1357: panic ("check_thread_time"); ! 1358: } ! 1359: #endif ! 1360: ! 1361: void ! 1362: log_thread_action(char * action, long info1, long info2, long info3) ! 1363: { ! 1364: int i; ! 1365: spl_t x; ! 1366: static unsigned int tstamp; ! 1367: ! 1368: x = splhigh(); ! 1369: ! 1370: for (i = THREAD_LOG_SIZE-1; i > 0; i--) { ! 1371: thread_log[i] = thread_log[i-1]; ! 1372: } ! 1373: ! 1374: thread_log[0].stamp.h = 0; ! 1375: thread_log[0].stamp.l = tstamp++; ! 1376: thread_log[0].thread = current_thread(); ! 1377: thread_log[0].info1 = info1; ! 1378: thread_log[0].info2 = info2; ! 1379: thread_log[0].info3 = info3; ! 1380: thread_log[0].action = action; ! 1381: /* strcpy (&thread_log[0].action[0], action);*/ ! 1382: ! 1383: splx(x); ! 1384: } ! 1385: #endif /* MACH_LDEBUG || MACH_KDB */ ! 1386: ! 1387: #if MACH_KDB ! 1388: #include <ddb/db_output.h> ! 1389: void db_show_thread_log(void); ! 1390: ! 1391: void ! 1392: db_show_thread_log(void) ! 1393: { ! 1394: int i; ! 1395: ! 1396: db_printf ("%s %s %s %s %s %s\n", " Thread ", " Info1 ", " Info2 ", ! 1397: " Info3 ", " Timestamp ", "Action"); ! 1398: ! 1399: for (i = 0; i < THREAD_LOG_SIZE; i++) { ! 1400: db_printf ("%08x %08x %08x %08x %08x/%08x %s\n", ! 1401: thread_log[i].thread, ! 1402: thread_log[i].info1, ! 1403: thread_log[i].info2, ! 1404: thread_log[i].info3, ! 1405: thread_log[i].stamp.h, ! 1406: thread_log[i].stamp.l, ! 1407: thread_log[i].action); ! 1408: } ! 1409: } ! 1410: #endif /* MACH_KDB */ ! 1411: ! 1412: /* ! 1413: * thread_block_reason: ! 1414: * ! 1415: * Block the current thread. If the thread is runnable ! 1416: * then someone must have woken it up between its request ! 1417: * to sleep and now. In this case, it goes back on a ! 1418: * run queue. ! 1419: * ! 1420: * If a continuation is specified, then thread_block will ! 1421: * attempt to discard the thread's kernel stack. When the ! 1422: * thread resumes, it will execute the continuation function ! 1423: * on a new kernel stack. ! 1424: */ ! 1425: counter(mach_counter_t c_thread_block_calls = 0;) ! 1426: ! 1427: int ! 1428: thread_block_reason( ! 1429: void (*continuation)(void), ! 1430: int reason) ! 1431: { ! 1432: register thread_t thread = current_thread(); ! 1433: register processor_t myprocessor; ! 1434: register thread_t new_thread; ! 1435: register int aborted; ! 1436: spl_t s; ! 1437: ! 1438: counter(++c_thread_block_calls); ! 1439: ! 1440: check_simple_locks(); ! 1441: ! 1442: if (thread->funnel_state & TH_FN_OWNED) { ! 1443: thread->funnel_state = TH_FN_REFUNNEL; ! 1444: mutex_unlock(&funnel_lock); ! 1445: } ! 1446: ! 1447: machine_clock_assist(); ! 1448: ! 1449: s = splsched(); ! 1450: mp_disable_preemption(); ! 1451: myprocessor = current_processor(); ! 1452: ! 1453: thread_lock(thread); ! 1454: aborted = (thread->state & TH_ABORT); ! 1455: if (aborted) ! 1456: clear_wait_internal(thread, THREAD_INTERRUPTED); ! 1457: ! 1458: /* Unconditionally remove either | both */ ! 1459: ast_off(AST_QUANTUM|AST_BLOCK|AST_URGENT); ! 1460: ! 1461: mp_enable_preemption(); ! 1462: ! 1463: new_thread = thread_select(myprocessor); ! 1464: assert(new_thread); ! 1465: assert(thread_runnable(new_thread)); ! 1466: thread_unlock(thread); ! 1467: while (!thread_invoke(thread, new_thread, reason, continuation)) { ! 1468: thread_lock(thread); ! 1469: new_thread = thread_select(myprocessor); ! 1470: assert(new_thread); ! 1471: assert(thread_runnable(new_thread)); ! 1472: thread_unlock(thread); ! 1473: } ! 1474: ! 1475: splx(s); ! 1476: ! 1477: if (thread->funnel_state & TH_FN_REFUNNEL) { ! 1478: kern_return_t save_wait_result; ! 1479: ! 1480: save_wait_result = thread->wait_result; ! 1481: thread->funnel_state = 0; ! 1482: mutex_lock(&funnel_lock); ! 1483: thread->funnel_state = TH_FN_OWNED; ! 1484: thread->wait_result = save_wait_result; ! 1485: } ! 1486: ! 1487: return thread->wait_result; ! 1488: } ! 1489: ! 1490: /* ! 1491: * thread_block: ! 1492: * ! 1493: * Now calls thread_block_reason() which forwards the ! 1494: * the reason parameter to thread_invoke() so it can ! 1495: * do the right thing if the thread's quantum expired. ! 1496: */ ! 1497: int ! 1498: thread_block( ! 1499: void (*continuation)(void)) ! 1500: { ! 1501: return thread_block_reason(continuation, 0); ! 1502: } ! 1503: ! 1504: /* ! 1505: * thread_run: ! 1506: * ! 1507: * Switch directly from the current thread to a specified ! 1508: * thread. Both the current and new threads must be ! 1509: * runnable. ! 1510: */ ! 1511: void ! 1512: thread_run( ! 1513: void (*continuation)(void), ! 1514: register thread_t new_thread) ! 1515: { ! 1516: register thread_t thread = current_thread(); ! 1517: spl_t s; ! 1518: ! 1519: s = splsched(); ! 1520: while (!thread_invoke(thread, new_thread, 0, continuation)) { ! 1521: register processor_t myprocessor = current_processor(); ! 1522: thread_lock(thread); ! 1523: new_thread = thread_select(myprocessor); ! 1524: thread_unlock(thread); ! 1525: } ! 1526: splx(s); ! 1527: } ! 1528: ! 1529: /* ! 1530: * Dispatches a running thread that is not on a runq. ! 1531: * Called at splsched. ! 1532: */ ! 1533: void ! 1534: thread_dispatch( ! 1535: register thread_t thread) ! 1536: { ! 1537: sched_policy_t *policy; ! 1538: sf_return_t sfr; ! 1539: ! 1540: /* ! 1541: * If we are discarding the thread's stack, we must do it ! 1542: * before the thread has a chance to run. ! 1543: */ ! 1544: wake_lock(thread); ! 1545: thread_lock(thread); ! 1546: ! 1547: if (thread->continuation != (void (*)())0) { ! 1548: assert((thread->state & TH_STACK_STATE) == 0); ! 1549: thread->state |= TH_STACK_HANDOFF; ! 1550: ! 1551: stack_free(thread); ! 1552: if (thread->top_act) { ! 1553: act_machine_sv_free(thread->top_act); ! 1554: } ! 1555: } ! 1556: ! 1557: switch (thread->state & (TH_RUN|TH_WAIT|TH_UNINT|TH_IDLE)) { ! 1558: ! 1559: case TH_RUN | TH_UNINT: ! 1560: case TH_RUN: ! 1561: /* ! 1562: * No reason to stop. Put back on a run queue. ! 1563: */ ! 1564: /* Leave enqueueing thread up to scheduling policy */ ! 1565: policy = &sched_policy[thread->policy]; ! 1566: /*** ??? maybe use a macro ***/ ! 1567: sfr = policy->sp_ops.sp_thread_dispatch(policy, thread); ! 1568: assert(sfr == SF_SUCCESS); ! 1569: break; ! 1570: ! 1571: case TH_RUN | TH_WAIT | TH_UNINT: ! 1572: case TH_RUN | TH_WAIT: ! 1573: thread->sleep_stamp = sched_tick; ! 1574: /* fallthrough */ ! 1575: case TH_WAIT: /* this happens! */ ! 1576: ! 1577: /* ! 1578: * Waiting ! 1579: */ ! 1580: thread->state &= ~TH_RUN; ! 1581: if (thread->state & TH_TERMINATE) ! 1582: thread_reaper_enqueue(thread); ! 1583: ! 1584: if (thread->wake_active) { ! 1585: thread->wake_active = FALSE; ! 1586: thread_unlock(thread); ! 1587: wake_unlock(thread); ! 1588: thread_wakeup((event_t)&thread->wake_active); ! 1589: return; ! 1590: } ! 1591: break; ! 1592: ! 1593: case TH_RUN | TH_IDLE: ! 1594: /* ! 1595: * Drop idle thread -- it is already in ! 1596: * idle_thread_array. ! 1597: */ ! 1598: break; ! 1599: ! 1600: default: ! 1601: panic("State 0x%x \n",thread->state); ! 1602: } ! 1603: thread_unlock(thread); ! 1604: wake_unlock(thread); ! 1605: } ! 1606: ! 1607: /* ! 1608: * Enqueue thread on run_queue. ! 1609: */ ! 1610: int ! 1611: run_queue_enqueue( ! 1612: register run_queue_t rq, ! 1613: register thread_t thread, ! 1614: boolean_t tail) ! 1615: { ! 1616: register int whichq; ! 1617: int oldrqcount; ! 1618: ! 1619: whichq = thread->sched_pri; ! 1620: if (whichq > MAXPRI || whichq < MINPRI) { ! 1621: panic("run_queue_enqueue: bad pri (%d)\n", whichq); ! 1622: } ! 1623: ! 1624: simple_lock(&rq->lock); /* lock the run queue */ ! 1625: assert(thread->runq == RUN_QUEUE_NULL); ! 1626: if (tail) ! 1627: enqueue_tail(&rq->runq[whichq], (queue_entry_t)thread); ! 1628: else ! 1629: enqueue_head(&rq->runq[whichq], (queue_entry_t)thread); ! 1630: ! 1631: setbit(MAXPRI - whichq, rq->bitmap); ! 1632: if (whichq > rq->highq) { ! 1633: rq->highq = whichq; ! 1634: } ! 1635: oldrqcount = rq->count++; ! 1636: if (whichq == DEPRESSPRI) ! 1637: rq->depress_count++; ! 1638: thread->runq = rq; ! 1639: thread->whichq = whichq; ! 1640: #if DEBUG ! 1641: thread_check(thread, rq); ! 1642: #endif /* DEBUG */ ! 1643: simple_unlock(&rq->lock); ! 1644: ! 1645: return (oldrqcount); ! 1646: } ! 1647: ! 1648: /* ! 1649: * thread_setrun: ! 1650: * ! 1651: * Make thread runnable; dispatch directly onto an idle processor ! 1652: * if possible. Else put on appropriate run queue (processor ! 1653: * if bound, else processor set. Caller must have lock on thread. ! 1654: * This is always called at splsched. ! 1655: * The tail parameter, if TRUE || TAIL_Q, indicates that the ! 1656: * thread should be placed at the tail of the runq. If ! 1657: * FALSE || HEAD_Q the thread will be placed at the head of the ! 1658: * appropriate runq. ! 1659: */ ! 1660: void ! 1661: thread_setrun( ! 1662: register thread_t new_thread, ! 1663: boolean_t may_preempt, ! 1664: boolean_t tail) ! 1665: { ! 1666: register processor_t processor; ! 1667: register run_queue_t runq; ! 1668: register processor_set_t pset; ! 1669: thread_t thread; ! 1670: ast_t ast_flags = AST_BLOCK; ! 1671: ! 1672: mp_disable_preemption(); ! 1673: ! 1674: assert(!(new_thread->state & TH_SWAPPED_OUT)); ! 1675: assert(thread_runnable(new_thread)); ! 1676: ! 1677: /* ! 1678: * Update priority if needed. ! 1679: */ ! 1680: /*** ??? fix me ***/ ! 1681: if (new_thread->policy & (POLICY_TIMESHARE|POLICY_RR|POLICY_FIFO)) { ! 1682: mk_sp_info_t sp_info = new_thread->sp_info; ! 1683: ! 1684: assert(sp_info != SP_INFO_NULL); ! 1685: if (sp_info->sched_stamp != sched_tick) ! 1686: update_priority(new_thread); ! 1687: ! 1688: #if 0 /* TEMPORARILY DISABLE PREEMPTION */ ! 1689: if ( (new_thread->policy & (POLICY_FIFO|POLICY_RR)) && ! 1690: sp_info->priority > BASEPRI_SYSTEM ) ! 1691: ast_flags |= AST_URGENT; ! 1692: #endif /* TEMPORARILY DISABLE PREEMPTION */ ! 1693: } ! 1694: ! 1695: assert(new_thread->runq == RUN_QUEUE_NULL); ! 1696: ! 1697: /*** ??? fix me ***/ ! 1698: assert(new_thread->sp_info != SP_INFO_NULL); ! 1699: ! 1700: /* ! 1701: * Try to dispatch the thread directly onto an idle processor. ! 1702: */ ! 1703: if ((processor = new_thread->bound_processor) == PROCESSOR_NULL) { ! 1704: /* ! 1705: * Not bound, any processor in the processor set is ok. ! 1706: */ ! 1707: pset = new_thread->processor_set; ! 1708: if (pset->idle_count > 0) { ! 1709: simple_lock(&pset->idle_lock); ! 1710: if (pset->idle_count > 0) { ! 1711: processor = (processor_t) queue_first(&pset->idle_queue); ! 1712: queue_remove(&(pset->idle_queue), processor, processor_t, ! 1713: processor_queue); ! 1714: pset->idle_count--; ! 1715: processor->next_thread = new_thread; ! 1716: processor->state = PROCESSOR_DISPATCHING; ! 1717: simple_unlock(&pset->idle_lock); ! 1718: ! 1719: mp_enable_preemption(); ! 1720: return; ! 1721: } ! 1722: simple_unlock(&pset->idle_lock); ! 1723: } ! 1724: ! 1725: ! 1726: /* ! 1727: * Preempt check ! 1728: */ ! 1729: runq = &pset->runq; ! 1730: thread = current_thread(); ! 1731: processor = current_processor(); ! 1732: if ( may_preempt && ! 1733: #if MACH_HOST ! 1734: pset == processor->processor_set && ! 1735: #endif /* MACH_HOST */ ! 1736: thread->sched_pri < new_thread->sched_pri ) { ! 1737: simple_lock(&processor->lock); ! 1738: pset = processor->processor_set; ! 1739: simple_lock(&pset->idle_lock); ! 1740: ! 1741: /* ! 1742: * XXX if we have a non-empty local runq or are ! 1743: * XXX running a bound thread, ought to check for ! 1744: * XXX another cpu running lower-pri thread to preempt. ! 1745: * ! 1746: * Turn off first_quantum to allow csw. ! 1747: */ ! 1748: if (processor->state == PROCESSOR_DISPATCHING) { ! 1749: thread = processor->next_thread; ! 1750: processor->next_thread = new_thread; ! 1751: simple_unlock(&pset->idle_lock); ! 1752: simple_unlock(&processor->lock); ! 1753: new_thread = thread; ! 1754: } ! 1755: else { ! 1756: simple_unlock(&pset->idle_lock); ! 1757: simple_unlock(&processor->lock); ! 1758: processor->first_quantum = FALSE; ! 1759: ast_on(ast_flags); ! 1760: } ! 1761: } ! 1762: ! 1763: /* ! 1764: * Put us on the end of the runq, if we are not preempting ! 1765: * or the guy we are preempting. ! 1766: */ ! 1767: run_queue_enqueue(runq, new_thread, tail); ! 1768: } ! 1769: else { ! 1770: /* ! 1771: * Bound, can only run on bound processor. Have to lock ! 1772: * processor here because it may not be the current one. ! 1773: */ ! 1774: if (processor->state == PROCESSOR_IDLE) { ! 1775: simple_lock(&processor->lock); ! 1776: pset = processor->processor_set; ! 1777: simple_lock(&pset->idle_lock); ! 1778: if (processor->state == PROCESSOR_IDLE) { ! 1779: queue_remove(&pset->idle_queue, processor, ! 1780: processor_t, processor_queue); ! 1781: pset->idle_count--; ! 1782: processor->next_thread = new_thread; ! 1783: processor->state = PROCESSOR_DISPATCHING; ! 1784: simple_unlock(&pset->idle_lock); ! 1785: simple_unlock(&processor->lock); ! 1786: ! 1787: mp_enable_preemption(); ! 1788: return; ! 1789: } ! 1790: simple_unlock(&pset->idle_lock); ! 1791: simple_unlock(&processor->lock); ! 1792: } ! 1793: ! 1794: /* ! 1795: * Cause ast on processor if processor is on line, and the ! 1796: * currently executing thread is not bound to that processor ! 1797: * (bound threads have implicit priority over non-bound threads). ! 1798: * We also avoid sending the AST to the idle thread (if it got ! 1799: * scheduled in the window between the 'if' above and here), ! 1800: * since the idle_thread is bound. ! 1801: */ ! 1802: runq = &processor->runq; ! 1803: thread = current_thread(); ! 1804: if (processor == current_processor()) { ! 1805: if ( thread->bound_processor == PROCESSOR_NULL || ! 1806: thread->sched_pri > new_thread->sched_pri ) { ! 1807: if (processor->state == PROCESSOR_DISPATCHING) { ! 1808: thread = processor->next_thread; ! 1809: processor->next_thread = new_thread; ! 1810: new_thread = thread; ! 1811: } ! 1812: else { ! 1813: processor->first_quantum = FALSE; ! 1814: ast_on(ast_flags); ! 1815: } ! 1816: } ! 1817: ! 1818: run_queue_enqueue(runq, new_thread, tail); ! 1819: } ! 1820: else { ! 1821: thread = cpu_data[processor->slot_num].active_thread; ! 1822: if ( run_queue_enqueue(runq, new_thread, tail) == 0 && ! 1823: processor->state != PROCESSOR_OFF_LINE && ! 1824: thread && thread->bound_processor != processor ) ! 1825: cause_ast_check(processor); ! 1826: } ! 1827: } ! 1828: ! 1829: mp_enable_preemption(); ! 1830: } ! 1831: ! 1832: /* ! 1833: * set_pri: ! 1834: * ! 1835: * Set the priority of the specified thread to the specified ! 1836: * priority. This may cause the thread to change queues. ! 1837: * ! 1838: * The thread *must* be locked by the caller. ! 1839: */ ! 1840: void ! 1841: set_pri( ! 1842: thread_t thread, ! 1843: int pri, ! 1844: boolean_t resched) ! 1845: { ! 1846: register struct run_queue *rq; ! 1847: ! 1848: rq = rem_runq(thread); ! 1849: assert(thread->runq == RUN_QUEUE_NULL); ! 1850: thread->sched_pri = pri; ! 1851: if (rq != RUN_QUEUE_NULL) { ! 1852: if (resched) ! 1853: thread_setrun(thread, TRUE, TAIL_Q); ! 1854: else ! 1855: run_queue_enqueue(rq, thread, TAIL_Q); ! 1856: } ! 1857: } ! 1858: ! 1859: /* ! 1860: * rem_runq: ! 1861: * ! 1862: * Remove a thread from its run queue. ! 1863: * The run queue that the process was on is returned ! 1864: * (or RUN_QUEUE_NULL if not on a run queue). Thread *must* be locked ! 1865: * before calling this routine. Unusual locking protocol on runq ! 1866: * field in thread structure makes this code interesting; see thread.h. ! 1867: */ ! 1868: run_queue_t ! 1869: rem_runq( ! 1870: thread_t thread) ! 1871: { ! 1872: register struct run_queue *rq; ! 1873: ! 1874: rq = thread->runq; ! 1875: /* ! 1876: * If rq is RUN_QUEUE_NULL, the thread will stay out of the ! 1877: * run_queues because the caller locked the thread. Otherwise ! 1878: * the thread is on a runq, but could leave. ! 1879: */ ! 1880: if (rq != RUN_QUEUE_NULL) { ! 1881: #if DEBUG ! 1882: thread_t t; ! 1883: int whichq; ! 1884: #endif ! 1885: simple_lock(&rq->lock); ! 1886: if (rq == thread->runq) { ! 1887: /* ! 1888: * Thread is in a runq and we have a lock on ! 1889: * that runq. ! 1890: */ ! 1891: #if DEBUG ! 1892: thread_check(thread, rq); ! 1893: #endif /* DEBUG */ ! 1894: remqueue(&rq->runq[0], (queue_entry_t)thread); ! 1895: rq->count--; ! 1896: ! 1897: if (thread->whichq == DEPRESSPRI) ! 1898: rq->depress_count--; ! 1899: ! 1900: if (queue_empty(rq->runq + thread->sched_pri)) { ! 1901: /* update run queue status */ ! 1902: clrbit(MAXPRI - thread->sched_pri, rq->bitmap); ! 1903: rq->highq = MAXPRI - ffsbit(rq->bitmap); ! 1904: } ! 1905: thread->runq = RUN_QUEUE_NULL; ! 1906: simple_unlock(&rq->lock); ! 1907: } ! 1908: else { ! 1909: /* ! 1910: * The thread left the runq before we could ! 1911: * lock the runq. It is not on a runq now, and ! 1912: * can't move again because this routine's ! 1913: * caller locked the thread. ! 1914: */ ! 1915: assert(thread->runq == RUN_QUEUE_NULL); ! 1916: simple_unlock(&rq->lock); ! 1917: rq = RUN_QUEUE_NULL; ! 1918: } ! 1919: } ! 1920: ! 1921: return (rq); ! 1922: } ! 1923: ! 1924: ! 1925: /* ! 1926: * choose_thread: ! 1927: * ! 1928: * Choose a thread to execute. The thread chosen is removed ! 1929: * from its run queue. Note that this requires only that the runq ! 1930: * lock be held. ! 1931: * ! 1932: * Strategy: ! 1933: * Check processor runq first; if anything found, run it. ! 1934: * Else check pset runq; if nothing found, return idle thread. ! 1935: * ! 1936: * Second line of strategy is implemented by choose_pset_thread. ! 1937: * This is only called on processor startup and when thread_block ! 1938: * thinks there's something in the processor runq. ! 1939: */ ! 1940: thread_t ! 1941: choose_thread( ! 1942: processor_t myprocessor) ! 1943: { ! 1944: thread_t thread; ! 1945: register queue_t q; ! 1946: register run_queue_t runq; ! 1947: processor_set_t pset; ! 1948: ! 1949: runq = &myprocessor->runq; ! 1950: pset = myprocessor->processor_set; ! 1951: ! 1952: simple_lock(&runq->lock); ! 1953: if (runq->count > 0 && runq->highq >= pset->runq.highq) { ! 1954: q = runq->runq + runq->highq; ! 1955: #if MACH_ASSERT ! 1956: if (!queue_empty(q)) { ! 1957: #endif /*MACH_ASSERT*/ ! 1958: thread = (thread_t)q->next; ! 1959: ((queue_entry_t)thread)->next->prev = q; ! 1960: q->next = ((queue_entry_t)thread)->next; ! 1961: thread->runq = RUN_QUEUE_NULL; ! 1962: runq->count--; ! 1963: if (thread->whichq == DEPRESSPRI) ! 1964: runq->depress_count--; ! 1965: if (queue_empty(q)) { ! 1966: clrbit(MAXPRI - runq->highq, runq->bitmap); ! 1967: runq->highq = MAXPRI - ffsbit(runq->bitmap); ! 1968: } ! 1969: simple_unlock(&runq->lock); ! 1970: return (thread); ! 1971: #if MACH_ASSERT ! 1972: } ! 1973: panic("choose_thread"); ! 1974: #endif /*MACH_ASSERT*/ ! 1975: /*NOTREACHED*/ ! 1976: } ! 1977: ! 1978: simple_unlock(&runq->lock); ! 1979: simple_lock(&pset->runq.lock); ! 1980: return (choose_pset_thread(myprocessor, pset)); ! 1981: } ! 1982: ! 1983: ! 1984: /* ! 1985: * choose_pset_thread: choose a thread from processor_set runq or ! 1986: * set processor idle and choose its idle thread. ! 1987: * ! 1988: * Caller must be at splsched and have a lock on the runq. This ! 1989: * lock is released by this routine. myprocessor is always the current ! 1990: * processor, and pset must be its processor set. ! 1991: * This routine chooses and removes a thread from the runq if there ! 1992: * is one (and returns it), else it sets the processor idle and ! 1993: * returns its idle thread. ! 1994: */ ! 1995: thread_t ! 1996: choose_pset_thread( ! 1997: register processor_t myprocessor, ! 1998: processor_set_t pset) ! 1999: { ! 2000: register run_queue_t runq; ! 2001: register thread_t thread; ! 2002: register queue_t q; ! 2003: ! 2004: runq = &pset->runq; ! 2005: if (runq->count > 0) { ! 2006: q = runq->runq + runq->highq; ! 2007: #if MACH_ASSERT ! 2008: if (!queue_empty(q)) { ! 2009: #endif /*MACH_ASSERT*/ ! 2010: thread = (thread_t)q->next; ! 2011: ((queue_entry_t)thread)->next->prev = q; ! 2012: q->next = ((queue_entry_t)thread)->next; ! 2013: thread->runq = RUN_QUEUE_NULL; ! 2014: runq->count--; ! 2015: if (thread->whichq == DEPRESSPRI) ! 2016: runq->depress_count--; ! 2017: if (queue_empty(q)) { ! 2018: clrbit(MAXPRI - runq->highq, runq->bitmap); ! 2019: runq->highq = MAXPRI - ffsbit(runq->bitmap); ! 2020: } ! 2021: simple_unlock(&runq->lock); ! 2022: return (thread); ! 2023: #if MACH_ASSERT ! 2024: } ! 2025: panic("choose_pset_thread"); ! 2026: #endif /*MACH_ASSERT*/ ! 2027: /*NOTREACHED*/ ! 2028: } ! 2029: simple_unlock(&runq->lock); ! 2030: ! 2031: /* ! 2032: * Nothing is runnable, so set this processor idle if it ! 2033: * was running. If it was in an assignment or shutdown, ! 2034: * leave it alone. Return its idle thread. ! 2035: */ ! 2036: simple_lock(&pset->idle_lock); ! 2037: if (myprocessor->state == PROCESSOR_RUNNING) { ! 2038: myprocessor->state = PROCESSOR_IDLE; ! 2039: /* ! 2040: * XXX Until it goes away, put master on end of queue, others ! 2041: * XXX on front so master gets used last. ! 2042: */ ! 2043: if (myprocessor == master_processor) ! 2044: queue_enter(&(pset->idle_queue), myprocessor, ! 2045: processor_t, processor_queue); ! 2046: else ! 2047: queue_enter_first(&(pset->idle_queue), myprocessor, ! 2048: processor_t, processor_queue); ! 2049: ! 2050: pset->idle_count++; ! 2051: } ! 2052: simple_unlock(&pset->idle_lock); ! 2053: ! 2054: return (myprocessor->idle_thread); ! 2055: } ! 2056: ! 2057: /* ! 2058: * no_dispatch_count counts number of times processors go non-idle ! 2059: * without being dispatched. This should be very rare. ! 2060: */ ! 2061: int no_dispatch_count = 0; ! 2062: ! 2063: /* ! 2064: * This is the idle thread, which just looks for other threads ! 2065: * to execute. ! 2066: */ ! 2067: void ! 2068: idle_thread_continue(void) ! 2069: { ! 2070: register processor_t myprocessor; ! 2071: register volatile thread_t *threadp; ! 2072: register volatile int *gcount; ! 2073: register volatile int *lcount; ! 2074: register thread_t new_thread; ! 2075: register int state; ! 2076: register processor_set_t pset; ! 2077: int mycpu; ! 2078: spl_t s; ! 2079: ! 2080: mycpu = cpu_number(); ! 2081: myprocessor = current_processor(); ! 2082: threadp = (volatile thread_t *) &myprocessor->next_thread; ! 2083: lcount = (volatile int *) &myprocessor->runq.count; ! 2084: ! 2085: for (;;) { ! 2086: #ifdef MARK_CPU_IDLE ! 2087: MARK_CPU_IDLE(mycpu); ! 2088: #endif /* MARK_CPU_IDLE */ ! 2089: ! 2090: #if MACH_HOST ! 2091: gcount = (volatile int *)&myprocessor->processor_set->runq.count; ! 2092: #else /* MACH_HOST */ ! 2093: gcount = (volatile int *)&default_pset.runq.count; ! 2094: #endif /* MACH_HOST */ ! 2095: ! 2096: /* ! 2097: * This cpu will be dispatched (by thread_setrun) by setting next_thread ! 2098: * to the value of the thread to run next. Also check runq counts. ! 2099: */ ! 2100: s = splsched(); ! 2101: while ((*threadp == (volatile thread_t)THREAD_NULL) && (*gcount == 0) && (*lcount == 0)) { ! 2102: ! 2103: /* check for ASTs while we wait */ ! 2104: ! 2105: if (need_ast[mycpu] &~ (AST_SCHEDULING|AST_BSD|AST_BSD_INIT)) { ! 2106: /* don't allow scheduling ASTs */ ! 2107: need_ast[mycpu] &= ~(AST_SCHEDULING|AST_BSD|AST_BSD_INIT); ! 2108: splx(s); ! 2109: ast_taken(FALSE, AST_ALL, s); ! 2110: /* back at spllo */ ! 2111: } ! 2112: else ! 2113: splx(s); ! 2114: ! 2115: machine_clock_assist(); ! 2116: ! 2117: /* ! 2118: * machine_idle is a machine dependent function, ! 2119: * to conserve power. ! 2120: */ ! 2121: #if POWER_SAVE ! 2122: machine_idle(mycpu); ! 2123: #endif /* POWER_SAVE */ ! 2124: s = splsched(); ! 2125: } ! 2126: ! 2127: #ifdef MARK_CPU_ACTIVE ! 2128: splx(s); ! 2129: MARK_CPU_ACTIVE(mycpu); ! 2130: s = splsched(); ! 2131: #endif /* MARK_CPU_ACTIVE */ ! 2132: ! 2133: /* ! 2134: * This is not a switch statement to avoid the ! 2135: * bounds checking code in the common case. ! 2136: */ ! 2137: pset = myprocessor->processor_set; ! 2138: simple_lock(&pset->idle_lock); ! 2139: retry: ! 2140: state = myprocessor->state; ! 2141: if (state == PROCESSOR_DISPATCHING) { ! 2142: /* ! 2143: * Commmon case -- cpu dispatched. ! 2144: */ ! 2145: new_thread = *threadp; ! 2146: *threadp = (volatile thread_t) THREAD_NULL; ! 2147: myprocessor->state = PROCESSOR_RUNNING; ! 2148: ! 2149: simple_unlock(&pset->idle_lock); ! 2150: thread_lock(new_thread); ! 2151: ! 2152: /* ! 2153: * set up quantum for new thread. ! 2154: */ ! 2155: if (new_thread->policy == POLICY_TIMESHARE) { ! 2156: /* ! 2157: * Just use set quantum. No point in ! 2158: * checking for shorter local runq quantum; ! 2159: * csw_needed will handle correctly. ! 2160: */ ! 2161: #if MACH_HOST ! 2162: myprocessor->quantum = new_thread->processor_set->set_quantum; ! 2163: #else /* MACH_HOST */ ! 2164: myprocessor->quantum = default_pset.set_quantum; ! 2165: #endif /* MACH_HOST */ ! 2166: } ! 2167: else ! 2168: if (new_thread->policy & (POLICY_RR|POLICY_FIFO)) { ! 2169: mk_sp_info_t sp_info = (mk_sp_info_t)new_thread->sp_info; ! 2170: ! 2171: assert(sp_info != SP_INFO_NULL); ! 2172: myprocessor->quantum = sp_info->unconsumed_quantum; ! 2173: } ! 2174: ! 2175: thread_unlock(new_thread); ! 2176: ! 2177: myprocessor->first_quantum = TRUE; ! 2178: counter(c_idle_thread_handoff++); ! 2179: thread_run((void(*)(void))0, new_thread); ! 2180: } ! 2181: else ! 2182: if (state == PROCESSOR_IDLE) { ! 2183: ! 2184: if (myprocessor->state != PROCESSOR_IDLE) { ! 2185: /* ! 2186: * Something happened, try again. ! 2187: */ ! 2188: goto retry; ! 2189: } ! 2190: /* ! 2191: * Processor was not dispatched (Rare). ! 2192: * Set it running again. ! 2193: */ ! 2194: no_dispatch_count++; ! 2195: pset->idle_count--; ! 2196: queue_remove(&pset->idle_queue, myprocessor, ! 2197: processor_t, processor_queue); ! 2198: myprocessor->state = PROCESSOR_RUNNING; ! 2199: simple_unlock(&pset->idle_lock); ! 2200: counter(c_idle_thread_block++); ! 2201: thread_block((void(*)(void))0); ! 2202: } ! 2203: else ! 2204: if ( state == PROCESSOR_ASSIGN || ! 2205: state == PROCESSOR_SHUTDOWN ) { ! 2206: /* ! 2207: * Changing processor sets, or going off-line. ! 2208: * Release next_thread if there is one. Actual ! 2209: * thread to run in on a runq. ! 2210: */ ! 2211: if ((new_thread = (thread_t)*threadp)!= THREAD_NULL) { ! 2212: *threadp = (volatile thread_t) THREAD_NULL; ! 2213: thread_setrun(new_thread, FALSE, TAIL_Q); ! 2214: } ! 2215: ! 2216: counter(c_idle_thread_block++); ! 2217: thread_block((void(*)(void))0); ! 2218: } ! 2219: else { ! 2220: simple_unlock(&pset->idle_lock); ! 2221: printf("Bad processor state %d (Cpu %d)\n", ! 2222: cpu_state(mycpu), mycpu); ! 2223: panic("idle_thread"); ! 2224: ! 2225: } ! 2226: splx(s); ! 2227: } ! 2228: } ! 2229: ! 2230: void ! 2231: idle_thread(void) ! 2232: { ! 2233: thread_t self = current_thread(); ! 2234: mk_sp_info_t sp_info; ! 2235: spl_t s; ! 2236: ! 2237: stack_privilege(self); ! 2238: thread_swappable(current_act(), FALSE); ! 2239: ! 2240: s = splsched(); ! 2241: thread_lock(self); ! 2242: ! 2243: /* ! 2244: * Set the idle flag to indicate that this is an idle thread, ! 2245: * enter ourselves in the idle array, and thread_block() to get ! 2246: * out of the run queues (and set the processor idle when we ! 2247: * run next time). ! 2248: */ ! 2249: self->state |= TH_IDLE; ! 2250: current_processor()->idle_thread = self; ! 2251: ! 2252: /*** ??? fix me ***/ ! 2253: assert(self->policy == POLICY_FIFO); ! 2254: sp_info = (mk_sp_info_t)self->sp_info; ! 2255: assert(sp_info != SP_INFO_NULL); ! 2256: sp_info->priority = IDLEPRI; ! 2257: self->sched_pri = sp_info->priority; ! 2258: ! 2259: thread_unlock(self); ! 2260: splx(s); ! 2261: ! 2262: counter(c_idle_thread_block++); ! 2263: thread_block((void(*)(void))0); ! 2264: idle_thread_continue(); ! 2265: /*NOTREACHED*/ ! 2266: ! 2267: panic("idle_thread_continue!"); ! 2268: } ! 2269: ! 2270: static thread_call_t sched_tick_timer; ! 2271: static thread_call_data_t sched_tick_timer_data; ! 2272: static AbsoluteTime sched_tick_interval, sched_tick_deadline; ! 2273: ! 2274: /* ! 2275: * recompute_priorities: ! 2276: * ! 2277: * Update the priorities of all threads periodically. ! 2278: */ ! 2279: void ! 2280: _recompute_priorities(void) ! 2281: { ! 2282: AbsoluteTime abstime; ! 2283: #if SIMPLE_CLOCK ! 2284: int new_usec; ! 2285: #endif /* SIMPLE_CLOCK */ ! 2286: ! 2287: clock_get_uptime(&abstime); ! 2288: ! 2289: sched_tick++; /* age usage one more time */ ! 2290: #if SIMPLE_CLOCK ! 2291: /* ! 2292: * Compensate for clock drift. sched_usec is an ! 2293: * exponential average of the number of microseconds in ! 2294: * a second. It decays in the same fashion as cpu_usage. ! 2295: */ ! 2296: new_usec = sched_usec_elapsed(); ! 2297: sched_usec = (5*sched_usec + 3*new_usec)/8; ! 2298: #endif /* SIMPLE_CLOCK */ ! 2299: ! 2300: /* ! 2301: * Compute the scheduler load factors. ! 2302: */ ! 2303: compute_mach_factor(); ! 2304: ! 2305: /* ! 2306: * Scan the run queues for runnable threads that need to ! 2307: * have their priorities recalculated. ! 2308: */ ! 2309: do_thread_scan(); ! 2310: ! 2311: clock_deadline_for_periodic_event(sched_tick_interval, abstime, ! 2312: &sched_tick_deadline); ! 2313: thread_call_enter_delayed(sched_tick_timer, sched_tick_deadline); ! 2314: } ! 2315: ! 2316: void ! 2317: recompute_priorities(void) ! 2318: { ! 2319: thread_call_setup(&sched_tick_timer_data, _recompute_priorities, NULL); ! 2320: clock_interval_to_absolutetime_interval(1, NSEC_PER_SEC, ! 2321: &sched_tick_interval); ! 2322: clock_get_uptime(&sched_tick_deadline); ! 2323: sched_tick_timer = &sched_tick_timer_data; ! 2324: ! 2325: _recompute_priorities(); ! 2326: } ! 2327: ! 2328: #define MAX_STUCK_THREADS 128 ! 2329: ! 2330: /* ! 2331: * do_thread_scan: scan for stuck threads. A thread is stuck if ! 2332: * it is runnable but its priority is so low that it has not ! 2333: * run for several seconds. Its priority should be higher, but ! 2334: * won't be until it runs and calls update_priority. The scanner ! 2335: * finds these threads and does the updates. ! 2336: * ! 2337: * Scanner runs in two passes. Pass one squirrels likely ! 2338: * thread ids away in an array (takes out references for them). ! 2339: * Pass two does the priority updates. This is necessary because ! 2340: * the run queue lock is required for the candidate scan, but ! 2341: * cannot be held during updates [set_pri will deadlock]. ! 2342: * ! 2343: * Array length should be enough so that restart isn't necessary, ! 2344: * but restart logic is included. Does not scan processor runqs. ! 2345: * ! 2346: */ ! 2347: thread_t stuck_threads[MAX_STUCK_THREADS]; ! 2348: int stuck_count = 0; ! 2349: ! 2350: /* ! 2351: * do_runq_scan is the guts of pass 1. It scans a runq for ! 2352: * stuck threads. A boolean is returned indicating whether ! 2353: * a retry is needed. ! 2354: */ ! 2355: boolean_t ! 2356: do_runq_scan( ! 2357: run_queue_t runq, ! 2358: int *mask) ! 2359: { ! 2360: register queue_t q; ! 2361: register thread_t thread; ! 2362: register int count; ! 2363: int qindex; ! 2364: spl_t s; ! 2365: boolean_t result = FALSE; ! 2366: ! 2367: s = splsched(); ! 2368: simple_lock(&runq->lock); ! 2369: if ((count = runq->count) > 0) { ! 2370: q = runq->runq + runq->highq; ! 2371: qindex = runq->highq; ! 2372: while (count > 0) { ! 2373: boolean_t qvalid = testbit(qindex, mask); ! 2374: ! 2375: queue_iterate(q, thread, thread_t, links) { ! 2376: if ( qvalid && ! 2377: !(thread->state & (TH_WAIT|TH_SUSP)) && ! 2378: thread->policy == POLICY_TIMESHARE ) { ! 2379: mk_sp_info_t sp_info = thread->sp_info; ! 2380: ! 2381: assert(sp_info != SP_INFO_NULL); ! 2382: /*** ??? fix me ***/ ! 2383: if (sp_info->sched_stamp != sched_tick) { ! 2384: /* ! 2385: * Stuck, save its id for later. ! 2386: */ ! 2387: if (stuck_count == MAX_STUCK_THREADS) { ! 2388: /* ! 2389: * !@#$% No more room. ! 2390: */ ! 2391: simple_unlock(&runq->lock); ! 2392: splx(s); ! 2393: ! 2394: return (TRUE); ! 2395: } ! 2396: ! 2397: /* ! 2398: * Inline version of thread_reference ! 2399: * XXX - lock ordering problem here: ! 2400: * thread locks should be taken before runq ! 2401: * locks: just try and get the thread's locks ! 2402: * and ignore this thread if we fail, we might ! 2403: * have better luck next time. ! 2404: */ ! 2405: if (simple_lock_try(&thread->lock)) { ! 2406: thread->ref_count++; ! 2407: thread_unlock(thread); ! 2408: stuck_threads[stuck_count++] = thread; ! 2409: } ! 2410: else ! 2411: result = TRUE; ! 2412: } ! 2413: } ! 2414: ! 2415: count--; ! 2416: } ! 2417: ! 2418: q--; ! 2419: qindex--; ! 2420: } ! 2421: } ! 2422: simple_unlock(&runq->lock); ! 2423: splx(s); ! 2424: ! 2425: return (result); ! 2426: } ! 2427: ! 2428: boolean_t thread_scan_enabled = TRUE; ! 2429: ! 2430: void ! 2431: do_thread_scan(void) ! 2432: { ! 2433: register boolean_t restart_needed = FALSE; ! 2434: register thread_t thread; ! 2435: #if MACH_HOST ! 2436: register processor_set_t pset; ! 2437: #endif /* MACH_HOST */ ! 2438: int *mask; ! 2439: spl_t s; ! 2440: ! 2441: if (!thread_scan_enabled) ! 2442: return; ! 2443: ! 2444: mask = sched_policy[POLICY_TIMESHARE].priority_mask.bitmap; ! 2445: ! 2446: do { ! 2447: #if MACH_HOST ! 2448: mutex_lock(&all_psets_lock); ! 2449: queue_iterate(&all_psets, pset, processor_set_t, all_psets) { ! 2450: if (restart_needed = do_runq_scan(&pset->runq, mask)) ! 2451: break; ! 2452: } ! 2453: mutex_unlock(&all_psets_lock); ! 2454: #else /* MACH_HOST */ ! 2455: restart_needed = do_runq_scan(&default_pset.runq, mask); ! 2456: #endif /* MACH_HOST */ ! 2457: if (!restart_needed) ! 2458: restart_needed = do_runq_scan(&master_processor->runq, mask); ! 2459: ! 2460: /* ! 2461: * Ok, we now have a collection of candidates -- fix them. ! 2462: */ ! 2463: while (stuck_count > 0) { ! 2464: thread = stuck_threads[--stuck_count]; ! 2465: stuck_threads[stuck_count] = THREAD_NULL; ! 2466: s = splsched(); ! 2467: thread_lock(thread); ! 2468: /*** ??? fix me ***/ ! 2469: if (thread->policy == POLICY_TIMESHARE) { ! 2470: mk_sp_info_t sp_info = thread->sp_info; ! 2471: ! 2472: assert(thread->sp_info != SP_INFO_NULL); ! 2473: if ( !(thread->state & (TH_WAIT|TH_SUSP)) && ! 2474: /*** ??? fix me ***/ ! 2475: sp_info->sched_stamp != sched_tick ) ! 2476: update_priority(thread); ! 2477: } ! 2478: thread_unlock(thread); ! 2479: splx(s); ! 2480: thread_deallocate(thread); ! 2481: } ! 2482: ! 2483: } while (restart_needed); ! 2484: } ! 2485: ! 2486: /* ! 2487: * Just in case someone doesn't use the macro ! 2488: */ ! 2489: #undef thread_wakeup ! 2490: void ! 2491: thread_wakeup( ! 2492: event_t x); ! 2493: ! 2494: void ! 2495: thread_wakeup( ! 2496: event_t x) ! 2497: { ! 2498: thread_wakeup_with_result(x, THREAD_AWAKENED); ! 2499: } ! 2500: ! 2501: boolean_t ! 2502: thread_runnable( ! 2503: thread_t thread) ! 2504: { ! 2505: sched_policy_t *policy; ! 2506: ! 2507: /* Ask sched policy if thread is runnable */ ! 2508: policy = policy_id_to_sched_policy(thread->policy); ! 2509: ! 2510: return ((policy != SCHED_POLICY_NULL)? ! 2511: policy->sp_ops.sp_thread_runnable(policy, thread) : FALSE); ! 2512: } ! 2513: ! 2514: void ! 2515: dump_processor_set( ! 2516: processor_set_t ps) ! 2517: { ! 2518: printf("processor_set: %08x\n",ps); ! 2519: printf("idle_queue: %08x %08x, idle_count: 0x%x\n", ! 2520: ps->idle_queue.next,ps->idle_queue.prev,ps->idle_count); ! 2521: printf("processors: %08x %08x, processor_count: 0x%x, empty: %x\n", ! 2522: ps->processors.next,ps->processors.prev,ps->processor_count); ! 2523: printf("tasks: %08x %08x, task_count: 0x%x\n", ! 2524: ps->tasks.next,ps->tasks.prev,ps->task_count); ! 2525: printf("threads: %08x %08x, thread_count: 0x%x\n", ! 2526: ps->threads.next,ps->threads.prev,ps->thread_count); ! 2527: printf("ref_count: 0x%x, all_psets: %08x %08x, active: %x\n", ! 2528: ps->ref_count, ps->all_psets.next,ps->all_psets.prev,ps->active); ! 2529: printf("pset_self: %08x, pset_name_self: %08x\n",ps->pset_self, ps->pset_name_self); ! 2530: printf("max_priority: 0x%x, policies: 0x%x, set_quantum: 0x%x\n", ! 2531: ps->max_priority, ps->policies, ps->set_quantum); ! 2532: } ! 2533: ! 2534: #define processor_state(s) (((s)>PROCESSOR_SHUTDOWN)?"*unknown*":states[s]) ! 2535: ! 2536: void ! 2537: dump_processor( ! 2538: processor_t p) ! 2539: { ! 2540: char *states[]={"OFF_LINE","RUNNING","IDLE","DISPATCHING", ! 2541: "ASSIGN","SHUTDOWN"}; ! 2542: ! 2543: printf("processor: %08x\n",p); ! 2544: printf("processor_queue: %08x %08x\n", ! 2545: p->processor_queue.next,p->processor_queue.prev); ! 2546: printf("state: %8s, next_thread: %08x, idle_thread: %08x\n", ! 2547: processor_state(p->state), p->next_thread, p->idle_thread); ! 2548: printf("quantum: %u, first_quantum: %x, last_quantum: %u\n", ! 2549: p->quantum, p->first_quantum, p->last_quantum); ! 2550: printf("processor_set: %08x, processor_set_next: %08x\n", ! 2551: p->processor_set, p->processor_set_next); ! 2552: printf("processors: %08x %08x\n", p->processors.next,p->processors.prev); ! 2553: printf("processor_self: %08x, slot_num: 0x%x\n", p->processor_self, p->slot_num); ! 2554: } ! 2555: ! 2556: void ! 2557: dump_run_queue_struct( ! 2558: run_queue_t rq) ! 2559: { ! 2560: char dump_buf[80]; ! 2561: int i; ! 2562: ! 2563: for( i=0; i < NRQS; ) { ! 2564: int j; ! 2565: ! 2566: printf("%6s",(i==0)?"runq:":""); ! 2567: for( j=0; (j<8) && (i < NRQS); j++,i++ ) { ! 2568: if( rq->runq[i].next == &rq->runq[i] ) ! 2569: printf( " --------"); ! 2570: else ! 2571: printf(" %08x",rq->runq[i].next); ! 2572: } ! 2573: printf("\n"); ! 2574: } ! 2575: for( i=0; i < NRQBM; ) { ! 2576: register unsigned int mask; ! 2577: char *d=dump_buf; ! 2578: ! 2579: mask = ~0; ! 2580: mask ^= (mask>>1); ! 2581: ! 2582: do { ! 2583: *d++ = ((rq->bitmap[i]&mask)?'r':'e'); ! 2584: mask >>=1; ! 2585: } while( mask ); ! 2586: *d = '\0'; ! 2587: printf("%8s%s\n",((i==0)?"bitmap:":""),dump_buf); ! 2588: i++; ! 2589: } ! 2590: printf("highq: 0x%x, count: %u\n", rq->highq, rq->count); ! 2591: } ! 2592: ! 2593: void ! 2594: dump_run_queues( ! 2595: run_queue_t runq) ! 2596: { ! 2597: register queue_t q1; ! 2598: register int i; ! 2599: register queue_entry_t e; ! 2600: ! 2601: q1 = runq->runq; ! 2602: for (i = 0; i < NRQS; i++) { ! 2603: if (q1->next != q1) { ! 2604: int t_cnt; ! 2605: ! 2606: printf("[%u]",i); ! 2607: for (t_cnt=0, e = q1->next; e != q1; e = e->next) { ! 2608: printf("\t0x%08x",e); ! 2609: if( (t_cnt = ++t_cnt%4) == 0 ) ! 2610: printf("\n"); ! 2611: } ! 2612: if( t_cnt ) ! 2613: printf("\n"); ! 2614: } ! 2615: /* else ! 2616: printf("[%u]\t<empty>\n",i); ! 2617: */ ! 2618: q1++; ! 2619: } ! 2620: } ! 2621: ! 2622: #if DEBUG ! 2623: ! 2624: void ! 2625: checkrq( ! 2626: run_queue_t rq, ! 2627: char *msg) ! 2628: { ! 2629: register queue_t q1; ! 2630: register int i, j; ! 2631: register queue_entry_t e; ! 2632: register int highq; ! 2633: ! 2634: highq = NRQS; ! 2635: j = 0; ! 2636: q1 = rq->runq; ! 2637: for (i = MAXPRI; i >= 0; i--) { ! 2638: if (q1->next == q1) { ! 2639: if (q1->prev != q1) { ! 2640: panic("checkrq: empty at %s", msg); ! 2641: } ! 2642: } ! 2643: else { ! 2644: if (highq == -1) ! 2645: highq = i; ! 2646: ! 2647: for (e = q1->next; e != q1; e = e->next) { ! 2648: j++; ! 2649: if (e->next->prev != e) ! 2650: panic("checkrq-2 at %s", msg); ! 2651: if (e->prev->next != e) ! 2652: panic("checkrq-3 at %s", msg); ! 2653: } ! 2654: } ! 2655: q1++; ! 2656: } ! 2657: if (j != rq->count) ! 2658: panic("checkrq: count wrong at %s", msg); ! 2659: if (rq->count != 0 && highq > rq->highq) ! 2660: panic("checkrq: highq wrong at %s", msg); ! 2661: } ! 2662: ! 2663: void ! 2664: thread_check( ! 2665: register thread_t th, ! 2666: register run_queue_t rq) ! 2667: { ! 2668: register unsigned int whichq; ! 2669: ! 2670: whichq = th->sched_pri; ! 2671: if (whichq < MINPRI) { ! 2672: printf("thread_check: priority too high\n"); ! 2673: whichq = MINPRI; ! 2674: } ! 2675: if ((th->links.next == &rq->runq[whichq]) && ! 2676: (rq->runq[whichq].prev != (queue_entry_t)th)) ! 2677: panic("thread_check"); ! 2678: } ! 2679: ! 2680: #endif /* DEBUG */ ! 2681: ! 2682: #if MACH_KDB ! 2683: #include <ddb/db_output.h> ! 2684: #define printf kdbprintf ! 2685: extern int db_indent; ! 2686: void db_sched(void); ! 2687: ! 2688: void ! 2689: db_sched(void) ! 2690: { ! 2691: iprintf("Scheduling Statistics:\n"); ! 2692: db_indent += 2; ! 2693: iprintf("Thread invocations: csw %d same %d\n", ! 2694: c_thread_invoke_csw, c_thread_invoke_same); ! 2695: #if MACH_COUNTERS ! 2696: iprintf("Thread block: calls %d\n", ! 2697: c_thread_block_calls); ! 2698: iprintf("Idle thread:\n\thandoff %d block %d no_dispatch %d\n", ! 2699: c_idle_thread_handoff, ! 2700: c_idle_thread_block, no_dispatch_count); ! 2701: iprintf("Sched thread blocks: %d\n", c_sched_thread_block); ! 2702: #endif /* MACH_COUNTERS */ ! 2703: db_indent -= 2; ! 2704: } ! 2705: #endif /* MACH_KDB */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.