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