|
|
1.1 ! root 1: /* ! 2: * Mach Operating System ! 3: * Copyright (c) 1994-1987 Carnegie Mellon University ! 4: * All Rights Reserved. ! 5: * ! 6: * Permission to use, copy, modify and distribute this software and its ! 7: * documentation is hereby granted, provided that both the copyright ! 8: * notice and this permission notice appear in all copies of the ! 9: * software, derivative works or modified versions, and any portions ! 10: * thereof, and that both notices appear in supporting documentation. ! 11: * ! 12: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" ! 13: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR ! 14: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 15: * ! 16: * Carnegie Mellon requests users of this software to return to ! 17: * ! 18: * Software Distribution Coordinator or [email protected] ! 19: * School of Computer Science ! 20: * Carnegie Mellon University ! 21: * Pittsburgh PA 15213-3890 ! 22: * ! 23: * any improvements or extensions that they make and grant Carnegie Mellon ! 24: * the rights to redistribute these changes. ! 25: */ ! 26: /* ! 27: * File: kern/thread.c ! 28: * Author: Avadis Tevanian, Jr., Michael Wayne Young, David Golub ! 29: * Date: 1986 ! 30: * ! 31: * Thread management primitives implementation. ! 32: */ ! 33: ! 34: #include <cpus.h> ! 35: #include <hw_footprint.h> ! 36: #include <mach_host.h> ! 37: #include <mach_fixpri.h> ! 38: #include <mach_pcsample.h> ! 39: #include <simple_clock.h> ! 40: #include <mach_debug.h> ! 41: #include <net_atm.h> ! 42: ! 43: #include <mach/std_types.h> ! 44: #include <mach/policy.h> ! 45: #include <mach/thread_info.h> ! 46: #include <mach/thread_special_ports.h> ! 47: #include <mach/thread_status.h> ! 48: #include <mach/time_value.h> ! 49: #include "vm_param.h" ! 50: #include <kern/ast.h> ! 51: #include <kern/counters.h> ! 52: #include <kern/ipc_tt.h> ! 53: #include <kern/mach_param.h> ! 54: #include <kern/processor.h> ! 55: #include <kern/queue.h> ! 56: #include <kern/sched.h> ! 57: #include <kern/sched_prim.h> ! 58: #include <kern/thread.h> ! 59: #include <kern/thread_swap.h> ! 60: #include <kern/host.h> ! 61: #include <kern/zalloc.h> ! 62: #include <vm/vm_kern.h> ! 63: #include <ipc/ipc_kmsg.h> ! 64: #include <ipc/ipc_port.h> ! 65: #include <ipc/mach_msg.h> ! 66: #include <machine/machspl.h> /* for splsched */ ! 67: #include <machine/thread.h> /* for MACHINE_STACK */ ! 68: ! 69: #if NET_ATM ! 70: #include <chips/nw_mk.h> ! 71: #endif ! 72: ! 73: thread_t active_threads[NCPUS]; ! 74: vm_offset_t active_stacks[NCPUS]; ! 75: ! 76: struct zone *thread_zone; ! 77: ! 78: queue_head_t reaper_queue; ! 79: decl_simple_lock_data(, reaper_lock) ! 80: ! 81: extern int tick; ! 82: ! 83: extern void pcb_module_init(void); ! 84: ! 85: /* private */ ! 86: struct thread thread_template; ! 87: ! 88: #if MACH_DEBUG ! 89: void stack_init(vm_offset_t stack); /* forward */ ! 90: void stack_finalize(vm_offset_t stack); /* forward */ ! 91: ! 92: #define STACK_MARKER 0xdeadbeefU ! 93: boolean_t stack_check_usage = FALSE; ! 94: decl_simple_lock_data(, stack_usage_lock) ! 95: vm_size_t stack_max_usage = 0; ! 96: #endif /* MACH_DEBUG */ ! 97: ! 98: /* ! 99: * Machine-dependent code must define: ! 100: * pcb_init ! 101: * pcb_terminate ! 102: * pcb_collect ! 103: * ! 104: * The thread->pcb field is reserved for machine-dependent code. ! 105: */ ! 106: ! 107: #ifdef MACHINE_STACK ! 108: /* ! 109: * Machine-dependent code must define: ! 110: * stack_alloc_try ! 111: * stack_alloc ! 112: * stack_free ! 113: * stack_handoff ! 114: * stack_collect ! 115: * and if MACH_DEBUG: ! 116: * stack_statistics ! 117: */ ! 118: #else /* MACHINE_STACK */ ! 119: /* ! 120: * We allocate stacks from generic kernel VM. ! 121: * Machine-dependent code must define: ! 122: * stack_attach ! 123: * stack_detach ! 124: * stack_handoff ! 125: * ! 126: * The stack_free_list can only be accessed at splsched, ! 127: * because stack_alloc_try/thread_invoke operate at splsched. ! 128: */ ! 129: ! 130: decl_simple_lock_data(, stack_lock_data)/* splsched only */ ! 131: #define stack_lock() simple_lock(&stack_lock_data) ! 132: #define stack_unlock() simple_unlock(&stack_lock_data) ! 133: ! 134: vm_offset_t stack_free_list; /* splsched only */ ! 135: unsigned int stack_free_count = 0; /* splsched only */ ! 136: unsigned int stack_free_limit = 1; /* patchable */ ! 137: ! 138: unsigned int stack_alloc_hits = 0; /* debugging */ ! 139: unsigned int stack_alloc_misses = 0; /* debugging */ ! 140: unsigned int stack_alloc_max = 0; /* debugging */ ! 141: ! 142: /* ! 143: * The next field is at the base of the stack, ! 144: * so the low end is left unsullied. ! 145: */ ! 146: ! 147: #define stack_next(stack) (*((vm_offset_t *)((stack) + KERNEL_STACK_SIZE) - 1)) ! 148: ! 149: /* ! 150: * stack_alloc_try: ! 151: * ! 152: * Non-blocking attempt to allocate a kernel stack. ! 153: * Called at splsched with the thread locked. ! 154: */ ! 155: ! 156: boolean_t stack_alloc_try( ! 157: thread_t thread, ! 158: void (*resume)(thread_t)) ! 159: { ! 160: register vm_offset_t stack; ! 161: ! 162: stack_lock(); ! 163: stack = stack_free_list; ! 164: if (stack != 0) { ! 165: stack_free_list = stack_next(stack); ! 166: stack_free_count--; ! 167: } else { ! 168: stack = thread->stack_privilege; ! 169: } ! 170: stack_unlock(); ! 171: ! 172: if (stack != 0) { ! 173: stack_attach(thread, stack, resume); ! 174: stack_alloc_hits++; ! 175: return TRUE; ! 176: } else { ! 177: stack_alloc_misses++; ! 178: return FALSE; ! 179: } ! 180: } ! 181: ! 182: /* ! 183: * stack_alloc: ! 184: * ! 185: * Allocate a kernel stack for a thread. ! 186: * May block. ! 187: */ ! 188: ! 189: void stack_alloc( ! 190: thread_t thread, ! 191: void (*resume)(thread_t)) ! 192: { ! 193: vm_offset_t stack; ! 194: spl_t s; ! 195: ! 196: /* ! 197: * We first try the free list. It is probably empty, ! 198: * or stack_alloc_try would have succeeded, but possibly ! 199: * a stack was freed before the swapin thread got to us. ! 200: */ ! 201: ! 202: s = splsched(); ! 203: stack_lock(); ! 204: stack = stack_free_list; ! 205: if (stack != 0) { ! 206: stack_free_list = stack_next(stack); ! 207: stack_free_count--; ! 208: } ! 209: stack_unlock(); ! 210: (void) splx(s); ! 211: ! 212: if (stack == 0) { ! 213: /* ! 214: * Kernel stacks should be naturally aligned, ! 215: * so that it is easy to find the starting/ending ! 216: * addresses of a stack given an address in the middle. ! 217: */ ! 218: ! 219: if (kmem_alloc_aligned(kernel_map, &stack, KERNEL_STACK_SIZE) ! 220: != KERN_SUCCESS) ! 221: panic("stack_alloc"); ! 222: ! 223: #if MACH_DEBUG ! 224: stack_init(stack); ! 225: #endif /* MACH_DEBUG */ ! 226: } ! 227: ! 228: stack_attach(thread, stack, resume); ! 229: } ! 230: ! 231: /* ! 232: * stack_free: ! 233: * ! 234: * Free a thread's kernel stack. ! 235: * Called at splsched with the thread locked. ! 236: */ ! 237: ! 238: void stack_free( ! 239: thread_t thread) ! 240: { ! 241: register vm_offset_t stack; ! 242: ! 243: stack = stack_detach(thread); ! 244: ! 245: if (stack != thread->stack_privilege) { ! 246: stack_lock(); ! 247: stack_next(stack) = stack_free_list; ! 248: stack_free_list = stack; ! 249: if (++stack_free_count > stack_alloc_max) ! 250: stack_alloc_max = stack_free_count; ! 251: stack_unlock(); ! 252: } ! 253: } ! 254: ! 255: /* ! 256: * stack_collect: ! 257: * ! 258: * Free excess kernel stacks. ! 259: * May block. ! 260: */ ! 261: ! 262: void stack_collect(void) ! 263: { ! 264: register vm_offset_t stack; ! 265: spl_t s; ! 266: ! 267: s = splsched(); ! 268: stack_lock(); ! 269: while (stack_free_count > stack_free_limit) { ! 270: stack = stack_free_list; ! 271: stack_free_list = stack_next(stack); ! 272: stack_free_count--; ! 273: stack_unlock(); ! 274: (void) splx(s); ! 275: ! 276: #if MACH_DEBUG ! 277: stack_finalize(stack); ! 278: #endif /* MACH_DEBUG */ ! 279: kmem_free(kernel_map, stack, KERNEL_STACK_SIZE); ! 280: ! 281: s = splsched(); ! 282: stack_lock(); ! 283: } ! 284: stack_unlock(); ! 285: (void) splx(s); ! 286: } ! 287: #endif /* MACHINE_STACK */ ! 288: ! 289: /* ! 290: * stack_privilege: ! 291: * ! 292: * stack_alloc_try on this thread must always succeed. ! 293: */ ! 294: ! 295: void stack_privilege( ! 296: register thread_t thread) ! 297: { ! 298: /* ! 299: * This implementation only works for the current thread. ! 300: */ ! 301: ! 302: if (thread != current_thread()) ! 303: panic("stack_privilege"); ! 304: ! 305: if (thread->stack_privilege == 0) ! 306: thread->stack_privilege = current_stack(); ! 307: } ! 308: ! 309: void thread_init(void) ! 310: { ! 311: thread_zone = zinit( ! 312: sizeof(struct thread), ! 313: THREAD_MAX * sizeof(struct thread), ! 314: THREAD_CHUNK * sizeof(struct thread), ! 315: 0, "threads"); ! 316: ! 317: /* ! 318: * Fill in a template thread for fast initialization. ! 319: * [Fields that must be (or are typically) reset at ! 320: * time of creation are so noted.] ! 321: */ ! 322: ! 323: /* thread_template.links (none) */ ! 324: thread_template.runq = RUN_QUEUE_NULL; ! 325: ! 326: /* thread_template.task (later) */ ! 327: /* thread_template.thread_list (later) */ ! 328: /* thread_template.pset_threads (later) */ ! 329: ! 330: /* thread_template.lock (later) */ ! 331: /* one ref for being alive; one for the guy who creates the thread */ ! 332: thread_template.ref_count = 2; ! 333: ! 334: thread_template.pcb = (pcb_t) 0; /* (reset) */ ! 335: thread_template.kernel_stack = (vm_offset_t) 0; ! 336: thread_template.stack_privilege = (vm_offset_t) 0; ! 337: ! 338: thread_template.wait_event = 0; ! 339: /* thread_template.suspend_count (later) */ ! 340: thread_template.wait_result = KERN_SUCCESS; ! 341: thread_template.wake_active = FALSE; ! 342: thread_template.state = TH_SUSP | TH_SWAPPED; ! 343: thread_template.swap_func = thread_bootstrap_return; ! 344: ! 345: /* thread_template.priority (later) */ ! 346: thread_template.max_priority = BASEPRI_USER; ! 347: /* thread_template.sched_pri (later - compute_priority) */ ! 348: #if MACH_FIXPRI ! 349: thread_template.sched_data = 0; ! 350: thread_template.policy = POLICY_TIMESHARE; ! 351: #endif /* MACH_FIXPRI */ ! 352: thread_template.depress_priority = -1; ! 353: thread_template.cpu_usage = 0; ! 354: thread_template.sched_usage = 0; ! 355: /* thread_template.sched_stamp (later) */ ! 356: ! 357: thread_template.recover = (vm_offset_t) 0; ! 358: thread_template.vm_privilege = FALSE; ! 359: ! 360: thread_template.user_stop_count = 1; ! 361: ! 362: /* thread_template.<IPC structures> (later) */ ! 363: ! 364: timer_init(&(thread_template.user_timer)); ! 365: timer_init(&(thread_template.system_timer)); ! 366: thread_template.user_timer_save.low = 0; ! 367: thread_template.user_timer_save.high = 0; ! 368: thread_template.system_timer_save.low = 0; ! 369: thread_template.system_timer_save.high = 0; ! 370: thread_template.cpu_delta = 0; ! 371: thread_template.sched_delta = 0; ! 372: ! 373: thread_template.active = FALSE; /* reset */ ! 374: thread_template.ast = AST_ZILCH; ! 375: ! 376: /* thread_template.processor_set (later) */ ! 377: thread_template.bound_processor = PROCESSOR_NULL; ! 378: #if MACH_HOST ! 379: thread_template.may_assign = TRUE; ! 380: thread_template.assign_active = FALSE; ! 381: #endif /* MACH_HOST */ ! 382: ! 383: #if NCPUS > 1 ! 384: /* thread_template.last_processor (later) */ ! 385: #endif /* NCPUS > 1 */ ! 386: ! 387: /* ! 388: * Initialize other data structures used in ! 389: * this module. ! 390: */ ! 391: ! 392: queue_init(&reaper_queue); ! 393: simple_lock_init(&reaper_lock); ! 394: ! 395: #ifndef MACHINE_STACK ! 396: simple_lock_init(&stack_lock_data); ! 397: #endif /* MACHINE_STACK */ ! 398: ! 399: #if MACH_DEBUG ! 400: simple_lock_init(&stack_usage_lock); ! 401: #endif /* MACH_DEBUG */ ! 402: ! 403: /* ! 404: * Initialize any machine-dependent ! 405: * per-thread structures necessary. ! 406: */ ! 407: ! 408: pcb_module_init(); ! 409: } ! 410: ! 411: kern_return_t thread_create( ! 412: register task_t parent_task, ! 413: thread_t *child_thread) /* OUT */ ! 414: { ! 415: register thread_t new_thread; ! 416: register processor_set_t pset; ! 417: ! 418: if (parent_task == TASK_NULL) ! 419: return KERN_INVALID_ARGUMENT; ! 420: ! 421: /* ! 422: * Allocate a thread and initialize static fields ! 423: */ ! 424: ! 425: new_thread = (thread_t) zalloc(thread_zone); ! 426: ! 427: if (new_thread == THREAD_NULL) ! 428: return KERN_RESOURCE_SHORTAGE; ! 429: ! 430: *new_thread = thread_template; ! 431: ! 432: /* ! 433: * Initialize runtime-dependent fields ! 434: */ ! 435: ! 436: new_thread->task = parent_task; ! 437: simple_lock_init(&new_thread->lock); ! 438: new_thread->sched_stamp = sched_tick; ! 439: thread_timeout_setup(new_thread); ! 440: ! 441: /* ! 442: * Create a pcb. The kernel stack is created later, ! 443: * when the thread is swapped-in. ! 444: */ ! 445: pcb_init(new_thread); ! 446: ! 447: ipc_thread_init(new_thread); ! 448: ! 449: #if NET_ATM ! 450: new_thread->nw_ep_waited = 0; ! 451: #endif ! 452: ! 453: /* ! 454: * Find the processor set for the parent task. ! 455: */ ! 456: task_lock(parent_task); ! 457: pset = parent_task->processor_set; ! 458: pset_reference(pset); ! 459: task_unlock(parent_task); ! 460: ! 461: /* ! 462: * Lock both the processor set and the task, ! 463: * so that the thread can be added to both ! 464: * simultaneously. Processor set must be ! 465: * locked first. ! 466: */ ! 467: ! 468: Restart: ! 469: pset_lock(pset); ! 470: task_lock(parent_task); ! 471: ! 472: /* ! 473: * If the task has changed processor sets, ! 474: * catch up (involves lots of lock juggling). ! 475: */ ! 476: { ! 477: processor_set_t cur_pset; ! 478: ! 479: cur_pset = parent_task->processor_set; ! 480: if (!cur_pset->active) ! 481: cur_pset = &default_pset; ! 482: ! 483: if (cur_pset != pset) { ! 484: pset_reference(cur_pset); ! 485: task_unlock(parent_task); ! 486: pset_unlock(pset); ! 487: pset_deallocate(pset); ! 488: pset = cur_pset; ! 489: goto Restart; ! 490: } ! 491: } ! 492: ! 493: /* ! 494: * Set the thread`s priority from the pset and task. ! 495: */ ! 496: ! 497: new_thread->priority = parent_task->priority; ! 498: if (pset->max_priority > new_thread->max_priority) ! 499: new_thread->max_priority = pset->max_priority; ! 500: if (new_thread->max_priority > new_thread->priority) ! 501: new_thread->priority = new_thread->max_priority; ! 502: /* ! 503: * Don't need to lock thread here because it can't ! 504: * possibly execute and no one else knows about it. ! 505: */ ! 506: compute_priority(new_thread, TRUE); ! 507: ! 508: /* ! 509: * Thread is suspended if the task is. Add 1 to ! 510: * suspend count since thread is created in suspended ! 511: * state. ! 512: */ ! 513: new_thread->suspend_count = parent_task->suspend_count + 1; ! 514: ! 515: /* ! 516: * Add the thread to the processor set. ! 517: * If the pset is empty, suspend the thread again. ! 518: */ ! 519: ! 520: pset_add_thread(pset, new_thread); ! 521: if (pset->empty) ! 522: new_thread->suspend_count++; ! 523: ! 524: #if HW_FOOTPRINT ! 525: /* ! 526: * Need to set last_processor, idle processor would be best, but ! 527: * that requires extra locking nonsense. Go for tail of ! 528: * processors queue to avoid master. ! 529: */ ! 530: if (!pset->empty) { ! 531: new_thread->last_processor = ! 532: (processor_t)queue_first(&pset->processors); ! 533: } ! 534: else { ! 535: /* ! 536: * Thread created in empty processor set. Pick ! 537: * master processor as an acceptable legal value. ! 538: */ ! 539: new_thread->last_processor = master_processor; ! 540: } ! 541: #else /* HW_FOOTPRINT */ ! 542: /* ! 543: * Don't need to initialize because the context switch ! 544: * code will set it before it can be used. ! 545: */ ! 546: #endif /* HW_FOOTPRINT */ ! 547: ! 548: #if MACH_PCSAMPLE ! 549: new_thread->pc_sample.buffer = 0; ! 550: new_thread->pc_sample.seqno = 0; ! 551: new_thread->pc_sample.sampletypes = 0; ! 552: #endif /* MACH_PCSAMPLE */ ! 553: ! 554: new_thread->pc_sample.buffer = 0; ! 555: /* ! 556: * Add the thread to the task`s list of threads. ! 557: * The new thread holds another reference to the task. ! 558: */ ! 559: ! 560: parent_task->ref_count++; ! 561: ! 562: parent_task->thread_count++; ! 563: queue_enter(&parent_task->thread_list, new_thread, thread_t, ! 564: thread_list); ! 565: ! 566: /* ! 567: * Finally, mark the thread active. ! 568: */ ! 569: ! 570: new_thread->active = TRUE; ! 571: ! 572: if (!parent_task->active) { ! 573: task_unlock(parent_task); ! 574: pset_unlock(pset); ! 575: (void) thread_terminate(new_thread); ! 576: /* release ref we would have given our caller */ ! 577: thread_deallocate(new_thread); ! 578: return KERN_FAILURE; ! 579: } ! 580: task_unlock(parent_task); ! 581: pset_unlock(pset); ! 582: ! 583: ipc_thread_enable(new_thread); ! 584: ! 585: *child_thread = new_thread; ! 586: return KERN_SUCCESS; ! 587: } ! 588: ! 589: unsigned int thread_deallocate_stack = 0; ! 590: ! 591: void thread_deallocate( ! 592: register thread_t thread) ! 593: { ! 594: spl_t s; ! 595: register task_t task; ! 596: register processor_set_t pset; ! 597: ! 598: time_value_t user_time, system_time; ! 599: ! 600: if (thread == THREAD_NULL) ! 601: return; ! 602: ! 603: /* ! 604: * First, check for new count > 0 (the common case). ! 605: * Only the thread needs to be locked. ! 606: */ ! 607: s = splsched(); ! 608: thread_lock(thread); ! 609: if (--thread->ref_count > 0) { ! 610: thread_unlock(thread); ! 611: (void) splx(s); ! 612: return; ! 613: } ! 614: ! 615: /* ! 616: * Count is zero. However, the task's and processor set's ! 617: * thread lists have implicit references to ! 618: * the thread, and may make new ones. Their locks also ! 619: * dominate the thread lock. To check for this, we ! 620: * temporarily restore the one thread reference, unlock ! 621: * the thread, and then lock the other structures in ! 622: * the proper order. ! 623: */ ! 624: thread->ref_count = 1; ! 625: thread_unlock(thread); ! 626: (void) splx(s); ! 627: ! 628: pset = thread->processor_set; ! 629: pset_lock(pset); ! 630: ! 631: #if MACH_HOST ! 632: /* ! 633: * The thread might have moved. ! 634: */ ! 635: while (pset != thread->processor_set) { ! 636: pset_unlock(pset); ! 637: pset = thread->processor_set; ! 638: pset_lock(pset); ! 639: } ! 640: #endif /* MACH_HOST */ ! 641: ! 642: task = thread->task; ! 643: task_lock(task); ! 644: ! 645: s = splsched(); ! 646: thread_lock(thread); ! 647: ! 648: if (--thread->ref_count > 0) { ! 649: /* ! 650: * Task or processor_set made extra reference. ! 651: */ ! 652: thread_unlock(thread); ! 653: (void) splx(s); ! 654: task_unlock(task); ! 655: pset_unlock(pset); ! 656: return; ! 657: } ! 658: ! 659: /* ! 660: * Thread has no references - we can remove it. ! 661: */ ! 662: ! 663: /* ! 664: * Remove pending timeouts. ! 665: */ ! 666: reset_timeout_check(&thread->timer); ! 667: ! 668: reset_timeout_check(&thread->depress_timer); ! 669: thread->depress_priority = -1; ! 670: ! 671: /* ! 672: * Accumulate times for dead threads in task. ! 673: */ ! 674: thread_read_times(thread, &user_time, &system_time); ! 675: time_value_add(&task->total_user_time, &user_time); ! 676: time_value_add(&task->total_system_time, &system_time); ! 677: ! 678: /* ! 679: * Remove thread from task list and processor_set threads list. ! 680: */ ! 681: task->thread_count--; ! 682: queue_remove(&task->thread_list, thread, thread_t, thread_list); ! 683: ! 684: pset_remove_thread(pset, thread); ! 685: ! 686: thread_unlock(thread); /* no more references - safe */ ! 687: (void) splx(s); ! 688: task_unlock(task); ! 689: pset_unlock(pset); ! 690: pset_deallocate(pset); ! 691: ! 692: /* ! 693: * A couple of quick sanity checks ! 694: */ ! 695: ! 696: if (thread == current_thread()) { ! 697: panic("thread deallocating itself"); ! 698: } ! 699: if ((thread->state & ~(TH_RUN | TH_HALTED | TH_SWAPPED)) != TH_SUSP) ! 700: panic("unstopped thread destroyed!"); ! 701: ! 702: /* ! 703: * Deallocate the task reference, since we know the thread ! 704: * is not running. ! 705: */ ! 706: task_deallocate(thread->task); /* may block */ ! 707: ! 708: /* ! 709: * Clean up any machine-dependent resources. ! 710: */ ! 711: if ((thread->state & TH_SWAPPED) == 0) { ! 712: spl_t _s_ = splsched(); ! 713: stack_free(thread); ! 714: (void) splx(s); ! 715: thread_deallocate_stack++; ! 716: } ! 717: /* ! 718: * Rattle the event count machinery (gag) ! 719: */ ! 720: evc_notify_abort(thread); ! 721: ! 722: pcb_terminate(thread); ! 723: zfree(thread_zone, (vm_offset_t) thread); ! 724: } ! 725: ! 726: void thread_reference( ! 727: register thread_t thread) ! 728: { ! 729: spl_t s; ! 730: ! 731: if (thread == THREAD_NULL) ! 732: return; ! 733: ! 734: s = splsched(); ! 735: thread_lock(thread); ! 736: thread->ref_count++; ! 737: thread_unlock(thread); ! 738: (void) splx(s); ! 739: } ! 740: ! 741: /* ! 742: * thread_terminate: ! 743: * ! 744: * Permanently stop execution of the specified thread. ! 745: * ! 746: * A thread to be terminated must be allowed to clean up any state ! 747: * that it has before it exits. The thread is broken out of any ! 748: * wait condition that it is in, and signalled to exit. It then ! 749: * cleans up its state and calls thread_halt_self on its way out of ! 750: * the kernel. The caller waits for the thread to halt, terminates ! 751: * its IPC state, and then deallocates it. ! 752: * ! 753: * If the caller is the current thread, it must still exit the kernel ! 754: * to clean up any state (thread and port references, messages, etc). ! 755: * When it exits the kernel, it then terminates its IPC state and ! 756: * queues itself for the reaper thread, which will wait for the thread ! 757: * to stop and then deallocate it. (A thread cannot deallocate itself, ! 758: * since it needs a kernel stack to execute.) ! 759: */ ! 760: kern_return_t thread_terminate( ! 761: register thread_t thread) ! 762: { ! 763: register thread_t cur_thread = current_thread(); ! 764: register task_t cur_task; ! 765: spl_t s; ! 766: ! 767: if (thread == THREAD_NULL) ! 768: return KERN_INVALID_ARGUMENT; ! 769: ! 770: /* ! 771: * Break IPC control over the thread. ! 772: */ ! 773: ipc_thread_disable(thread); ! 774: ! 775: if (thread == cur_thread) { ! 776: ! 777: /* ! 778: * Current thread will queue itself for reaper when ! 779: * exiting kernel. ! 780: */ ! 781: s = splsched(); ! 782: thread_lock(thread); ! 783: if (thread->active) { ! 784: thread->active = FALSE; ! 785: thread_ast_set(thread, AST_TERMINATE); ! 786: } ! 787: thread_unlock(thread); ! 788: ast_on(cpu_number(), AST_TERMINATE); ! 789: splx(s); ! 790: return KERN_SUCCESS; ! 791: } ! 792: ! 793: /* ! 794: * Lock both threads and the current task ! 795: * to check termination races and prevent deadlocks. ! 796: */ ! 797: cur_task = current_task(); ! 798: task_lock(cur_task); ! 799: s = splsched(); ! 800: if ((vm_offset_t)thread < (vm_offset_t)cur_thread) { ! 801: thread_lock(thread); ! 802: thread_lock(cur_thread); ! 803: } ! 804: else { ! 805: thread_lock(cur_thread); ! 806: thread_lock(thread); ! 807: } ! 808: ! 809: /* ! 810: * If the current thread is being terminated, help out. ! 811: */ ! 812: if ((!cur_task->active) || (!cur_thread->active)) { ! 813: thread_unlock(cur_thread); ! 814: thread_unlock(thread); ! 815: (void) splx(s); ! 816: task_unlock(cur_task); ! 817: thread_terminate(cur_thread); ! 818: return KERN_FAILURE; ! 819: } ! 820: ! 821: thread_unlock(cur_thread); ! 822: task_unlock(cur_task); ! 823: ! 824: /* ! 825: * Terminate victim thread. ! 826: */ ! 827: if (!thread->active) { ! 828: /* ! 829: * Someone else got there first. ! 830: */ ! 831: thread_unlock(thread); ! 832: (void) splx(s); ! 833: return KERN_FAILURE; ! 834: } ! 835: ! 836: thread->active = FALSE; ! 837: ! 838: thread_unlock(thread); ! 839: (void) splx(s); ! 840: ! 841: #if MACH_HOST ! 842: /* ! 843: * Reassign thread to default pset if needed. ! 844: */ ! 845: thread_freeze(thread); ! 846: if (thread->processor_set != &default_pset) { ! 847: thread_doassign(thread, &default_pset, FALSE); ! 848: } ! 849: #endif /* MACH_HOST */ ! 850: ! 851: /* ! 852: * Halt the victim at the clean point. ! 853: */ ! 854: (void) thread_halt(thread, TRUE); ! 855: #if MACH_HOST ! 856: thread_unfreeze(thread); ! 857: #endif /* MACH_HOST */ ! 858: /* ! 859: * Shut down the victims IPC and deallocate its ! 860: * reference to itself. ! 861: */ ! 862: ipc_thread_terminate(thread); ! 863: #if NET_ATM ! 864: mk_waited_collect(thread); ! 865: #endif ! 866: thread_deallocate(thread); ! 867: return KERN_SUCCESS; ! 868: } ! 869: ! 870: /* ! 871: * thread_force_terminate: ! 872: * ! 873: * Version of thread_terminate called by task_terminate. thread is ! 874: * not the current thread. task_terminate is the dominant operation, ! 875: * so we can force this thread to stop. ! 876: */ ! 877: void ! 878: thread_force_terminate( ! 879: register thread_t thread) ! 880: { ! 881: boolean_t deallocate_here = FALSE; ! 882: spl_t s; ! 883: ! 884: ipc_thread_disable(thread); ! 885: ! 886: #if MACH_HOST ! 887: /* ! 888: * Reassign thread to default pset if needed. ! 889: */ ! 890: thread_freeze(thread); ! 891: if (thread->processor_set != &default_pset) ! 892: thread_doassign(thread, &default_pset, FALSE); ! 893: #endif /* MACH_HOST */ ! 894: ! 895: s = splsched(); ! 896: thread_lock(thread); ! 897: deallocate_here = thread->active; ! 898: thread->active = FALSE; ! 899: thread_unlock(thread); ! 900: (void) splx(s); ! 901: ! 902: (void) thread_halt(thread, TRUE); ! 903: ipc_thread_terminate(thread); ! 904: #if NET_ATM ! 905: mk_waited_collect(thread); ! 906: #endif ! 907: ! 908: #if MACH_HOST ! 909: thread_unfreeze(thread); ! 910: #endif /* MACH_HOST */ ! 911: ! 912: if (deallocate_here) ! 913: thread_deallocate(thread); ! 914: } ! 915: ! 916: ! 917: /* ! 918: * Halt a thread at a clean point, leaving it suspended. ! 919: * ! 920: * must_halt indicates whether thread must halt. ! 921: * ! 922: */ ! 923: kern_return_t thread_halt( ! 924: register thread_t thread, ! 925: boolean_t must_halt) ! 926: { ! 927: register thread_t cur_thread = current_thread(); ! 928: register kern_return_t ret; ! 929: spl_t s; ! 930: ! 931: if (thread == cur_thread) ! 932: panic("thread_halt: trying to halt current thread."); ! 933: /* ! 934: * If must_halt is FALSE, then a check must be made for ! 935: * a cycle of halt operations. ! 936: */ ! 937: if (!must_halt) { ! 938: /* ! 939: * Grab both thread locks. ! 940: */ ! 941: s = splsched(); ! 942: if ((vm_offset_t)thread < (vm_offset_t)cur_thread) { ! 943: thread_lock(thread); ! 944: thread_lock(cur_thread); ! 945: } ! 946: else { ! 947: thread_lock(cur_thread); ! 948: thread_lock(thread); ! 949: } ! 950: ! 951: /* ! 952: * If target thread is already halted, grab a hold ! 953: * on it and return. ! 954: */ ! 955: if (thread->state & TH_HALTED) { ! 956: thread->suspend_count++; ! 957: thread_unlock(cur_thread); ! 958: thread_unlock(thread); ! 959: (void) splx(s); ! 960: return KERN_SUCCESS; ! 961: } ! 962: ! 963: /* ! 964: * If someone is trying to halt us, we have a potential ! 965: * halt cycle. Break the cycle by interrupting anyone ! 966: * who is trying to halt us, and causing this operation ! 967: * to fail; retry logic will only retry operations ! 968: * that cannot deadlock. (If must_halt is TRUE, this ! 969: * operation can never cause a deadlock.) ! 970: */ ! 971: if (cur_thread->ast & AST_HALT) { ! 972: thread_wakeup_with_result((event_t)&cur_thread->wake_active, ! 973: THREAD_INTERRUPTED); ! 974: thread_unlock(thread); ! 975: thread_unlock(cur_thread); ! 976: (void) splx(s); ! 977: return KERN_FAILURE; ! 978: } ! 979: ! 980: thread_unlock(cur_thread); ! 981: ! 982: } ! 983: else { ! 984: /* ! 985: * Lock thread and check whether it is already halted. ! 986: */ ! 987: s = splsched(); ! 988: thread_lock(thread); ! 989: if (thread->state & TH_HALTED) { ! 990: thread->suspend_count++; ! 991: thread_unlock(thread); ! 992: (void) splx(s); ! 993: return KERN_SUCCESS; ! 994: } ! 995: } ! 996: ! 997: /* ! 998: * Suspend thread - inline version of thread_hold() because ! 999: * thread is already locked. ! 1000: */ ! 1001: thread->suspend_count++; ! 1002: thread->state |= TH_SUSP; ! 1003: ! 1004: /* ! 1005: * If someone else is halting it, wait for that to complete. ! 1006: * Fail if wait interrupted and must_halt is false. ! 1007: */ ! 1008: while ((thread->ast & AST_HALT) && (!(thread->state & TH_HALTED))) { ! 1009: thread->wake_active = TRUE; ! 1010: thread_sleep((event_t) &thread->wake_active, ! 1011: simple_lock_addr(thread->lock), TRUE); ! 1012: ! 1013: if (thread->state & TH_HALTED) { ! 1014: (void) splx(s); ! 1015: return KERN_SUCCESS; ! 1016: } ! 1017: if ((current_thread()->wait_result != THREAD_AWAKENED) ! 1018: && !(must_halt)) { ! 1019: (void) splx(s); ! 1020: thread_release(thread); ! 1021: return KERN_FAILURE; ! 1022: } ! 1023: thread_lock(thread); ! 1024: } ! 1025: ! 1026: /* ! 1027: * Otherwise, have to do it ourselves. ! 1028: */ ! 1029: ! 1030: thread_ast_set(thread, AST_HALT); ! 1031: ! 1032: while (TRUE) { ! 1033: /* ! 1034: * Wait for thread to stop. ! 1035: */ ! 1036: thread_unlock(thread); ! 1037: (void) splx(s); ! 1038: ! 1039: ret = thread_dowait(thread, must_halt); ! 1040: ! 1041: /* ! 1042: * If the dowait failed, so do we. Drop AST_HALT, and ! 1043: * wake up anyone else who might be waiting for it. ! 1044: */ ! 1045: if (ret != KERN_SUCCESS) { ! 1046: s = splsched(); ! 1047: thread_lock(thread); ! 1048: thread_ast_clear(thread, AST_HALT); ! 1049: thread_wakeup_with_result((event_t)&thread->wake_active, ! 1050: THREAD_INTERRUPTED); ! 1051: thread_unlock(thread); ! 1052: (void) splx(s); ! 1053: ! 1054: thread_release(thread); ! 1055: return ret; ! 1056: } ! 1057: ! 1058: /* ! 1059: * Clear any interruptible wait. ! 1060: */ ! 1061: clear_wait(thread, THREAD_INTERRUPTED, TRUE); ! 1062: ! 1063: /* ! 1064: * If the thread's at a clean point, we're done. ! 1065: * Don't need a lock because it really is stopped. ! 1066: */ ! 1067: if (thread->state & TH_HALTED) { ! 1068: return KERN_SUCCESS; ! 1069: } ! 1070: ! 1071: /* ! 1072: * If the thread is at a nice continuation, ! 1073: * or a continuation with a cleanup routine, ! 1074: * call the cleanup routine. ! 1075: */ ! 1076: if ((((thread->swap_func == mach_msg_continue) || ! 1077: (thread->swap_func == mach_msg_receive_continue)) && ! 1078: mach_msg_interrupt(thread)) || ! 1079: (thread->swap_func == thread_exception_return) || ! 1080: (thread->swap_func == thread_bootstrap_return)) { ! 1081: s = splsched(); ! 1082: thread_lock(thread); ! 1083: thread->state |= TH_HALTED; ! 1084: thread_ast_clear(thread, AST_HALT); ! 1085: thread_unlock(thread); ! 1086: splx(s); ! 1087: ! 1088: return KERN_SUCCESS; ! 1089: } ! 1090: ! 1091: /* ! 1092: * Force the thread to stop at a clean ! 1093: * point, and arrange to wait for it. ! 1094: * ! 1095: * Set it running, so it can notice. Override ! 1096: * the suspend count. We know that the thread ! 1097: * is suspended and not waiting. ! 1098: * ! 1099: * Since the thread may hit an interruptible wait ! 1100: * before it reaches a clean point, we must force it ! 1101: * to wake us up when it does so. This involves some ! 1102: * trickery: ! 1103: * We mark the thread SUSPENDED so that thread_block ! 1104: * will suspend it and wake us up. ! 1105: * We mark the thread RUNNING so that it will run. ! 1106: * We mark the thread UN-INTERRUPTIBLE (!) so that ! 1107: * some other thread trying to halt or suspend it won't ! 1108: * take it off the run queue before it runs. Since ! 1109: * dispatching a thread (the tail of thread_invoke) marks ! 1110: * the thread interruptible, it will stop at the next ! 1111: * context switch or interruptible wait. ! 1112: */ ! 1113: ! 1114: s = splsched(); ! 1115: thread_lock(thread); ! 1116: if ((thread->state & TH_SCHED_STATE) != TH_SUSP) ! 1117: panic("thread_halt"); ! 1118: thread->state |= TH_RUN | TH_UNINT; ! 1119: thread_setrun(thread, FALSE); ! 1120: ! 1121: /* ! 1122: * Continue loop and wait for thread to stop. ! 1123: */ ! 1124: } ! 1125: } ! 1126: ! 1127: void walking_zombie(void) ! 1128: { ! 1129: panic("the zombie walks!"); ! 1130: } ! 1131: ! 1132: /* ! 1133: * Thread calls this routine on exit from the kernel when it ! 1134: * notices a halt request. ! 1135: */ ! 1136: void thread_halt_self(void) ! 1137: { ! 1138: register thread_t thread = current_thread(); ! 1139: spl_t s; ! 1140: ! 1141: if (thread->ast & AST_TERMINATE) { ! 1142: /* ! 1143: * Thread is terminating itself. Shut ! 1144: * down IPC, then queue it up for the ! 1145: * reaper thread. ! 1146: */ ! 1147: ipc_thread_terminate(thread); ! 1148: #if NET_ATM ! 1149: mk_waited_collect(thread); ! 1150: #endif ! 1151: ! 1152: thread_hold(thread); ! 1153: ! 1154: s = splsched(); ! 1155: simple_lock(&reaper_lock); ! 1156: enqueue_tail(&reaper_queue, (queue_entry_t) thread); ! 1157: simple_unlock(&reaper_lock); ! 1158: ! 1159: thread_lock(thread); ! 1160: thread->state |= TH_HALTED; ! 1161: thread_unlock(thread); ! 1162: (void) splx(s); ! 1163: ! 1164: thread_wakeup((event_t)&reaper_queue); ! 1165: counter(c_thread_halt_self_block++); ! 1166: thread_block(walking_zombie); ! 1167: /*NOTREACHED*/ ! 1168: } else { ! 1169: /* ! 1170: * Thread was asked to halt - show that it ! 1171: * has done so. ! 1172: */ ! 1173: s = splsched(); ! 1174: thread_lock(thread); ! 1175: thread->state |= TH_HALTED; ! 1176: thread_ast_clear(thread, AST_HALT); ! 1177: thread_unlock(thread); ! 1178: splx(s); ! 1179: counter(c_thread_halt_self_block++); ! 1180: thread_block(thread_exception_return); ! 1181: /* ! 1182: * thread_release resets TH_HALTED. ! 1183: */ ! 1184: } ! 1185: } ! 1186: ! 1187: /* ! 1188: * thread_hold: ! 1189: * ! 1190: * Suspend execution of the specified thread. ! 1191: * This is a recursive-style suspension of the thread, a count of ! 1192: * suspends is maintained. ! 1193: */ ! 1194: void thread_hold( ! 1195: register thread_t thread) ! 1196: { ! 1197: spl_t s; ! 1198: ! 1199: s = splsched(); ! 1200: thread_lock(thread); ! 1201: thread->suspend_count++; ! 1202: thread->state |= TH_SUSP; ! 1203: thread_unlock(thread); ! 1204: (void) splx(s); ! 1205: } ! 1206: ! 1207: /* ! 1208: * thread_dowait: ! 1209: * ! 1210: * Wait for a thread to actually enter stopped state. ! 1211: * ! 1212: * must_halt argument indicates if this may fail on interruption. ! 1213: * This is FALSE only if called from thread_abort via thread_halt. ! 1214: */ ! 1215: kern_return_t ! 1216: thread_dowait( ! 1217: register thread_t thread, ! 1218: boolean_t must_halt) ! 1219: { ! 1220: register boolean_t need_wakeup; ! 1221: register kern_return_t ret = KERN_SUCCESS; ! 1222: spl_t s; ! 1223: ! 1224: if (thread == current_thread()) ! 1225: panic("thread_dowait"); ! 1226: ! 1227: /* ! 1228: * If a thread is not interruptible, it may not be suspended ! 1229: * until it becomes interruptible. In this case, we wait for ! 1230: * the thread to stop itself, and indicate that we are waiting ! 1231: * for it to stop so that it can wake us up when it does stop. ! 1232: * ! 1233: * If the thread is interruptible, we may be able to suspend ! 1234: * it immediately. There are several cases: ! 1235: * ! 1236: * 1) The thread is already stopped (trivial) ! 1237: * 2) The thread is runnable (marked RUN and on a run queue). ! 1238: * We pull it off the run queue and mark it stopped. ! 1239: * 3) The thread is running. We wait for it to stop. ! 1240: */ ! 1241: ! 1242: need_wakeup = FALSE; ! 1243: s = splsched(); ! 1244: thread_lock(thread); ! 1245: ! 1246: for (;;) { ! 1247: switch (thread->state & TH_SCHED_STATE) { ! 1248: case TH_SUSP: ! 1249: case TH_WAIT | TH_SUSP: ! 1250: /* ! 1251: * Thread is already suspended, or sleeping in an ! 1252: * interruptible wait. We win! ! 1253: */ ! 1254: break; ! 1255: ! 1256: case TH_RUN | TH_SUSP: ! 1257: /* ! 1258: * The thread is interruptible. If we can pull ! 1259: * it off a runq, stop it here. ! 1260: */ ! 1261: if (rem_runq(thread) != RUN_QUEUE_NULL) { ! 1262: thread->state &= ~TH_RUN; ! 1263: need_wakeup = thread->wake_active; ! 1264: thread->wake_active = FALSE; ! 1265: break; ! 1266: } ! 1267: #if NCPUS > 1 ! 1268: /* ! 1269: * The thread must be running, so make its ! 1270: * processor execute ast_check(). This ! 1271: * should cause the thread to take an ast and ! 1272: * context switch to suspend for us. ! 1273: */ ! 1274: cause_ast_check(thread->last_processor); ! 1275: #endif /* NCPUS > 1 */ ! 1276: ! 1277: /* ! 1278: * Fall through to wait for thread to stop. ! 1279: */ ! 1280: ! 1281: case TH_RUN | TH_SUSP | TH_UNINT: ! 1282: case TH_RUN | TH_WAIT | TH_SUSP: ! 1283: case TH_RUN | TH_WAIT | TH_SUSP | TH_UNINT: ! 1284: case TH_WAIT | TH_SUSP | TH_UNINT: ! 1285: /* ! 1286: * Wait for the thread to stop, or sleep interruptibly ! 1287: * (thread_block will stop it in the latter case). ! 1288: * Check for failure if interrupted. ! 1289: */ ! 1290: thread->wake_active = TRUE; ! 1291: thread_sleep((event_t) &thread->wake_active, ! 1292: simple_lock_addr(thread->lock), TRUE); ! 1293: thread_lock(thread); ! 1294: if ((current_thread()->wait_result != THREAD_AWAKENED) && ! 1295: !must_halt) { ! 1296: ret = KERN_FAILURE; ! 1297: break; ! 1298: } ! 1299: ! 1300: /* ! 1301: * Repeat loop to check thread`s state. ! 1302: */ ! 1303: continue; ! 1304: } ! 1305: /* ! 1306: * Thread is stopped at this point. ! 1307: */ ! 1308: break; ! 1309: } ! 1310: ! 1311: thread_unlock(thread); ! 1312: (void) splx(s); ! 1313: ! 1314: if (need_wakeup) ! 1315: thread_wakeup((event_t) &thread->wake_active); ! 1316: ! 1317: return ret; ! 1318: } ! 1319: ! 1320: void thread_release( ! 1321: register thread_t thread) ! 1322: { ! 1323: spl_t s; ! 1324: ! 1325: s = splsched(); ! 1326: thread_lock(thread); ! 1327: if (--thread->suspend_count == 0) { ! 1328: thread->state &= ~(TH_SUSP | TH_HALTED); ! 1329: if ((thread->state & (TH_WAIT | TH_RUN)) == 0) { ! 1330: /* was only suspended */ ! 1331: thread->state |= TH_RUN; ! 1332: thread_setrun(thread, TRUE); ! 1333: } ! 1334: } ! 1335: thread_unlock(thread); ! 1336: (void) splx(s); ! 1337: } ! 1338: ! 1339: kern_return_t thread_suspend( ! 1340: register thread_t thread) ! 1341: { ! 1342: register boolean_t hold; ! 1343: spl_t spl; ! 1344: ! 1345: if (thread == THREAD_NULL) ! 1346: return KERN_INVALID_ARGUMENT; ! 1347: ! 1348: hold = FALSE; ! 1349: spl = splsched(); ! 1350: thread_lock(thread); ! 1351: if (thread->user_stop_count++ == 0) { ! 1352: hold = TRUE; ! 1353: thread->suspend_count++; ! 1354: thread->state |= TH_SUSP; ! 1355: } ! 1356: thread_unlock(thread); ! 1357: (void) splx(spl); ! 1358: ! 1359: /* ! 1360: * Now wait for the thread if necessary. ! 1361: */ ! 1362: if (hold) { ! 1363: if (thread == current_thread()) { ! 1364: /* ! 1365: * We want to call thread_block on our way out, ! 1366: * to stop running. ! 1367: */ ! 1368: spl = splsched(); ! 1369: ast_on(cpu_number(), AST_BLOCK); ! 1370: (void) splx(spl); ! 1371: } else ! 1372: (void) thread_dowait(thread, TRUE); ! 1373: } ! 1374: return KERN_SUCCESS; ! 1375: } ! 1376: ! 1377: ! 1378: kern_return_t thread_resume( ! 1379: register thread_t thread) ! 1380: { ! 1381: register kern_return_t ret; ! 1382: spl_t s; ! 1383: ! 1384: if (thread == THREAD_NULL) ! 1385: return KERN_INVALID_ARGUMENT; ! 1386: ! 1387: ret = KERN_SUCCESS; ! 1388: ! 1389: s = splsched(); ! 1390: thread_lock(thread); ! 1391: if (thread->user_stop_count > 0) { ! 1392: if (--thread->user_stop_count == 0) { ! 1393: if (--thread->suspend_count == 0) { ! 1394: thread->state &= ~(TH_SUSP | TH_HALTED); ! 1395: if ((thread->state & (TH_WAIT | TH_RUN)) == 0) { ! 1396: /* was only suspended */ ! 1397: thread->state |= TH_RUN; ! 1398: thread_setrun(thread, TRUE); ! 1399: } ! 1400: } ! 1401: } ! 1402: } ! 1403: else { ! 1404: ret = KERN_FAILURE; ! 1405: } ! 1406: ! 1407: thread_unlock(thread); ! 1408: (void) splx(s); ! 1409: ! 1410: return ret; ! 1411: } ! 1412: ! 1413: /* ! 1414: * Return thread's machine-dependent state. ! 1415: */ ! 1416: kern_return_t thread_get_state( ! 1417: register thread_t thread, ! 1418: int flavor, ! 1419: thread_state_t old_state, /* pointer to OUT array */ ! 1420: natural_t *old_state_count) /*IN/OUT*/ ! 1421: { ! 1422: kern_return_t ret; ! 1423: ! 1424: if (thread == THREAD_NULL || thread == current_thread()) { ! 1425: return KERN_INVALID_ARGUMENT; ! 1426: } ! 1427: ! 1428: thread_hold(thread); ! 1429: (void) thread_dowait(thread, TRUE); ! 1430: ! 1431: ret = thread_getstatus(thread, flavor, old_state, old_state_count); ! 1432: ! 1433: thread_release(thread); ! 1434: return ret; ! 1435: } ! 1436: ! 1437: /* ! 1438: * Change thread's machine-dependent state. ! 1439: */ ! 1440: kern_return_t thread_set_state( ! 1441: register thread_t thread, ! 1442: int flavor, ! 1443: thread_state_t new_state, ! 1444: natural_t new_state_count) ! 1445: { ! 1446: kern_return_t ret; ! 1447: ! 1448: if (thread == THREAD_NULL || thread == current_thread()) { ! 1449: return KERN_INVALID_ARGUMENT; ! 1450: } ! 1451: ! 1452: thread_hold(thread); ! 1453: (void) thread_dowait(thread, TRUE); ! 1454: ! 1455: ret = thread_setstatus(thread, flavor, new_state, new_state_count); ! 1456: ! 1457: thread_release(thread); ! 1458: return ret; ! 1459: } ! 1460: ! 1461: kern_return_t thread_info( ! 1462: register thread_t thread, ! 1463: int flavor, ! 1464: thread_info_t thread_info_out, /* pointer to OUT array */ ! 1465: natural_t *thread_info_count) /*IN/OUT*/ ! 1466: { ! 1467: int state, flags; ! 1468: spl_t s; ! 1469: ! 1470: if (thread == THREAD_NULL) ! 1471: return KERN_INVALID_ARGUMENT; ! 1472: ! 1473: if (flavor == THREAD_BASIC_INFO) { ! 1474: register thread_basic_info_t basic_info; ! 1475: ! 1476: if (*thread_info_count < THREAD_BASIC_INFO_COUNT) { ! 1477: return KERN_INVALID_ARGUMENT; ! 1478: } ! 1479: ! 1480: basic_info = (thread_basic_info_t) thread_info_out; ! 1481: ! 1482: s = splsched(); ! 1483: thread_lock(thread); ! 1484: ! 1485: /* ! 1486: * Update lazy-evaluated scheduler info because someone wants it. ! 1487: */ ! 1488: if ((thread->state & TH_RUN) == 0 && ! 1489: thread->sched_stamp != sched_tick) ! 1490: update_priority(thread); ! 1491: ! 1492: /* fill in info */ ! 1493: ! 1494: thread_read_times(thread, ! 1495: &basic_info->user_time, ! 1496: &basic_info->system_time); ! 1497: basic_info->base_priority = thread->priority; ! 1498: basic_info->cur_priority = thread->sched_pri; ! 1499: ! 1500: /* ! 1501: * To calculate cpu_usage, first correct for timer rate, ! 1502: * then for 5/8 ageing. The correction factor [3/5] is ! 1503: * (1/(5/8) - 1). ! 1504: */ ! 1505: basic_info->cpu_usage = thread->cpu_usage / ! 1506: (TIMER_RATE/TH_USAGE_SCALE); ! 1507: basic_info->cpu_usage = (basic_info->cpu_usage * 3) / 5; ! 1508: #if SIMPLE_CLOCK ! 1509: /* ! 1510: * Clock drift compensation. ! 1511: */ ! 1512: basic_info->cpu_usage = ! 1513: (basic_info->cpu_usage * 1000000)/sched_usec; ! 1514: #endif /* SIMPLE_CLOCK */ ! 1515: ! 1516: if (thread->state & TH_SWAPPED) ! 1517: flags = TH_FLAGS_SWAPPED; ! 1518: else if (thread->state & TH_IDLE) ! 1519: flags = TH_FLAGS_IDLE; ! 1520: else ! 1521: flags = 0; ! 1522: ! 1523: if (thread->state & TH_HALTED) ! 1524: state = TH_STATE_HALTED; ! 1525: else ! 1526: if (thread->state & TH_RUN) ! 1527: state = TH_STATE_RUNNING; ! 1528: else ! 1529: if (thread->state & TH_UNINT) ! 1530: state = TH_STATE_UNINTERRUPTIBLE; ! 1531: else ! 1532: if (thread->state & TH_SUSP) ! 1533: state = TH_STATE_STOPPED; ! 1534: else ! 1535: if (thread->state & TH_WAIT) ! 1536: state = TH_STATE_WAITING; ! 1537: else ! 1538: state = 0; /* ? */ ! 1539: ! 1540: basic_info->run_state = state; ! 1541: basic_info->flags = flags; ! 1542: basic_info->suspend_count = thread->user_stop_count; ! 1543: if (state == TH_STATE_RUNNING) ! 1544: basic_info->sleep_time = 0; ! 1545: else ! 1546: basic_info->sleep_time = sched_tick - thread->sched_stamp; ! 1547: ! 1548: thread_unlock(thread); ! 1549: splx(s); ! 1550: ! 1551: *thread_info_count = THREAD_BASIC_INFO_COUNT; ! 1552: return KERN_SUCCESS; ! 1553: } ! 1554: else if (flavor == THREAD_SCHED_INFO) { ! 1555: register thread_sched_info_t sched_info; ! 1556: ! 1557: if (*thread_info_count < THREAD_SCHED_INFO_COUNT) { ! 1558: return KERN_INVALID_ARGUMENT; ! 1559: } ! 1560: ! 1561: sched_info = (thread_sched_info_t) thread_info_out; ! 1562: ! 1563: s = splsched(); ! 1564: thread_lock(thread); ! 1565: ! 1566: #if MACH_FIXPRI ! 1567: sched_info->policy = thread->policy; ! 1568: if (thread->policy == POLICY_FIXEDPRI) { ! 1569: sched_info->data = (thread->sched_data * tick)/1000; ! 1570: } ! 1571: else { ! 1572: sched_info->data = 0; ! 1573: } ! 1574: #else /* MACH_FIXPRI */ ! 1575: sched_info->policy = POLICY_TIMESHARE; ! 1576: sched_info->data = 0; ! 1577: #endif /* MACH_FIXPRI */ ! 1578: ! 1579: sched_info->base_priority = thread->priority; ! 1580: sched_info->max_priority = thread->max_priority; ! 1581: sched_info->cur_priority = thread->sched_pri; ! 1582: ! 1583: sched_info->depressed = (thread->depress_priority >= 0); ! 1584: sched_info->depress_priority = thread->depress_priority; ! 1585: ! 1586: thread_unlock(thread); ! 1587: splx(s); ! 1588: ! 1589: *thread_info_count = THREAD_SCHED_INFO_COUNT; ! 1590: return KERN_SUCCESS; ! 1591: } ! 1592: ! 1593: return KERN_INVALID_ARGUMENT; ! 1594: } ! 1595: ! 1596: kern_return_t thread_abort( ! 1597: register thread_t thread) ! 1598: { ! 1599: if (thread == THREAD_NULL || thread == current_thread()) { ! 1600: return KERN_INVALID_ARGUMENT; ! 1601: } ! 1602: ! 1603: /* ! 1604: * ! 1605: * clear it of an event wait ! 1606: */ ! 1607: evc_notify_abort(thread); ! 1608: ! 1609: /* ! 1610: * Try to force the thread to a clean point ! 1611: * If the halt operation fails return KERN_ABORTED. ! 1612: * ipc code will convert this to an ipc interrupted error code. ! 1613: */ ! 1614: if (thread_halt(thread, FALSE) != KERN_SUCCESS) ! 1615: return KERN_ABORTED; ! 1616: ! 1617: /* ! 1618: * If the thread was in an exception, abort that too. ! 1619: */ ! 1620: mach_msg_abort_rpc(thread); ! 1621: ! 1622: /* ! 1623: * Then set it going again. ! 1624: */ ! 1625: thread_release(thread); ! 1626: ! 1627: /* ! 1628: * Also abort any depression. ! 1629: */ ! 1630: if (thread->depress_priority != -1) ! 1631: thread_depress_abort(thread); ! 1632: ! 1633: return KERN_SUCCESS; ! 1634: } ! 1635: ! 1636: /* ! 1637: * thread_start: ! 1638: * ! 1639: * Start a thread at the specified routine. ! 1640: * The thread must be in a swapped state. ! 1641: */ ! 1642: ! 1643: void ! 1644: thread_start( ! 1645: thread_t thread, ! 1646: continuation_t start) ! 1647: { ! 1648: thread->swap_func = start; ! 1649: } ! 1650: ! 1651: /* ! 1652: * kernel_thread: ! 1653: * ! 1654: * Start up a kernel thread in the specified task. ! 1655: */ ! 1656: ! 1657: thread_t kernel_thread( ! 1658: task_t task, ! 1659: continuation_t start, ! 1660: void * arg) ! 1661: { ! 1662: thread_t thread; ! 1663: ! 1664: (void) thread_create(task, &thread); ! 1665: /* release "extra" ref that thread_create gave us */ ! 1666: thread_deallocate(thread); ! 1667: thread_start(thread, start); ! 1668: thread->ith_other = arg; ! 1669: ! 1670: /* ! 1671: * We ensure that the kernel thread starts with a stack. ! 1672: * The swapin mechanism might not be operational yet. ! 1673: */ ! 1674: thread_doswapin(thread); ! 1675: thread->max_priority = BASEPRI_SYSTEM; ! 1676: thread->priority = BASEPRI_SYSTEM; ! 1677: thread->sched_pri = BASEPRI_SYSTEM; ! 1678: (void) thread_resume(thread); ! 1679: return thread; ! 1680: } ! 1681: ! 1682: /* ! 1683: * reaper_thread: ! 1684: * ! 1685: * This kernel thread runs forever looking for threads to destroy ! 1686: * (when they request that they be destroyed, of course). ! 1687: */ ! 1688: void reaper_thread_continue(void) ! 1689: { ! 1690: for (;;) { ! 1691: register thread_t thread; ! 1692: spl_t s; ! 1693: ! 1694: s = splsched(); ! 1695: simple_lock(&reaper_lock); ! 1696: ! 1697: while ((thread = (thread_t) dequeue_head(&reaper_queue)) ! 1698: != THREAD_NULL) { ! 1699: simple_unlock(&reaper_lock); ! 1700: (void) splx(s); ! 1701: ! 1702: (void) thread_dowait(thread, TRUE); /* may block */ ! 1703: thread_deallocate(thread); /* may block */ ! 1704: ! 1705: s = splsched(); ! 1706: simple_lock(&reaper_lock); ! 1707: } ! 1708: ! 1709: assert_wait((event_t) &reaper_queue, FALSE); ! 1710: simple_unlock(&reaper_lock); ! 1711: (void) splx(s); ! 1712: counter(c_reaper_thread_block++); ! 1713: thread_block(reaper_thread_continue); ! 1714: } ! 1715: } ! 1716: ! 1717: void reaper_thread(void) ! 1718: { ! 1719: reaper_thread_continue(); ! 1720: /*NOTREACHED*/ ! 1721: } ! 1722: ! 1723: #if MACH_HOST ! 1724: /* ! 1725: * thread_assign: ! 1726: * ! 1727: * Change processor set assignment. ! 1728: * Caller must hold an extra reference to the thread (if this is ! 1729: * called directly from the ipc interface, this is an operation ! 1730: * in progress reference). Caller must hold no locks -- this may block. ! 1731: */ ! 1732: ! 1733: kern_return_t ! 1734: thread_assign( ! 1735: thread_t thread, ! 1736: processor_set_t new_pset) ! 1737: { ! 1738: if (thread == THREAD_NULL || new_pset == PROCESSOR_SET_NULL) { ! 1739: return KERN_INVALID_ARGUMENT; ! 1740: } ! 1741: ! 1742: thread_freeze(thread); ! 1743: thread_doassign(thread, new_pset, TRUE); ! 1744: ! 1745: return KERN_SUCCESS; ! 1746: } ! 1747: ! 1748: /* ! 1749: * thread_freeze: ! 1750: * ! 1751: * Freeze thread's assignment. Prelude to assigning thread. ! 1752: * Only one freeze may be held per thread. ! 1753: */ ! 1754: void ! 1755: thread_freeze( ! 1756: thread_t thread) ! 1757: { ! 1758: spl_t s; ! 1759: /* ! 1760: * Freeze the assignment, deferring to a prior freeze. ! 1761: */ ! 1762: s = splsched(); ! 1763: thread_lock(thread); ! 1764: while (thread->may_assign == FALSE) { ! 1765: thread->assign_active = TRUE; ! 1766: thread_sleep((event_t) &thread->assign_active, ! 1767: simple_lock_addr(thread->lock), FALSE); ! 1768: thread_lock(thread); ! 1769: } ! 1770: thread->may_assign = FALSE; ! 1771: thread_unlock(thread); ! 1772: (void) splx(s); ! 1773: ! 1774: } ! 1775: ! 1776: /* ! 1777: * thread_unfreeze: release freeze on thread's assignment. ! 1778: */ ! 1779: void ! 1780: thread_unfreeze( ! 1781: thread_t thread) ! 1782: { ! 1783: spl_t s; ! 1784: ! 1785: s = splsched(); ! 1786: thread_lock(thread); ! 1787: thread->may_assign = TRUE; ! 1788: if (thread->assign_active) { ! 1789: thread->assign_active = FALSE; ! 1790: thread_wakeup((event_t)&thread->assign_active); ! 1791: } ! 1792: thread_unlock(thread); ! 1793: splx(s); ! 1794: } ! 1795: ! 1796: /* ! 1797: * thread_doassign: ! 1798: * ! 1799: * Actually do thread assignment. thread_will_assign must have been ! 1800: * called on the thread. release_freeze argument indicates whether ! 1801: * to release freeze on thread. ! 1802: */ ! 1803: ! 1804: void ! 1805: thread_doassign( ! 1806: register thread_t thread, ! 1807: register processor_set_t new_pset, ! 1808: boolean_t release_freeze) ! 1809: { ! 1810: register processor_set_t pset; ! 1811: register boolean_t old_empty, new_empty; ! 1812: boolean_t recompute_pri = FALSE; ! 1813: spl_t s; ! 1814: ! 1815: /* ! 1816: * Check for silly no-op. ! 1817: */ ! 1818: pset = thread->processor_set; ! 1819: if (pset == new_pset) { ! 1820: if (release_freeze) ! 1821: thread_unfreeze(thread); ! 1822: return; ! 1823: } ! 1824: /* ! 1825: * Suspend the thread and stop it if it's not the current thread. ! 1826: */ ! 1827: thread_hold(thread); ! 1828: if (thread != current_thread()) ! 1829: (void) thread_dowait(thread, TRUE); ! 1830: ! 1831: /* ! 1832: * Lock both psets now, use ordering to avoid deadlocks. ! 1833: */ ! 1834: Restart: ! 1835: if ((vm_offset_t)pset < (vm_offset_t)new_pset) { ! 1836: pset_lock(pset); ! 1837: pset_lock(new_pset); ! 1838: } ! 1839: else { ! 1840: pset_lock(new_pset); ! 1841: pset_lock(pset); ! 1842: } ! 1843: ! 1844: /* ! 1845: * Check if new_pset is ok to assign to. If not, reassign ! 1846: * to default_pset. ! 1847: */ ! 1848: if (!new_pset->active) { ! 1849: pset_unlock(pset); ! 1850: pset_unlock(new_pset); ! 1851: new_pset = &default_pset; ! 1852: goto Restart; ! 1853: } ! 1854: ! 1855: pset_reference(new_pset); ! 1856: ! 1857: /* ! 1858: * Grab the thread lock and move the thread. ! 1859: * Then drop the lock on the old pset and the thread's ! 1860: * reference to it. ! 1861: */ ! 1862: s = splsched(); ! 1863: thread_lock(thread); ! 1864: ! 1865: thread_change_psets(thread, pset, new_pset); ! 1866: ! 1867: old_empty = pset->empty; ! 1868: new_empty = new_pset->empty; ! 1869: ! 1870: pset_unlock(pset); ! 1871: ! 1872: /* ! 1873: * Reset policy and priorities if needed. ! 1874: */ ! 1875: #if MACH_FIXPRI ! 1876: if (thread->policy & new_pset->policies == 0) { ! 1877: thread->policy = POLICY_TIMESHARE; ! 1878: recompute_pri = TRUE; ! 1879: } ! 1880: #endif /* MACH_FIXPRI */ ! 1881: ! 1882: if (thread->max_priority < new_pset->max_priority) { ! 1883: thread->max_priority = new_pset->max_priority; ! 1884: if (thread->priority < thread->max_priority) { ! 1885: thread->priority = thread->max_priority; ! 1886: recompute_pri = TRUE; ! 1887: } ! 1888: else { ! 1889: if ((thread->depress_priority >= 0) && ! 1890: (thread->depress_priority < thread->max_priority)) { ! 1891: thread->depress_priority = thread->max_priority; ! 1892: } ! 1893: } ! 1894: } ! 1895: ! 1896: pset_unlock(new_pset); ! 1897: ! 1898: if (recompute_pri) ! 1899: compute_priority(thread, TRUE); ! 1900: ! 1901: if (release_freeze) { ! 1902: thread->may_assign = TRUE; ! 1903: if (thread->assign_active) { ! 1904: thread->assign_active = FALSE; ! 1905: thread_wakeup((event_t)&thread->assign_active); ! 1906: } ! 1907: } ! 1908: ! 1909: thread_unlock(thread); ! 1910: splx(s); ! 1911: ! 1912: pset_deallocate(pset); ! 1913: ! 1914: /* ! 1915: * Figure out hold status of thread. Threads assigned to empty ! 1916: * psets must be held. Therefore: ! 1917: * If old pset was empty release its hold. ! 1918: * Release our hold from above unless new pset is empty. ! 1919: */ ! 1920: ! 1921: if (old_empty) ! 1922: thread_release(thread); ! 1923: if (!new_empty) ! 1924: thread_release(thread); ! 1925: ! 1926: /* ! 1927: * If current_thread is assigned, context switch to force ! 1928: * assignment to happen. This also causes hold to take ! 1929: * effect if the new pset is empty. ! 1930: */ ! 1931: if (thread == current_thread()) { ! 1932: s = splsched(); ! 1933: ast_on(cpu_number(), AST_BLOCK); ! 1934: (void) splx(s); ! 1935: } ! 1936: } ! 1937: #else /* MACH_HOST */ ! 1938: kern_return_t ! 1939: thread_assign( ! 1940: thread_t thread, ! 1941: processor_set_t new_pset) ! 1942: { ! 1943: return KERN_FAILURE; ! 1944: } ! 1945: #endif /* MACH_HOST */ ! 1946: ! 1947: /* ! 1948: * thread_assign_default: ! 1949: * ! 1950: * Special version of thread_assign for assigning threads to default ! 1951: * processor set. ! 1952: */ ! 1953: kern_return_t ! 1954: thread_assign_default( ! 1955: thread_t thread) ! 1956: { ! 1957: return thread_assign(thread, &default_pset); ! 1958: } ! 1959: ! 1960: /* ! 1961: * thread_get_assignment ! 1962: * ! 1963: * Return current assignment for this thread. ! 1964: */ ! 1965: kern_return_t thread_get_assignment( ! 1966: thread_t thread, ! 1967: processor_set_t *pset) ! 1968: { ! 1969: *pset = thread->processor_set; ! 1970: pset_reference(*pset); ! 1971: return KERN_SUCCESS; ! 1972: } ! 1973: ! 1974: /* ! 1975: * thread_priority: ! 1976: * ! 1977: * Set priority (and possibly max priority) for thread. ! 1978: */ ! 1979: kern_return_t ! 1980: thread_priority( ! 1981: thread_t thread, ! 1982: int priority, ! 1983: boolean_t set_max) ! 1984: { ! 1985: spl_t s; ! 1986: kern_return_t ret = KERN_SUCCESS; ! 1987: ! 1988: if ((thread == THREAD_NULL) || invalid_pri(priority)) ! 1989: return KERN_INVALID_ARGUMENT; ! 1990: ! 1991: s = splsched(); ! 1992: thread_lock(thread); ! 1993: ! 1994: /* ! 1995: * Check for violation of max priority ! 1996: */ ! 1997: if (priority < thread->max_priority) { ! 1998: ret = KERN_FAILURE; ! 1999: } ! 2000: else { ! 2001: /* ! 2002: * Set priorities. If a depression is in progress, ! 2003: * change the priority to restore. ! 2004: */ ! 2005: if (thread->depress_priority >= 0) { ! 2006: thread->depress_priority = priority; ! 2007: } ! 2008: else { ! 2009: thread->priority = priority; ! 2010: compute_priority(thread, TRUE); ! 2011: } ! 2012: ! 2013: if (set_max) ! 2014: thread->max_priority = priority; ! 2015: } ! 2016: thread_unlock(thread); ! 2017: (void) splx(s); ! 2018: ! 2019: return ret; ! 2020: } ! 2021: ! 2022: /* ! 2023: * thread_set_own_priority: ! 2024: * ! 2025: * Internal use only; sets the priority of the calling thread. ! 2026: * Will adjust max_priority if necessary. ! 2027: */ ! 2028: void ! 2029: thread_set_own_priority( ! 2030: int priority) ! 2031: { ! 2032: spl_t s; ! 2033: thread_t thread = current_thread(); ! 2034: ! 2035: s = splsched(); ! 2036: thread_lock(thread); ! 2037: ! 2038: if (priority < thread->max_priority) ! 2039: thread->max_priority = priority; ! 2040: thread->priority = priority; ! 2041: compute_priority(thread, TRUE); ! 2042: ! 2043: thread_unlock(thread); ! 2044: (void) splx(s); ! 2045: } ! 2046: ! 2047: /* ! 2048: * thread_max_priority: ! 2049: * ! 2050: * Reset the max priority for a thread. ! 2051: */ ! 2052: kern_return_t ! 2053: thread_max_priority( ! 2054: thread_t thread, ! 2055: processor_set_t pset, ! 2056: int max_priority) ! 2057: { ! 2058: spl_t s; ! 2059: kern_return_t ret = KERN_SUCCESS; ! 2060: ! 2061: if ((thread == THREAD_NULL) || (pset == PROCESSOR_SET_NULL) || ! 2062: invalid_pri(max_priority)) ! 2063: return KERN_INVALID_ARGUMENT; ! 2064: ! 2065: s = splsched(); ! 2066: thread_lock(thread); ! 2067: ! 2068: #if MACH_HOST ! 2069: /* ! 2070: * Check for wrong processor set. ! 2071: */ ! 2072: if (pset != thread->processor_set) { ! 2073: ret = KERN_FAILURE; ! 2074: } ! 2075: else { ! 2076: #endif /* MACH_HOST */ ! 2077: thread->max_priority = max_priority; ! 2078: ! 2079: /* ! 2080: * Reset priority if it violates new max priority ! 2081: */ ! 2082: if (max_priority > thread->priority) { ! 2083: thread->priority = max_priority; ! 2084: ! 2085: compute_priority(thread, TRUE); ! 2086: } ! 2087: else { ! 2088: if (thread->depress_priority >= 0 && ! 2089: max_priority > thread->depress_priority) ! 2090: thread->depress_priority = max_priority; ! 2091: } ! 2092: #if MACH_HOST ! 2093: } ! 2094: #endif /* MACH_HOST */ ! 2095: ! 2096: thread_unlock(thread); ! 2097: (void) splx(s); ! 2098: ! 2099: return ret; ! 2100: } ! 2101: ! 2102: /* ! 2103: * thread_policy: ! 2104: * ! 2105: * Set scheduling policy for thread. ! 2106: */ ! 2107: kern_return_t ! 2108: thread_policy( ! 2109: thread_t thread, ! 2110: int policy, ! 2111: int data) ! 2112: { ! 2113: #if MACH_FIXPRI ! 2114: register kern_return_t ret = KERN_SUCCESS; ! 2115: register int temp; ! 2116: spl_t s; ! 2117: #endif /* MACH_FIXPRI */ ! 2118: ! 2119: if ((thread == THREAD_NULL) || invalid_policy(policy)) ! 2120: return KERN_INVALID_ARGUMENT; ! 2121: ! 2122: #if MACH_FIXPRI ! 2123: s = splsched(); ! 2124: thread_lock(thread); ! 2125: ! 2126: /* ! 2127: * Check if changing policy. ! 2128: */ ! 2129: if (policy == thread->policy) { ! 2130: /* ! 2131: * Just changing data. This is meaningless for ! 2132: * timesharing, quantum for fixed priority (but ! 2133: * has no effect until current quantum runs out). ! 2134: */ ! 2135: if (policy == POLICY_FIXEDPRI) { ! 2136: temp = data * 1000; ! 2137: if (temp % tick) ! 2138: temp += tick; ! 2139: thread->sched_data = temp/tick; ! 2140: } ! 2141: } ! 2142: else { ! 2143: /* ! 2144: * Changing policy. Check if new policy is allowed. ! 2145: */ ! 2146: if ((thread->processor_set->policies & policy) == 0) { ! 2147: ret = KERN_FAILURE; ! 2148: } ! 2149: else { ! 2150: /* ! 2151: * Changing policy. Save data and calculate new ! 2152: * priority. ! 2153: */ ! 2154: thread->policy = policy; ! 2155: if (policy == POLICY_FIXEDPRI) { ! 2156: temp = data * 1000; ! 2157: if (temp % tick) ! 2158: temp += tick; ! 2159: thread->sched_data = temp/tick; ! 2160: } ! 2161: compute_priority(thread, TRUE); ! 2162: } ! 2163: } ! 2164: thread_unlock(thread); ! 2165: (void) splx(s); ! 2166: ! 2167: return ret; ! 2168: #else /* MACH_FIXPRI */ ! 2169: if (policy == POLICY_TIMESHARE) ! 2170: return KERN_SUCCESS; ! 2171: else ! 2172: return KERN_FAILURE; ! 2173: #endif /* MACH_FIXPRI */ ! 2174: } ! 2175: ! 2176: /* ! 2177: * thread_wire: ! 2178: * ! 2179: * Specify that the target thread must always be able ! 2180: * to run and to allocate memory. ! 2181: */ ! 2182: kern_return_t ! 2183: thread_wire( ! 2184: host_t host, ! 2185: thread_t thread, ! 2186: boolean_t wired) ! 2187: { ! 2188: spl_t s; ! 2189: ! 2190: if (host == HOST_NULL) ! 2191: return KERN_INVALID_ARGUMENT; ! 2192: ! 2193: if (thread == THREAD_NULL) ! 2194: return KERN_INVALID_ARGUMENT; ! 2195: ! 2196: /* ! 2197: * This implementation only works for the current thread. ! 2198: * See stack_privilege. ! 2199: */ ! 2200: if (thread != current_thread()) ! 2201: return KERN_INVALID_ARGUMENT; ! 2202: ! 2203: s = splsched(); ! 2204: thread_lock(thread); ! 2205: ! 2206: if (wired) { ! 2207: thread->vm_privilege = TRUE; ! 2208: stack_privilege(thread); ! 2209: } ! 2210: else { ! 2211: thread->vm_privilege = FALSE; ! 2212: /*XXX stack_unprivilege(thread); */ ! 2213: thread->stack_privilege = 0; ! 2214: } ! 2215: ! 2216: thread_unlock(thread); ! 2217: splx(s); ! 2218: ! 2219: return KERN_SUCCESS; ! 2220: } ! 2221: ! 2222: /* ! 2223: * thread_collect_scan: ! 2224: * ! 2225: * Attempt to free resources owned by threads. ! 2226: * pcb_collect doesn't do anything yet. ! 2227: */ ! 2228: ! 2229: void thread_collect_scan(void) ! 2230: { ! 2231: #if 0 ! 2232: register thread_t thread, prev_thread; ! 2233: processor_set_t pset, prev_pset; ! 2234: ! 2235: prev_thread = THREAD_NULL; ! 2236: prev_pset = PROCESSOR_SET_NULL; ! 2237: ! 2238: simple_lock(&all_psets_lock); ! 2239: queue_iterate(&all_psets, pset, processor_set_t, all_psets) { ! 2240: pset_lock(pset); ! 2241: queue_iterate(&pset->threads, thread, thread_t, pset_threads) { ! 2242: spl_t s = splsched(); ! 2243: thread_lock(thread); ! 2244: ! 2245: /* ! 2246: * Only collect threads which are ! 2247: * not runnable and are swapped. ! 2248: */ ! 2249: ! 2250: if ((thread->state & (TH_RUN|TH_SWAPPED)) ! 2251: == TH_SWAPPED) { ! 2252: thread->ref_count++; ! 2253: thread_unlock(thread); ! 2254: (void) splx(s); ! 2255: pset->ref_count++; ! 2256: pset_unlock(pset); ! 2257: simple_unlock(&all_psets_lock); ! 2258: ! 2259: pcb_collect(thread); ! 2260: ! 2261: if (prev_thread != THREAD_NULL) ! 2262: thread_deallocate(prev_thread); ! 2263: prev_thread = thread; ! 2264: ! 2265: if (prev_pset != PROCESSOR_SET_NULL) ! 2266: pset_deallocate(prev_pset); ! 2267: prev_pset = pset; ! 2268: ! 2269: simple_lock(&all_psets_lock); ! 2270: pset_lock(pset); ! 2271: } else { ! 2272: thread_unlock(thread); ! 2273: (void) splx(s); ! 2274: } ! 2275: } ! 2276: pset_unlock(pset); ! 2277: } ! 2278: simple_unlock(&all_psets_lock); ! 2279: ! 2280: if (prev_thread != THREAD_NULL) ! 2281: thread_deallocate(prev_thread); ! 2282: if (prev_pset != PROCESSOR_SET_NULL) ! 2283: pset_deallocate(prev_pset); ! 2284: #endif /* 0 */ ! 2285: } ! 2286: ! 2287: boolean_t thread_collect_allowed = TRUE; ! 2288: unsigned thread_collect_last_tick = 0; ! 2289: unsigned thread_collect_max_rate = 0; /* in ticks */ ! 2290: ! 2291: /* ! 2292: * consider_thread_collect: ! 2293: * ! 2294: * Called by the pageout daemon when the system needs more free pages. ! 2295: */ ! 2296: ! 2297: void consider_thread_collect(void) ! 2298: { ! 2299: /* ! 2300: * By default, don't attempt thread collection more frequently ! 2301: * than once a second. ! 2302: */ ! 2303: ! 2304: if (thread_collect_max_rate == 0) ! 2305: thread_collect_max_rate = hz; ! 2306: ! 2307: if (thread_collect_allowed && ! 2308: (sched_tick > ! 2309: (thread_collect_last_tick + thread_collect_max_rate))) { ! 2310: thread_collect_last_tick = sched_tick; ! 2311: thread_collect_scan(); ! 2312: } ! 2313: } ! 2314: ! 2315: #if MACH_DEBUG ! 2316: ! 2317: vm_size_t stack_usage( ! 2318: register vm_offset_t stack) ! 2319: { ! 2320: int i; ! 2321: ! 2322: for (i = 0; i < KERNEL_STACK_SIZE/sizeof(unsigned int); i++) ! 2323: if (((unsigned int *)stack)[i] != STACK_MARKER) ! 2324: break; ! 2325: ! 2326: return KERNEL_STACK_SIZE - i * sizeof(unsigned int); ! 2327: } ! 2328: ! 2329: /* ! 2330: * Machine-dependent code should call stack_init ! 2331: * before doing its own initialization of the stack. ! 2332: */ ! 2333: ! 2334: void stack_init( ! 2335: register vm_offset_t stack) ! 2336: { ! 2337: if (stack_check_usage) { ! 2338: int i; ! 2339: ! 2340: for (i = 0; i < KERNEL_STACK_SIZE/sizeof(unsigned int); i++) ! 2341: ((unsigned int *)stack)[i] = STACK_MARKER; ! 2342: } ! 2343: } ! 2344: ! 2345: /* ! 2346: * Machine-dependent code should call stack_finalize ! 2347: * before releasing the stack memory. ! 2348: */ ! 2349: ! 2350: void stack_finalize( ! 2351: register vm_offset_t stack) ! 2352: { ! 2353: if (stack_check_usage) { ! 2354: vm_size_t used = stack_usage(stack); ! 2355: ! 2356: simple_lock(&stack_usage_lock); ! 2357: if (used > stack_max_usage) ! 2358: stack_max_usage = used; ! 2359: simple_unlock(&stack_usage_lock); ! 2360: } ! 2361: } ! 2362: ! 2363: #ifndef MACHINE_STACK ! 2364: /* ! 2365: * stack_statistics: ! 2366: * ! 2367: * Return statistics on cached kernel stacks. ! 2368: * *maxusagep must be initialized by the caller. ! 2369: */ ! 2370: ! 2371: void stack_statistics( ! 2372: natural_t *totalp, ! 2373: vm_size_t *maxusagep) ! 2374: { ! 2375: spl_t s; ! 2376: ! 2377: s = splsched(); ! 2378: stack_lock(); ! 2379: if (stack_check_usage) { ! 2380: vm_offset_t stack; ! 2381: ! 2382: /* ! 2383: * This is pretty expensive to do at splsched, ! 2384: * but it only happens when someone makes ! 2385: * a debugging call, so it should be OK. ! 2386: */ ! 2387: ! 2388: for (stack = stack_free_list; stack != 0; ! 2389: stack = stack_next(stack)) { ! 2390: vm_size_t usage = stack_usage(stack); ! 2391: ! 2392: if (usage > *maxusagep) ! 2393: *maxusagep = usage; ! 2394: } ! 2395: } ! 2396: ! 2397: *totalp = stack_free_count; ! 2398: stack_unlock(); ! 2399: (void) splx(s); ! 2400: } ! 2401: #endif /* MACHINE_STACK */ ! 2402: ! 2403: kern_return_t host_stack_usage( ! 2404: host_t host, ! 2405: vm_size_t *reservedp, ! 2406: unsigned int *totalp, ! 2407: vm_size_t *spacep, ! 2408: vm_size_t *residentp, ! 2409: vm_size_t *maxusagep, ! 2410: vm_offset_t *maxstackp) ! 2411: { ! 2412: unsigned int total; ! 2413: vm_size_t maxusage; ! 2414: ! 2415: if (host == HOST_NULL) ! 2416: return KERN_INVALID_HOST; ! 2417: ! 2418: simple_lock(&stack_usage_lock); ! 2419: maxusage = stack_max_usage; ! 2420: simple_unlock(&stack_usage_lock); ! 2421: ! 2422: stack_statistics(&total, &maxusage); ! 2423: ! 2424: *reservedp = 0; ! 2425: *totalp = total; ! 2426: *spacep = *residentp = total * round_page(KERNEL_STACK_SIZE); ! 2427: *maxusagep = maxusage; ! 2428: *maxstackp = 0; ! 2429: return KERN_SUCCESS; ! 2430: } ! 2431: ! 2432: kern_return_t processor_set_stack_usage( ! 2433: processor_set_t pset, ! 2434: unsigned int *totalp, ! 2435: vm_size_t *spacep, ! 2436: vm_size_t *residentp, ! 2437: vm_size_t *maxusagep, ! 2438: vm_offset_t *maxstackp) ! 2439: { ! 2440: unsigned int total; ! 2441: vm_size_t maxusage; ! 2442: vm_offset_t maxstack; ! 2443: ! 2444: register thread_t *threads; ! 2445: register thread_t tmp_thread; ! 2446: ! 2447: unsigned int actual; /* this many things */ ! 2448: unsigned int i; ! 2449: ! 2450: vm_size_t size, size_needed; ! 2451: vm_offset_t addr; ! 2452: ! 2453: if (pset == PROCESSOR_SET_NULL) ! 2454: return KERN_INVALID_ARGUMENT; ! 2455: ! 2456: size = 0; addr = 0; ! 2457: ! 2458: for (;;) { ! 2459: pset_lock(pset); ! 2460: if (!pset->active) { ! 2461: pset_unlock(pset); ! 2462: return KERN_INVALID_ARGUMENT; ! 2463: } ! 2464: ! 2465: actual = pset->thread_count; ! 2466: ! 2467: /* do we have the memory we need? */ ! 2468: ! 2469: size_needed = actual * sizeof(thread_t); ! 2470: if (size_needed <= size) ! 2471: break; ! 2472: ! 2473: /* unlock the pset and allocate more memory */ ! 2474: pset_unlock(pset); ! 2475: ! 2476: if (size != 0) ! 2477: kfree(addr, size); ! 2478: ! 2479: assert(size_needed > 0); ! 2480: size = size_needed; ! 2481: ! 2482: addr = kalloc(size); ! 2483: if (addr == 0) ! 2484: return KERN_RESOURCE_SHORTAGE; ! 2485: } ! 2486: ! 2487: /* OK, have memory and the processor_set is locked & active */ ! 2488: ! 2489: threads = (thread_t *) addr; ! 2490: for (i = 0, tmp_thread = (thread_t) queue_first(&pset->threads); ! 2491: i < actual; ! 2492: i++, ! 2493: tmp_thread = (thread_t) queue_next(&tmp_thread->pset_threads)) { ! 2494: thread_reference(tmp_thread); ! 2495: threads[i] = tmp_thread; ! 2496: } ! 2497: assert(queue_end(&pset->threads, (queue_entry_t) tmp_thread)); ! 2498: ! 2499: /* can unlock processor set now that we have the thread refs */ ! 2500: pset_unlock(pset); ! 2501: ! 2502: /* calculate maxusage and free thread references */ ! 2503: ! 2504: total = 0; ! 2505: maxusage = 0; ! 2506: maxstack = 0; ! 2507: for (i = 0; i < actual; i++) { ! 2508: thread_t thread = threads[i]; ! 2509: vm_offset_t stack = 0; ! 2510: ! 2511: /* ! 2512: * thread->kernel_stack is only accurate if the ! 2513: * thread isn't swapped and is not executing. ! 2514: * ! 2515: * Of course, we don't have the appropriate locks ! 2516: * for these shenanigans. ! 2517: */ ! 2518: ! 2519: if ((thread->state & TH_SWAPPED) == 0) { ! 2520: int cpu; ! 2521: ! 2522: stack = thread->kernel_stack; ! 2523: ! 2524: for (cpu = 0; cpu < NCPUS; cpu++) ! 2525: if (active_threads[cpu] == thread) { ! 2526: stack = active_stacks[cpu]; ! 2527: break; ! 2528: } ! 2529: } ! 2530: ! 2531: if (stack != 0) { ! 2532: total++; ! 2533: ! 2534: if (stack_check_usage) { ! 2535: vm_size_t usage = stack_usage(stack); ! 2536: ! 2537: if (usage > maxusage) { ! 2538: maxusage = usage; ! 2539: maxstack = (vm_offset_t) thread; ! 2540: } ! 2541: } ! 2542: } ! 2543: ! 2544: thread_deallocate(thread); ! 2545: } ! 2546: ! 2547: if (size != 0) ! 2548: kfree(addr, size); ! 2549: ! 2550: *totalp = total; ! 2551: *residentp = *spacep = total * round_page(KERNEL_STACK_SIZE); ! 2552: *maxusagep = maxusage; ! 2553: *maxstackp = maxstack; ! 2554: return KERN_SUCCESS; ! 2555: } ! 2556: ! 2557: /* ! 2558: * Useful in the debugger: ! 2559: */ ! 2560: void ! 2561: thread_stats(void) ! 2562: { ! 2563: register thread_t thread; ! 2564: int total = 0, rpcreply = 0; ! 2565: ! 2566: queue_iterate(&default_pset.threads, thread, thread_t, pset_threads) { ! 2567: total++; ! 2568: if (thread->ith_rpc_reply != IP_NULL) ! 2569: rpcreply++; ! 2570: } ! 2571: ! 2572: printf("%d total threads.\n", total); ! 2573: printf("%d using rpc_reply.\n", rpcreply); ! 2574: } ! 2575: #endif /* MACH_DEBUG */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.