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