|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * @OSF_FREE_COPYRIGHT@ ! 24: */ ! 25: /* ! 26: * Mach Operating System ! 27: * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University ! 28: * All Rights Reserved. ! 29: * ! 30: * Permission to use, copy, modify and distribute this software and its ! 31: * documentation is hereby granted, provided that both the copyright ! 32: * notice and this permission notice appear in all copies of the ! 33: * software, derivative works or modified versions, and any portions ! 34: * thereof, and that both notices appear in supporting documentation. ! 35: * ! 36: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" ! 37: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR ! 38: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 39: * ! 40: * Carnegie Mellon requests users of this software to return to ! 41: * ! 42: * Software Distribution Coordinator or [email protected] ! 43: * School of Computer Science ! 44: * Carnegie Mellon University ! 45: * Pittsburgh PA 15213-3890 ! 46: * ! 47: * any improvements or extensions that they make and grant Carnegie Mellon ! 48: * the rights to redistribute these changes. ! 49: */ ! 50: /* ! 51: */ ! 52: /* ! 53: * File: kern/thread.c ! 54: * Author: Avadis Tevanian, Jr., Michael Wayne Young, David Golub ! 55: * Date: 1986 ! 56: * ! 57: * Thread/thread_shuttle management primitives implementation. ! 58: */ ! 59: /* ! 60: * Copyright (c) 1993 The University of Utah and ! 61: * the Computer Systems Laboratory (CSL). All rights reserved. ! 62: * ! 63: * Permission to use, copy, modify and distribute this software and its ! 64: * documentation is hereby granted, provided that both the copyright ! 65: * notice and this permission notice appear in all copies of the ! 66: * software, derivative works or modified versions, and any portions ! 67: * thereof, and that both notices appear in supporting documentation. ! 68: * ! 69: * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS ! 70: * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF ! 71: * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 72: * ! 73: * CSL requests users of this software to return to [email protected] any ! 74: * improvements that they make and grant CSL redistribution rights. ! 75: * ! 76: */ ! 77: ! 78: #include <cpus.h> ! 79: #include <mach_host.h> ! 80: #include <simple_clock.h> ! 81: #include <mach_debug.h> ! 82: #include <mach_prof.h> ! 83: #include <dipc.h> ! 84: #include <stack_usage.h> ! 85: ! 86: #include <mach/boolean.h> ! 87: #include <mach/policy.h> ! 88: #include <mach/thread_info.h> ! 89: #include <mach/thread_special_ports.h> ! 90: #include <mach/thread_status.h> ! 91: #include <mach/time_value.h> ! 92: #include <mach/vm_param.h> ! 93: #include <kern/ast.h> ! 94: #include <kern/cpu_data.h> ! 95: #include <kern/counters.h> ! 96: #include <kern/etap_macros.h> ! 97: #include <kern/ipc_mig.h> ! 98: #include <kern/ipc_tt.h> ! 99: #include <kern/mach_param.h> ! 100: #include <kern/machine.h> ! 101: #include <kern/misc_protos.h> ! 102: #include <kern/processor.h> ! 103: #include <kern/queue.h> ! 104: #include <kern/sched.h> ! 105: #include <kern/sched_prim.h> ! 106: #include <kern/sf.h> ! 107: #include <kern/mk_sp.h> /*** ??? fix so this can be removed ***/ ! 108: #include <kern/task.h> ! 109: #include <kern/thread.h> ! 110: #include <kern/thread_act.h> ! 111: #include <kern/thread_swap.h> ! 112: #include <kern/host.h> ! 113: #include <kern/zalloc.h> ! 114: #include <vm/vm_kern.h> ! 115: #include <ipc/ipc_kmsg.h> ! 116: #include <ipc/ipc_port.h> ! 117: #include <machine/thread.h> /* for MACHINE_STACK */ ! 118: #include <kern/profile.h> ! 119: #include <kern/assert.h> ! 120: #include <sys/kdebug.h> ! 121: ! 122: /* ! 123: * Exported interfaces ! 124: */ ! 125: ! 126: #include <mach/thread_act_server.h> ! 127: #include <mach/mach_host_server.h> ! 128: ! 129: /* ! 130: * Per-Cpu stashed global state ! 131: */ ! 132: vm_offset_t active_stacks[NCPUS]; /* per-cpu active stacks */ ! 133: vm_offset_t kernel_stack[NCPUS]; /* top of active stacks */ ! 134: thread_act_t active_kloaded[NCPUS]; /* + act if kernel loaded */ ! 135: ! 136: decl_mutex_data(, funnel_lock) ! 137: ! 138: struct zone *thread_shuttle_zone; ! 139: ! 140: queue_head_t reaper_queue; ! 141: decl_simple_lock_data(,reaper_lock) ! 142: thread_call_t thread_reaper_call; ! 143: ! 144: extern int tick; ! 145: ! 146: extern void pcb_module_init(void); ! 147: ! 148: /* private */ ! 149: static struct thread_shuttle thr_sh_template; ! 150: ! 151: #if MACH_DEBUG ! 152: #if STACK_USAGE ! 153: static void stack_init(vm_offset_t stack, unsigned int bytes); ! 154: void stack_finalize(vm_offset_t stack); ! 155: vm_size_t stack_usage(vm_offset_t stack); ! 156: #else /*STACK_USAGE*/ ! 157: #define stack_init(stack, size) ! 158: #define stack_finalize(stack) ! 159: #define stack_usage(stack) (vm_size_t)0 ! 160: #endif /*STACK_USAGE*/ ! 161: ! 162: #ifdef MACHINE_STACK ! 163: extern ! 164: #endif ! 165: void stack_statistics( ! 166: unsigned int *totalp, ! 167: vm_size_t *maxusagep); ! 168: ! 169: #define STACK_MARKER 0xdeadbeef ! 170: #if STACK_USAGE ! 171: boolean_t stack_check_usage = TRUE; ! 172: #else /* STACK_USAGE */ ! 173: boolean_t stack_check_usage = FALSE; ! 174: #endif /* STACK_USAGE */ ! 175: decl_simple_lock_data(,stack_usage_lock) ! 176: vm_size_t stack_max_usage = 0; ! 177: vm_size_t stack_max_use = KERNEL_STACK_SIZE - 64; ! 178: #endif /* MACH_DEBUG */ ! 179: ! 180: /* Forwards */ ! 181: void thread_collect_scan(void); ! 182: ! 183: kern_return_t thread_create_shuttle( ! 184: thread_act_t thr_act, ! 185: sp_attributes_t policy_attributes, ! 186: void (*start_at)(void), ! 187: thread_t *new_thread); ! 188: ! 189: extern void Load_context( ! 190: thread_t thread); ! 191: ! 192: ! 193: /* ! 194: * Machine-dependent code must define: ! 195: * thread_machine_init ! 196: * thread_machine_terminate ! 197: * thread_machine_collect ! 198: * ! 199: * The thread->pcb field is reserved for machine-dependent code. ! 200: */ ! 201: ! 202: #ifdef MACHINE_STACK ! 203: /* ! 204: * Machine-dependent code must define: ! 205: * stack_alloc_try ! 206: * stack_alloc ! 207: * stack_free ! 208: * stack_collect ! 209: * and if MACH_DEBUG: ! 210: * stack_statistics ! 211: */ ! 212: #else /* MACHINE_STACK */ ! 213: /* ! 214: * We allocate stacks from generic kernel VM. ! 215: * Machine-dependent code must define: ! 216: * machine_kernel_stack_init ! 217: * ! 218: * The stack_free_list can only be accessed at splsched, ! 219: * because stack_alloc_try/thread_invoke operate at splsched. ! 220: */ ! 221: ! 222: decl_simple_lock_data(,stack_lock_data) /* splsched only */ ! 223: #define stack_lock() simple_lock(&stack_lock_data) ! 224: #define stack_unlock() simple_unlock(&stack_lock_data) ! 225: ! 226: vm_offset_t stack_free_list; /* splsched only */ ! 227: unsigned int stack_free_count = 0; /* splsched only */ ! 228: unsigned int stack_free_limit = 1; /* patchable */ ! 229: ! 230: unsigned int stack_alloc_hits = 0; /* debugging */ ! 231: unsigned int stack_alloc_misses = 0; /* debugging */ ! 232: unsigned int stack_alloc_max = 0; /* debugging */ ! 233: ! 234: unsigned int stack_alloc_total = 0; ! 235: unsigned int stack_alloc_hiwater = 0; ! 236: ! 237: /* ! 238: * The next field is at the base of the stack, ! 239: * so the low end is left unsullied. ! 240: */ ! 241: ! 242: #define stack_next(stack) (*((vm_offset_t *)((stack) + KERNEL_STACK_SIZE) - 1)) ! 243: ! 244: /* ! 245: * stack_alloc: ! 246: * ! 247: * Allocate a kernel stack for an activation. ! 248: * May block. ! 249: */ ! 250: vm_offset_t ! 251: stack_alloc( ! 252: thread_t thread, ! 253: void (*continuation)(void)) ! 254: { ! 255: vm_offset_t stack; ! 256: spl_t s; ! 257: ! 258: /* ! 259: * We first try the free list. It is probably empty, ! 260: * or stack_alloc_try would have succeeded, but possibly ! 261: * a stack was freed before the swapin thread got to us. ! 262: */ ! 263: ! 264: s = splsched(); ! 265: stack_lock(); ! 266: stack = stack_free_list; ! 267: if (stack != 0) { ! 268: stack_free_list = stack_next(stack); ! 269: stack_free_count--; ! 270: } ! 271: stack_unlock(); ! 272: splx(s); ! 273: ! 274: if (stack == 0) { ! 275: /* ! 276: * Kernel stacks should be naturally aligned, ! 277: * so that it is easy to find the starting/ending ! 278: * addresses of a stack given an address in the middle. ! 279: */ ! 280: ! 281: if (kmem_alloc_aligned(kernel_map, &stack, ! 282: round_page(KERNEL_STACK_SIZE)) != KERN_SUCCESS) ! 283: panic("stack_alloc"); ! 284: ! 285: stack_alloc_total++; ! 286: if (stack_alloc_total > stack_alloc_hiwater) ! 287: stack_alloc_hiwater = stack_alloc_total; ! 288: ! 289: #if MACH_DEBUG ! 290: stack_init(stack, round_page(KERNEL_STACK_SIZE)); ! 291: #endif /* MACH_DEBUG */ ! 292: ! 293: /* ! 294: * If using fractional pages, free the remainder(s) ! 295: */ ! 296: if (KERNEL_STACK_SIZE < round_page(KERNEL_STACK_SIZE)) { ! 297: vm_offset_t ptr = stack + KERNEL_STACK_SIZE; ! 298: vm_offset_t endp = stack + round_page(KERNEL_STACK_SIZE); ! 299: while (ptr < endp) { ! 300: #if MACH_DEBUG ! 301: /* ! 302: * We need to initialize just the end of the ! 303: * region. ! 304: */ ! 305: stack_init(ptr, (unsigned int) (endp - ptr)); ! 306: #endif ! 307: stack_lock(); ! 308: stack_next(stack) = stack_free_list; ! 309: stack_free_list = stack; ! 310: if (++stack_free_count > stack_alloc_max) ! 311: stack_alloc_max = stack_free_count; ! 312: stack_unlock(); ! 313: ptr += KERNEL_STACK_SIZE; ! 314: } ! 315: } ! 316: } ! 317: stack_attach(thread, stack, continuation); ! 318: return (stack); ! 319: } ! 320: ! 321: /* ! 322: * stack_free: ! 323: * ! 324: * Free a kernel stack. ! 325: * Called at splsched. ! 326: */ ! 327: ! 328: void ! 329: stack_free( ! 330: thread_t thread) ! 331: { ! 332: vm_offset_t stack = stack_detach(thread); ! 333: assert(stack); ! 334: if (stack != thread->stack_privilege) { ! 335: stack_lock(); ! 336: stack_next(stack) = stack_free_list; ! 337: stack_free_list = stack; ! 338: if (++stack_free_count > stack_alloc_max) ! 339: stack_alloc_max = stack_free_count; ! 340: stack_unlock(); ! 341: } ! 342: } ! 343: ! 344: /* ! 345: * stack_collect: ! 346: * ! 347: * Free excess kernel stacks. ! 348: * May block. ! 349: */ ! 350: ! 351: void ! 352: stack_collect(void) ! 353: { ! 354: register vm_offset_t stack; ! 355: spl_t s; ! 356: ! 357: /* If using fractional pages, Cannot just call kmem_free(), ! 358: * and we're too lazy to coalesce small chunks. ! 359: */ ! 360: if (KERNEL_STACK_SIZE < round_page(KERNEL_STACK_SIZE)) ! 361: return; ! 362: ! 363: s = splsched(); ! 364: stack_lock(); ! 365: while (stack_free_count > stack_free_limit) { ! 366: stack = stack_free_list; ! 367: stack_free_list = stack_next(stack); ! 368: stack_free_count--; ! 369: stack_unlock(); ! 370: splx(s); ! 371: ! 372: #if MACH_DEBUG ! 373: stack_finalize(stack); ! 374: #endif /* MACH_DEBUG */ ! 375: kmem_free(kernel_map, stack, KERNEL_STACK_SIZE); ! 376: ! 377: s = splsched(); ! 378: stack_alloc_total--; ! 379: stack_lock(); ! 380: } ! 381: stack_unlock(); ! 382: splx(s); ! 383: } ! 384: ! 385: ! 386: #if MACH_DEBUG ! 387: /* ! 388: * stack_statistics: ! 389: * ! 390: * Return statistics on cached kernel stacks. ! 391: * *maxusagep must be initialized by the caller. ! 392: */ ! 393: ! 394: void ! 395: stack_statistics( ! 396: unsigned int *totalp, ! 397: vm_size_t *maxusagep) ! 398: { ! 399: spl_t s; ! 400: ! 401: s = splsched(); ! 402: stack_lock(); ! 403: ! 404: #if STACK_USAGE ! 405: if (stack_check_usage) { ! 406: vm_offset_t stack; ! 407: ! 408: /* ! 409: * This is pretty expensive to do at splsched, ! 410: * but it only happens when someone makes ! 411: * a debugging call, so it should be OK. ! 412: */ ! 413: ! 414: for (stack = stack_free_list; stack != 0; ! 415: stack = stack_next(stack)) { ! 416: vm_size_t usage = stack_usage(stack); ! 417: ! 418: if (usage > *maxusagep) ! 419: *maxusagep = usage; ! 420: } ! 421: } ! 422: #endif /* STACK_USAGE */ ! 423: ! 424: *totalp = stack_free_count; ! 425: stack_unlock(); ! 426: splx(s); ! 427: } ! 428: #endif /* MACH_DEBUG */ ! 429: ! 430: #endif /* MACHINE_STACK */ ! 431: ! 432: ! 433: /* ! 434: * stack_privilege: ! 435: * ! 436: * stack_alloc_try on this thread must always succeed. ! 437: */ ! 438: ! 439: void ! 440: stack_privilege( ! 441: register thread_t thread) ! 442: { ! 443: /* ! 444: * This implementation only works for the current thread. ! 445: */ ! 446: ! 447: if (thread != current_thread()) ! 448: panic("stack_privilege"); ! 449: ! 450: if (thread->stack_privilege == 0) ! 451: thread->stack_privilege = current_stack(); ! 452: } ! 453: ! 454: /* ! 455: * stack_alloc_try: ! 456: * ! 457: * Non-blocking attempt to allocate a kernel stack. ! 458: * Called at splsched with the thread locked. ! 459: */ ! 460: ! 461: boolean_t stack_alloc_try( ! 462: thread_t thread, ! 463: void (*resume)(void)) ! 464: { ! 465: register vm_offset_t stack; ! 466: ! 467: if ((stack = thread->stack_privilege) == (vm_offset_t)0) { ! 468: stack_lock(); ! 469: stack = stack_free_list; ! 470: if (stack != (vm_offset_t)0) { ! 471: stack_free_list = stack_next(stack); ! 472: stack_free_count--; ! 473: } ! 474: stack_unlock(); ! 475: } ! 476: ! 477: if (stack != 0) { ! 478: stack_attach(thread, stack, resume); ! 479: stack_alloc_hits++; ! 480: return TRUE; ! 481: } else { ! 482: stack_alloc_misses++; ! 483: return FALSE; ! 484: } ! 485: } ! 486: ! 487: void ! 488: thread_init(void) ! 489: { ! 490: thread_shuttle_zone = zinit( ! 491: sizeof(struct thread_shuttle), ! 492: THREAD_MAX * sizeof(struct thread_shuttle), ! 493: THREAD_CHUNK * sizeof(struct thread_shuttle), ! 494: "threads"); ! 495: ! 496: /* ! 497: * Fill in a template thread_shuttle for fast initialization. ! 498: * [Fields that must be (or are typically) reset at ! 499: * time of creation are so noted.] ! 500: */ ! 501: ! 502: /* thr_sh_template.links (none) */ ! 503: thr_sh_template.runq = RUN_QUEUE_NULL; ! 504: ! 505: ! 506: /* thr_sh_template.task (later) */ ! 507: /* thr_sh_template.thread_list (later) */ ! 508: /* thr_sh_template.pset_threads (later) */ ! 509: ! 510: /* one ref for being alive, one to return to the creator */ ! 511: thr_sh_template.ref_count = 2; ! 512: ! 513: thr_sh_template.wait_event = NO_EVENT; ! 514: thr_sh_template.wait_result = KERN_SUCCESS; ! 515: thr_sh_template.wait_queue = WAIT_QUEUE_NULL; ! 516: thr_sh_template.wake_active = FALSE; ! 517: /*thr_sh_template.state = TH_SUSP;*/ ! 518: thr_sh_template.state = 0; ! 519: thr_sh_template.continuation = (void (*)(void))thread_bootstrap_return; ! 520: thr_sh_template.top_act = THR_ACT_NULL; ! 521: ! 522: /* thr_sh_template.priority (later) */ ! 523: /***??? thr_sh_template.max_priority = BASEPRI_USER; ***/ ! 524: /* thr_sh_template.sched_pri (later - compute_priority) */ ! 525: /***??? thr_sh_template.sched_data = 0; ***/ ! 526: thr_sh_template.policy = POLICY_TIMESHARE; ! 527: /***??? thr_sh_template.depress_priority = -1; ***/ ! 528: /***??? thr_sh_template.cpu_usage = 0; ***/ ! 529: /***??? thr_sh_template.sched_usage = 0; ***/ ! 530: /* thr_sh_template.sched_stamp (later) */ ! 531: /***??? thr_sh_template.sched_change_stamp = 1; ***/ ! 532: ! 533: thr_sh_template.vm_privilege = FALSE; ! 534: ! 535: /* thr_sh_template.<IPC structures> (later) */ ! 536: ! 537: timer_init(&(thr_sh_template.user_timer)); ! 538: timer_init(&(thr_sh_template.system_timer)); ! 539: thr_sh_template.user_timer_save.low = 0; ! 540: thr_sh_template.user_timer_save.high = 0; ! 541: thr_sh_template.system_timer_save.low = 0; ! 542: thr_sh_template.system_timer_save.high = 0; ! 543: thr_sh_template.cpu_delta = 0; ! 544: thr_sh_template.sched_delta = 0; ! 545: ! 546: thr_sh_template.active = FALSE; /* reset */ ! 547: ! 548: /* thr_sh_template.processor_set (later) */ ! 549: #if NCPUS > 1 ! 550: thr_sh_template.bound_processor = PROCESSOR_NULL; ! 551: #endif /*NCPUS > 1*/ ! 552: #if MACH_HOST ! 553: thr_sh_template.may_assign = TRUE; ! 554: thr_sh_template.assign_active = FALSE; ! 555: #endif /* MACH_HOST */ ! 556: thr_sh_template.funnel_state = 0; ! 557: ! 558: #if NCPUS > 1 ! 559: /* thr_sh_template.last_processor (later) */ ! 560: #endif /* NCPUS > 1 */ ! 561: ! 562: /* ! 563: * Initialize other data structures used in ! 564: * this module. ! 565: */ ! 566: ! 567: queue_init(&reaper_queue); ! 568: simple_lock_init(&reaper_lock, ETAP_THREAD_REAPER); ! 569: mutex_init(&funnel_lock,0); ! 570: ! 571: #ifndef MACHINE_STACK ! 572: simple_lock_init(&stack_lock_data, ETAP_THREAD_STACK); ! 573: #endif /* MACHINE_STACK */ ! 574: ! 575: #if MACH_DEBUG ! 576: simple_lock_init(&stack_usage_lock, ETAP_THREAD_STACK_USAGE); ! 577: #endif /* MACH_DEBUG */ ! 578: ! 579: #if MACH_LDEBUG ! 580: thr_sh_template.kthread = FALSE; ! 581: thr_sh_template.mutex_count = 0; ! 582: #endif /* MACH_LDEBUG */ ! 583: ! 584: /* ! 585: * Initialize any machine-dependent ! 586: * per-thread structures necessary. ! 587: */ ! 588: thread_machine_init(); ! 589: } ! 590: ! 591: void ! 592: thread_reaper_enqueue( ! 593: thread_t thread) ! 594: { ! 595: /* ! 596: * thread lock is already held, splsched() ! 597: * not necessary here. ! 598: */ ! 599: simple_lock(&reaper_lock); ! 600: ! 601: enqueue_tail(&reaper_queue, (queue_entry_t)thread); ! 602: #if 0 /* CHECKME! */ ! 603: /* ! 604: * Since thread has been put in the reaper_queue, it must no longer ! 605: * be preempted (otherwise, it could be put back in a run queue). ! 606: */ ! 607: thread->preempt = TH_NOT_PREEMPTABLE; ! 608: #endif ! 609: ! 610: simple_unlock(&reaper_lock); ! 611: ! 612: thread_call_enter(thread_reaper_call); ! 613: } ! 614: ! 615: void ! 616: thread_terminate_self(void) ! 617: { ! 618: register thread_t thread = current_thread(); ! 619: thread_act_t thr_act, prev_act; ! 620: task_t task; ! 621: sched_policy_t *policy; ! 622: spl_t s; ! 623: ! 624: /* ! 625: * Check for rpc chain. If so, switch to the previous ! 626: * activation, set error code, switch stacks and jump ! 627: * to mach_rpc_return_error. ! 628: */ ! 629: thr_act = thread->top_act; ! 630: thread = thr_act->thread; ! 631: task = thr_act->task; ! 632: ! 633: if (task) { ! 634: time_value_t user_time, system_time; ! 635: void *proc = NULL; ! 636: ! 637: /* ! 638: * Accumulate times for dead threads into task. ! 639: */ ! 640: thread_read_times(thread, &user_time, &system_time); ! 641: ! 642: task_lock(task); ! 643: time_value_add(&task->total_user_time, &user_time); ! 644: time_value_add(&task->total_system_time, &system_time); ! 645: if (task->thr_act_count == 1) ! 646: proc = task->bsd_info; ! 647: task_unlock(task); ! 648: ! 649: if (proc) ! 650: proc_exit(proc); ! 651: } ! 652: ! 653: thread = act_lock_thread(thr_act); ! 654: ! 655: /* Unlink the thr_act from the task's thr_act list, ! 656: * so it doesn't appear in calls to task_threads and such. ! 657: * The thr_act still keeps its ref on the task, however. ! 658: */ ! 659: task_lock(task); ! 660: mutex_lock(&task->act_list_lock); ! 661: queue_remove(&task->thr_acts, thr_act, thread_act_t, thr_acts); ! 662: ! 663: /* ! 664: * Decrement the act count for this task. ! 665: */ ! 666: task->thr_act_count--; ! 667: ! 668: #if THREAD_SWAPPER ! 669: /* ! 670: * Thread is supposed to be unswappable by now... ! 671: */ ! 672: assert(thr_act->swap_state == TH_SW_UNSWAPPABLE || ! 673: !(thread_swap_unwire_stack || ! 674: thread_swap_unwire_user_stack)); ! 675: #endif /* THREAD_SWAPPER */ ! 676: task->res_act_count--; ! 677: thr_act->thr_acts.next = NULL; ! 678: mutex_unlock(&task->act_list_lock); ! 679: task_unlock(task); ! 680: ! 681: #ifdef CALLOUT_RPC_MODEL ! 682: if (thr_act->lower) { ! 683: /* ! 684: * JMM - RPC will not be using a callout/stack manipulation ! 685: * mechanism. instead we will let it return normally as if ! 686: * from a continuation. Accordingly, these need to be cleaned ! 687: * up a bit. ! 688: */ ! 689: act_unlock(thr_act); ! 690: act_switch_swapcheck(thread, (ipc_port_t)0); ! 691: act_lock(thr_act); /* hierarchy violation XXX */ ! 692: (void) switch_act(THR_ACT_NULL); ! 693: assert(thr_act->ref_count == 1); /* XXX */ ! 694: /* act_deallocate(thr_act); XXX */ ! 695: prev_act = thread->top_act; ! 696: /* disable preemption to protect kernel stack changes */ ! 697: disable_preemption(); ! 698: MACH_RPC_RET(prev_act) = KERN_RPC_SERVER_TERMINATED; ! 699: * machine_kernel_stack_init(thread, ! 700: * (void (*)(void)) mach_rpc_return_error); ! 701: * Load_context(thread); ! 702: */ ! 703: /* NOTREACHED */ ! 704: } ! 705: ! 706: #else /* !CALLOUT_RPC_MODEL */ ! 707: ! 708: assert(!thr_act->lower); ! 709: ! 710: #endif /* CALLOUT_RPC_MODEL */ ! 711: ! 712: act_unlock_thread(thr_act); ! 713: ! 714: s = splsched(); ! 715: thread_lock(thread); ! 716: policy = &sched_policy[thread->policy]; ! 717: thr_act = thread->top_act; ! 718: thread->active = FALSE; ! 719: thread_unlock(thread); ! 720: splx(s); ! 721: ! 722: policy->sp_ops.sp_thread_depress_abort(policy, thread); ! 723: thread_cancel_timer(); ! 724: ! 725: /* flush any lazy HW state while in own context */ ! 726: thread_machine_flush(thr_act); ! 727: ! 728: /* Reap times from dying threads */ ! 729: ipc_thr_act_disable(thr_act); ! 730: ! 731: /* ! 732: * the test for task_active seems unnecessary because ! 733: * the thread holds a reference to the task (so it ! 734: * can't be deleted out from under it). ! 735: */ ! 736: if( task && task->active) { ! 737: #if THREAD_SWAPPER ! 738: thread_swap_disable(thr_act); ! 739: #endif /* THREAD_SWAPPER */ ! 740: ! 741: task_lock(task); ! 742: ! 743: /* Make act inactive iff it was born as a base activation */ ! 744: act_lock_thread(thr_act); ! 745: if( thr_act->active && (thr_act->pool_port == IP_NULL)) ! 746: act_disable_task_locked( thr_act ); ! 747: act_unlock_thread(thr_act); ! 748: task_unlock( task ); ! 749: } ! 750: ! 751: thread_deallocate(thread); /* take caller's ref; 1 left for reaper */ ! 752: ! 753: ipc_thread_terminate(thread); ! 754: ! 755: s = splsched(); ! 756: thread_lock(thread); ! 757: thread->state |= (TH_HALTED|TH_TERMINATE); ! 758: assert((thread->state & TH_UNINT) == 0); ! 759: #if 0 /* CHECKME! */ ! 760: /* ! 761: * Since thread has been put in the reaper_queue, it must no longer ! 762: * be preempted (otherwise, it could be put back in a run queue). ! 763: */ ! 764: thread->preempt = TH_NOT_PREEMPTABLE; ! 765: #endif ! 766: thread_mark_wait_locked(thread); ! 767: thread_unlock(thread); ! 768: /* splx(s); */ ! 769: ! 770: ETAP_SET_REASON(thread, BLOCKED_ON_TERMINATION); ! 771: thread_block((void (*)(void)) 0); ! 772: panic("the zombie walks!"); ! 773: /*NOTREACHED*/ ! 774: } ! 775: ! 776: ! 777: /* ! 778: * Create a new thread in the specified activation (i.e. "populate" the ! 779: * activation). The activation can be either user or kernel, but it must ! 780: * be brand-new: no thread, no pool_port, nobody else knows about it. ! 781: * Doesn't start the thread running; use thread_setrun to start it. ! 782: */ ! 783: kern_return_t ! 784: thread_create_shuttle( ! 785: thread_act_t thr_act, ! 786: sp_attributes_t attributes, ! 787: void (*start_at)(void), ! 788: thread_t *new_thread) ! 789: { ! 790: thread_t new_shuttle; ! 791: task_t parent_task = thr_act->task; ! 792: processor_set_t pset; ! 793: kern_return_t result; ! 794: sched_policy_t *policy; ! 795: sf_return_t sfr; ! 796: int suspcnt; ! 797: ! 798: /* ! 799: * Allocate a thread and initialize static fields ! 800: */ ! 801: new_shuttle = (thread_t)zalloc(thread_shuttle_zone); ! 802: if (new_shuttle == THREAD_NULL) ! 803: return (KERN_RESOURCE_SHORTAGE); ! 804: ! 805: *new_shuttle = thr_sh_template; ! 806: ! 807: /* Allocate space for scheduling information and attributes */ ! 808: /*** Think about integrating with shuttle structure someday ***/ ! 809: new_shuttle->sp_info = (sp_info_t)kalloc(max_sched_info_size); ! 810: if (new_shuttle->sp_info == SP_INFO_NULL) { ! 811: zfree(thread_shuttle_zone, (vm_offset_t)new_shuttle); ! 812: return (KERN_RESOURCE_SHORTAGE); ! 813: } ! 814: new_shuttle->pending_sched_attr = ! 815: (sp_attributes_t)kalloc(max_sched_attributes_size); ! 816: if (new_shuttle->pending_sched_attr == SP_ATTRIBUTES_NULL) { ! 817: kfree((vm_offset_t)new_shuttle->sp_info, ! 818: (vm_size_t)max_sched_info_size); ! 819: zfree(thread_shuttle_zone, (vm_offset_t)new_shuttle); ! 820: return (KERN_RESOURCE_SHORTAGE); ! 821: } ! 822: ! 823: thread_lock_init(new_shuttle); ! 824: rpc_lock_init(new_shuttle); ! 825: wake_lock_init(new_shuttle); ! 826: new_shuttle->sleep_stamp = sched_tick; ! 827: ! 828: /* ! 829: * No need to lock thr_act, since it can't be known to anyone -- ! 830: * we set its suspend_count to one more than the task suspend_count ! 831: * by calling thread_hold. ! 832: */ ! 833: thr_act->user_stop_count = 1; ! 834: for (suspcnt = thr_act->task->suspend_count + 1; suspcnt; --suspcnt) ! 835: thread_hold(thr_act); ! 836: ! 837: simple_lock_init(&new_shuttle->lock, ETAP_THREAD_NEW); ! 838: ! 839: /* ! 840: * Initialize system-dependent part. ! 841: */ ! 842: result = thread_machine_create(new_shuttle, thr_act, start_at); ! 843: if (result != KERN_SUCCESS) { ! 844: kfree((vm_offset_t)new_shuttle->pending_sched_attr, ! 845: (vm_size_t)max_sched_attributes_size); ! 846: kfree((vm_offset_t)new_shuttle->sp_info, ! 847: (vm_size_t)max_sched_info_size); ! 848: zfree(thread_shuttle_zone, (vm_offset_t)new_shuttle); ! 849: return (result); ! 850: } ! 851: ! 852: /* Attach the thread to the activation. */ ! 853: assert(!thr_act->thread); ! 854: assert(!thr_act->pool_port); ! 855: /* Synchronize with act_lock_thread() et al. */ ! 856: act_lock(thr_act); ! 857: /* Thread holds a ref to the thr_act */ ! 858: act_locked_act_reference(thr_act); ! 859: act_attach(thr_act, new_shuttle, 0); ! 860: act_unlock(thr_act); ! 861: ! 862: /* ! 863: * Initialize runtime-dependent fields ! 864: */ ! 865: thread_timer_setup(new_shuttle); ! 866: machine_kernel_stack_init(new_shuttle, (void (*)(void))thread_continue); ! 867: ipc_thread_init(new_shuttle); ! 868: thread_start(new_shuttle, start_at); ! 869: ! 870: pset = parent_task->processor_set; ! 871: if (!pset->active) { ! 872: pset = &default_pset; ! 873: } ! 874: pset_lock(pset); ! 875: ! 876: task_lock(parent_task); ! 877: ! 878: if (attributes == SP_ATTRIBUTES_NULL) ! 879: attributes = parent_task->sp_attributes; ! 880: ! 881: /* Associate the thread with that scheduling policy */ ! 882: new_shuttle->policy = attributes->policy_id; ! 883: policy = &sched_policy[new_shuttle->policy]; ! 884: sfr = policy->sp_ops.sp_thread_attach(policy, new_shuttle); ! 885: if (sfr != SF_SUCCESS) ! 886: panic("thread_create_shuttle: sp_thread_attach"); ! 887: ! 888: /* Indicate that no change in scheduling policy is pending */ ! 889: new_shuttle->pending_policy = POLICY_NULL; ! 890: ! 891: /* Associate the thread with the processor set */ ! 892: sfr = policy->sp_ops.sp_thread_processor_set(policy, new_shuttle, pset); ! 893: if (sfr != SF_SUCCESS) ! 894: panic("thread_create_shuttle: sp_thread_proceessor_set"); ! 895: ! 896: /* Set the thread's scheduling parameters */ ! 897: sfr = policy->sp_ops.sp_thread_set(policy, new_shuttle, attributes); ! 898: if (sfr != SF_SUCCESS) ! 899: panic("thread_create_shuttle: sp_thread_set"); ! 900: ! 901: /*** ! 902: *** ??? Have to do something here. I want the call above to ! 903: *** send the parameters to the policy and have the policy do ! 904: *** its thing. Unfortunately, I can't see the "artful" way ! 905: *** to use the current MK SP routines to do this without ! 906: *** alteration. ! 907: *** ! 908: *** I must return to this. ! 909: *** ! 910: *** Perhaps a state bit should be associated with each thread ! 911: *** under the MK SP indicating whether that thread is runnable. ! 912: *** If it is not, `compute_priority()' or one of its siblings ! 913: *** is used to adjust scheduling parameter values; if it is ! 914: *** runnable, then the scheduling parameter adjustments can be ! 915: *** followed by code that tries to place the thread on the ! 916: *** appropriate run queue, or tries to run it immediately. ! 917: ***/ ! 918: ! 919: #if ETAP_EVENT_MONITOR ! 920: new_thread->etap_reason = 0; ! 921: new_thread->etap_trace = FALSE; ! 922: #endif /* ETAP_EVENT_MONITOR */ ! 923: ! 924: new_shuttle->active = TRUE; ! 925: ! 926: /* ! 927: * Don't need to initialize because the context switch ! 928: * code will set it before it can be used. ! 929: */ ! 930: if (!parent_task->active) { ! 931: task_unlock(parent_task); ! 932: pset_unlock(pset); ! 933: thread_deallocate(new_shuttle); ! 934: /* Drop ref we'd have given caller */ ! 935: thread_deallocate(new_shuttle); ! 936: ! 937: return (KERN_FAILURE); ! 938: } ! 939: ! 940: task_unlock(parent_task); ! 941: pset_unlock(pset); ! 942: ! 943: *new_thread = new_shuttle; ! 944: ! 945: { ! 946: long dbg_arg1, dbg_arg2, dbg_arg3, dbg_arg4; ! 947: ! 948: KERNEL_DEBUG_CONSTANT((TRACEDBG_CODE(DBG_TRACE_DATA, 1)) | DBG_FUNC_NONE, ! 949: new_shuttle, 0,0,0,0); ! 950: ! 951: kdbg_trace_string(parent_task->bsd_info, &dbg_arg1, &dbg_arg2, &dbg_arg3, ! 952: &dbg_arg4); ! 953: KERNEL_DEBUG_CONSTANT((TRACEDBG_CODE(DBG_TRACE_STRING, 1)) | DBG_FUNC_NONE, ! 954: dbg_arg1, dbg_arg2, dbg_arg3, dbg_arg4, 0); ! 955: } ! 956: ! 957: return (KERN_SUCCESS); ! 958: } ! 959: ! 960: kern_return_t ! 961: thread_create( ! 962: task_t task, ! 963: thread_act_t *new_act) ! 964: { ! 965: thread_act_t thr_act; ! 966: thread_t thread; ! 967: kern_return_t result; ! 968: sched_policy_t *policy; ! 969: sf_return_t sfr; ! 970: spl_t s; ! 971: extern void thread_bootstrap_return(void); ! 972: ! 973: result = act_create(task, NULL_PARAMS, &thr_act); ! 974: if (result != KERN_SUCCESS) ! 975: return (result); ! 976: ! 977: result = thread_create_shuttle(thr_act, SP_ATTRIBUTES_NULL, ! 978: thread_bootstrap_return, &thread); ! 979: if (result != KERN_SUCCESS) { ! 980: thread_terminate(thr_act); ! 981: act_deallocate(thr_act); ! 982: return (result); ! 983: } ! 984: ! 985: if (task->kernel_loaded) ! 986: thread_user_to_kernel(thread); ! 987: ! 988: /* Start the thread running (it will immediately suspend itself). */ ! 989: s = splsched(); ! 990: thread_ast_set(thr_act, AST_APC); ! 991: thread_lock(thread); ! 992: thread->state |= TH_RUN; /*** ??? I think this is okay ***/ ! 993: ! 994: /* Allow the thread to execute */ ! 995: policy = &sched_policy[thread->policy]; ! 996: sfr = policy->sp_ops.sp_thread_dispatch(policy, thread); ! 997: if (sfr != SF_SUCCESS) ! 998: panic("thread_create: sp_thread_dispatch"); ! 999: ! 1000: thread_unlock(thread); ! 1001: splx(s); ! 1002: ! 1003: /***** ! 1004: act_lock_thread(thr_act); ! 1005: thread_dowait( thr_act, FALSE); ! 1006: act_unlock_thread(thr_act); ! 1007: *****/ ! 1008: ! 1009: *new_act = thr_act; ! 1010: ! 1011: return (KERN_SUCCESS); ! 1012: } ! 1013: ! 1014: /* ! 1015: * Update thread that belongs to a task created via kernel_task_create(). ! 1016: */ ! 1017: void ! 1018: thread_user_to_kernel( ! 1019: thread_t thread) ! 1020: { ! 1021: /* ! 1022: * Used to set special swap_func here... ! 1023: */ ! 1024: } ! 1025: ! 1026: kern_return_t ! 1027: thread_create_running( ! 1028: register task_t parent_task, ! 1029: int flavor, ! 1030: thread_state_t new_state, ! 1031: mach_msg_type_number_t new_state_count, ! 1032: thread_act_t *child_act) /* OUT */ ! 1033: { ! 1034: register kern_return_t result; ! 1035: ! 1036: result = thread_create(parent_task, child_act); ! 1037: if (result != KERN_SUCCESS) ! 1038: return (result); ! 1039: ! 1040: result = act_set_state(*child_act, flavor, new_state, new_state_count); ! 1041: if (result != KERN_SUCCESS) { ! 1042: (void) thread_terminate(*child_act); ! 1043: return (result); ! 1044: } ! 1045: ! 1046: result = thread_resume(*child_act); ! 1047: if (result != KERN_SUCCESS) { ! 1048: (void) thread_terminate(*child_act); ! 1049: return (result); ! 1050: } ! 1051: ! 1052: return (result); ! 1053: } ! 1054: ! 1055: /* ! 1056: * kernel_thread: ! 1057: * ! 1058: * Create and kernel thread in the specified task, and ! 1059: * optionally start it running. ! 1060: */ ! 1061: thread_t ! 1062: kernel_thread_with_attributes( ! 1063: task_t task, ! 1064: sp_attributes_t attributes, ! 1065: void (*start_at)(void), ! 1066: boolean_t start_running) ! 1067: { ! 1068: kern_return_t result; ! 1069: thread_t thread; ! 1070: thread_act_t thr_act; ! 1071: sched_policy_t *policy; ! 1072: sf_return_t sfr; ! 1073: spl_t s; ! 1074: ! 1075: result = act_create(task, NULL_PARAMS, &thr_act); ! 1076: if (result != KERN_SUCCESS) { ! 1077: printf("kernel_thread act_create %x\n", result); ! 1078: panic("act_create failure"); ! 1079: } ! 1080: ! 1081: result = thread_create_shuttle(thr_act, attributes, start_at, &thread); ! 1082: if (result != KERN_SUCCESS) { ! 1083: printf("kernel_thread create_shuttle %x\n", result); ! 1084: panic("create_shuttle failure"); ! 1085: } ! 1086: ! 1087: thread_swappable(thr_act, FALSE); ! 1088: ! 1089: s = splsched(); ! 1090: thread_lock(thread); ! 1091: ! 1092: thr_act = thread->top_act; ! 1093: #if MACH_LDEBUG ! 1094: thread->kthread = TRUE; ! 1095: #endif /* MACH_LDEBUG */ ! 1096: ! 1097: if (start_running) { ! 1098: policy = &sched_policy[thread->policy]; ! 1099: thread->state |= TH_RUN; ! 1100: sfr = policy->sp_ops.sp_thread_unblock(policy, thread); ! 1101: if (sfr != SF_SUCCESS) ! 1102: panic("kernel_thread: sp_thread_unblock"); ! 1103: } ! 1104: ! 1105: thread_unlock(thread); ! 1106: splx(s); ! 1107: ! 1108: act_deallocate(thr_act); ! 1109: ! 1110: if (start_running) ! 1111: thread_resume(thr_act); ! 1112: ! 1113: return (thread); ! 1114: } ! 1115: ! 1116: thread_t ! 1117: kernel_thread( ! 1118: task_t task, ! 1119: void (*start_at)(void)) ! 1120: { ! 1121: return kernel_thread_with_attributes( ! 1122: task, SP_ATTRIBUTES_NULL, start_at, TRUE); ! 1123: } ! 1124: ! 1125: unsigned int c_weird_pset_ref_exit = 0; /* pset code raced us */ ! 1126: ! 1127: void ! 1128: thread_deallocate( ! 1129: thread_t thread) ! 1130: { ! 1131: task_t task; ! 1132: processor_set_t pset; ! 1133: sched_policy_t *policy; ! 1134: sf_return_t sfr; ! 1135: spl_t s; ! 1136: ! 1137: if (thread == THREAD_NULL) ! 1138: return; ! 1139: ! 1140: /* ! 1141: * First, check for new count > 0 (the common case). ! 1142: * Only the thread needs to be locked. ! 1143: */ ! 1144: s = splsched(); ! 1145: thread_lock(thread); ! 1146: if (--thread->ref_count > 0) { ! 1147: thread_unlock(thread); ! 1148: splx(s); ! 1149: return; ! 1150: } ! 1151: ! 1152: /* ! 1153: * Count is zero. However, the processor set's ! 1154: * thread list has an implicit reference to ! 1155: * the thread, and may make new ones. Its lock also ! 1156: * dominate the thread lock. To check for this, we ! 1157: * temporarily restore the one thread reference, unlock ! 1158: * the thread, and then lock the pset in the proper order. ! 1159: */ ! 1160: assert(thread->ref_count == 0); /* Else this is an extra dealloc! */ ! 1161: thread->ref_count++; ! 1162: thread_unlock(thread); ! 1163: splx(s); ! 1164: ! 1165: #if MACH_HOST ! 1166: thread_freeze(thread); ! 1167: #endif /* MACH_HOST */ ! 1168: ! 1169: pset = thread->processor_set; ! 1170: pset_lock(pset); ! 1171: ! 1172: s = splsched(); ! 1173: thread_lock(thread); ! 1174: ! 1175: if (--thread->ref_count > 0) { ! 1176: #if MACH_HOST ! 1177: boolean_t need_wakeup = FALSE; ! 1178: /* ! 1179: * processor_set made extra reference. ! 1180: */ ! 1181: /* Inline the unfreeze */ ! 1182: thread->may_assign = TRUE; ! 1183: if (thread->assign_active) { ! 1184: need_wakeup = TRUE; ! 1185: thread->assign_active = FALSE; ! 1186: } ! 1187: #endif /* MACH_HOST */ ! 1188: thread_unlock(thread); ! 1189: splx(s); ! 1190: pset_unlock(pset); ! 1191: #if MACH_HOST ! 1192: if (need_wakeup) ! 1193: thread_wakeup((event_t)&thread->assign_active); ! 1194: #endif /* MACH_HOST */ ! 1195: c_weird_pset_ref_exit++; ! 1196: return; ! 1197: } ! 1198: #if MACH_HOST ! 1199: assert(thread->assign_active == FALSE); ! 1200: #endif /* MACH_HOST */ ! 1201: ! 1202: /* ! 1203: * Thread has no references - we can remove it. ! 1204: */ ! 1205: ! 1206: /* ! 1207: * A quick sanity check ! 1208: */ ! 1209: if (thread == current_thread()) ! 1210: panic("thread deallocating itself"); ! 1211: ! 1212: /* Detach thread (shuttle) from its sched policy */ ! 1213: policy = &sched_policy[thread->policy]; ! 1214: sfr = policy->sp_ops.sp_thread_detach(policy, thread); ! 1215: if (sfr != SF_SUCCESS) ! 1216: panic("thread_deallocate: sp_thread_detach"); ! 1217: ! 1218: /* Release storage used for scheduling info and attributes */ ! 1219: assert(thread->pending_sched_attr != SP_ATTRIBUTES_NULL); ! 1220: kfree((vm_offset_t) thread->pending_sched_attr, ! 1221: (vm_size_t) max_sched_attributes_size); ! 1222: assert(thread->sp_info != SP_INFO_NULL); ! 1223: kfree((vm_offset_t) thread->sp_info, ! 1224: (vm_size_t) max_sched_info_size); ! 1225: ! 1226: pset_remove_thread(pset, thread); ! 1227: ! 1228: thread_unlock(thread); /* no more references - safe */ ! 1229: splx(s); ! 1230: pset_unlock(pset); ! 1231: ! 1232: pset_deallocate(thread->processor_set); ! 1233: ! 1234: /* frees kernel stack & other MD resources */ ! 1235: thread->stack_privilege = 0; ! 1236: thread_machine_destroy(thread); ! 1237: ! 1238: zfree(thread_shuttle_zone, (vm_offset_t) thread); ! 1239: } ! 1240: ! 1241: void ! 1242: thread_reference( ! 1243: thread_t thread) ! 1244: { ! 1245: spl_t s; ! 1246: ! 1247: if (thread == THREAD_NULL) ! 1248: return; ! 1249: ! 1250: s = splsched(); ! 1251: thread_lock(thread); ! 1252: thread->ref_count++; ! 1253: thread_unlock(thread); ! 1254: splx(s); ! 1255: } ! 1256: ! 1257: /* ! 1258: * Called with "appropriate" thread-related locks held on ! 1259: * thread and its top_act for synchrony with RPC (see ! 1260: * act_lock_thread()). ! 1261: */ ! 1262: kern_return_t ! 1263: thread_info_shuttle( ! 1264: register thread_act_t thr_act, ! 1265: thread_flavor_t flavor, ! 1266: thread_info_t thread_info_out, /* ptr to OUT array */ ! 1267: mach_msg_type_number_t *thread_info_count) /*IN/OUT*/ ! 1268: { ! 1269: register thread_t thread = thr_act->thread; ! 1270: int state, flags; ! 1271: spl_t s; ! 1272: ! 1273: if (thread == THREAD_NULL) ! 1274: return (KERN_INVALID_ARGUMENT); ! 1275: ! 1276: if (flavor == THREAD_BASIC_INFO) { ! 1277: register thread_basic_info_t basic_info; ! 1278: ! 1279: if (*thread_info_count < THREAD_BASIC_INFO_COUNT) ! 1280: return (KERN_INVALID_ARGUMENT); ! 1281: ! 1282: basic_info = (thread_basic_info_t) thread_info_out; ! 1283: ! 1284: s = splsched(); ! 1285: thread_lock(thread); ! 1286: ! 1287: /* fill in info */ ! 1288: ! 1289: thread_read_times(thread, &basic_info->user_time, ! 1290: &basic_info->system_time); ! 1291: ! 1292: /*** ??? fix me ***/ ! 1293: if (thread->policy & (POLICY_TIMESHARE|POLICY_RR|POLICY_FIFO)) { ! 1294: mk_sp_info_t sp_info = (mk_sp_info_t)thread->sp_info; ! 1295: ! 1296: /* ! 1297: * Update lazy-evaluated scheduler info because someone wants it. ! 1298: */ ! 1299: assert(sp_info != SP_INFO_NULL); ! 1300: if (sp_info->sched_stamp != sched_tick) ! 1301: update_priority(thread); ! 1302: ! 1303: basic_info->sleep_time = 0; ! 1304: ! 1305: /* ! 1306: * To calculate cpu_usage, first correct for timer rate, ! 1307: * then for 5/8 ageing. The correction factor [3/5] is ! 1308: * (1/(5/8) - 1). ! 1309: */ ! 1310: basic_info->cpu_usage = sp_info->cpu_usage / ! 1311: (TIMER_RATE / TH_USAGE_SCALE); ! 1312: basic_info->cpu_usage = (basic_info->cpu_usage * 3) / 5; ! 1313: #if SIMPLE_CLOCK ! 1314: /* ! 1315: * Clock drift compensation. ! 1316: */ ! 1317: basic_info->cpu_usage = ! 1318: (basic_info->cpu_usage * 1000000) / sched_usec; ! 1319: #endif /* SIMPLE_CLOCK */ ! 1320: } ! 1321: else ! 1322: basic_info->sleep_time = basic_info->cpu_usage = 0; ! 1323: ! 1324: basic_info->policy = thread->policy; ! 1325: ! 1326: flags = 0; ! 1327: if (thread->state & TH_SWAPPED_OUT) ! 1328: flags = TH_FLAGS_SWAPPED; ! 1329: else ! 1330: if (thread->state & TH_IDLE) ! 1331: flags = TH_FLAGS_IDLE; ! 1332: ! 1333: state = 0; ! 1334: if (thread->state & TH_HALTED) ! 1335: state = TH_STATE_HALTED; ! 1336: else ! 1337: if (thread->state & TH_RUN) ! 1338: state = TH_STATE_RUNNING; ! 1339: else ! 1340: if (thread->state & TH_UNINT) ! 1341: state = TH_STATE_UNINTERRUPTIBLE; ! 1342: else ! 1343: if (thread->state & TH_SUSP) ! 1344: state = TH_STATE_STOPPED; ! 1345: else ! 1346: if (thread->state & TH_WAIT) ! 1347: state = TH_STATE_WAITING; ! 1348: ! 1349: basic_info->run_state = state; ! 1350: basic_info->flags = flags; ! 1351: ! 1352: basic_info->suspend_count = thr_act->user_stop_count; ! 1353: ! 1354: thread_unlock(thread); ! 1355: splx(s); ! 1356: ! 1357: *thread_info_count = THREAD_BASIC_INFO_COUNT; ! 1358: ! 1359: return (KERN_SUCCESS); ! 1360: } ! 1361: else ! 1362: if (flavor == THREAD_SCHED_TIMESHARE_INFO) { ! 1363: policy_timeshare_info_t ts_info; ! 1364: mk_sp_info_t sp_info = (mk_sp_info_t)thread->sp_info; ! 1365: ! 1366: if (*thread_info_count < POLICY_TIMESHARE_INFO_COUNT) ! 1367: return (KERN_INVALID_ARGUMENT); ! 1368: ! 1369: ts_info = (policy_timeshare_info_t)thread_info_out; ! 1370: ! 1371: s = splsched(); ! 1372: thread_lock(thread); ! 1373: ! 1374: if (thread->policy != POLICY_TIMESHARE) { ! 1375: thread_unlock(thread); ! 1376: splx(s); ! 1377: ! 1378: return (KERN_INVALID_POLICY); ! 1379: } ! 1380: ! 1381: /*** ??? fix me ***/ ! 1382: assert(sp_info != SP_INFO_NULL); ! 1383: ts_info->base_priority = sp_info->priority; ! 1384: ts_info->max_priority = sp_info->max_priority; ! 1385: ts_info->cur_priority = thread->sched_pri; ! 1386: ! 1387: ts_info->depressed = (sp_info->depress_priority >= 0); ! 1388: ts_info->depress_priority = sp_info->depress_priority; ! 1389: ! 1390: thread_unlock(thread); ! 1391: splx(s); ! 1392: ! 1393: *thread_info_count = POLICY_TIMESHARE_INFO_COUNT; ! 1394: ! 1395: return (KERN_SUCCESS); ! 1396: } ! 1397: else ! 1398: if (flavor == THREAD_SCHED_FIFO_INFO) { ! 1399: policy_fifo_info_t fifo_info; ! 1400: mk_sp_info_t sp_info = (mk_sp_info_t)thread->sp_info; ! 1401: ! 1402: if (*thread_info_count < POLICY_FIFO_INFO_COUNT) ! 1403: return (KERN_INVALID_ARGUMENT); ! 1404: ! 1405: fifo_info = (policy_fifo_info_t)thread_info_out; ! 1406: ! 1407: s = splsched(); ! 1408: thread_lock(thread); ! 1409: ! 1410: if (thread->policy != POLICY_FIFO) { ! 1411: thread_unlock(thread); ! 1412: splx(s); ! 1413: ! 1414: return (KERN_INVALID_POLICY); ! 1415: } ! 1416: ! 1417: /*** ??? fix me ***/ ! 1418: assert(sp_info != SP_INFO_NULL); ! 1419: fifo_info->base_priority = sp_info->priority; ! 1420: fifo_info->max_priority = sp_info->max_priority; ! 1421: ! 1422: fifo_info->depressed = (sp_info->depress_priority >= 0); ! 1423: fifo_info->depress_priority = sp_info->depress_priority; ! 1424: ! 1425: thread_unlock(thread); ! 1426: splx(s); ! 1427: ! 1428: *thread_info_count = POLICY_FIFO_INFO_COUNT; ! 1429: ! 1430: return (KERN_SUCCESS); ! 1431: } ! 1432: else ! 1433: if (flavor == THREAD_SCHED_RR_INFO) { ! 1434: policy_rr_info_t rr_info; ! 1435: mk_sp_info_t sp_info = (mk_sp_info_t)thread->sp_info; ! 1436: ! 1437: if (*thread_info_count < POLICY_RR_INFO_COUNT) ! 1438: return (KERN_INVALID_ARGUMENT); ! 1439: ! 1440: rr_info = (policy_rr_info_t) thread_info_out; ! 1441: ! 1442: s = splsched(); ! 1443: thread_lock(thread); ! 1444: ! 1445: if (thread->policy != POLICY_RR) { ! 1446: thread_unlock(thread); ! 1447: splx(s); ! 1448: ! 1449: return (KERN_INVALID_POLICY); ! 1450: } ! 1451: ! 1452: /*** ??? fix me ***/ ! 1453: assert(sp_info != SP_INFO_NULL); ! 1454: rr_info->base_priority = sp_info->priority; ! 1455: rr_info->max_priority = sp_info->max_priority; ! 1456: ! 1457: rr_info->quantum = (sp_info->sched_data * tick) / 1000; ! 1458: ! 1459: rr_info->depressed = (sp_info->depress_priority >= 0); ! 1460: rr_info->depress_priority = sp_info->depress_priority; ! 1461: ! 1462: thread_unlock(thread); ! 1463: splx(s); ! 1464: ! 1465: *thread_info_count = POLICY_RR_INFO_COUNT; ! 1466: ! 1467: return (KERN_SUCCESS); ! 1468: } ! 1469: ! 1470: return (KERN_INVALID_ARGUMENT); ! 1471: } ! 1472: ! 1473: void ! 1474: thread_doreap( ! 1475: register thread_t thread) ! 1476: { ! 1477: thread_act_t thr_act; ! 1478: struct ipc_port *pool_port; ! 1479: ! 1480: ! 1481: thr_act = thread_lock_act(thread); ! 1482: assert(thr_act && thr_act->thread == thread); ! 1483: ! 1484: act_locked_act_reference(thr_act); ! 1485: pool_port = thr_act->pool_port; ! 1486: ! 1487: /* ! 1488: * Replace `act_unlock_thread()' with individual ! 1489: * calls. (`act_detach()' can change fields used ! 1490: * to determine which locks are held, confusing ! 1491: * `act_unlock_thread()'.) ! 1492: */ ! 1493: rpc_unlock(thread); ! 1494: if (pool_port != IP_NULL) ! 1495: ip_unlock(pool_port); ! 1496: act_unlock(thr_act); ! 1497: ! 1498: /* Remove the reference held by a rooted thread */ ! 1499: if (pool_port == IP_NULL) ! 1500: act_deallocate(thr_act); ! 1501: ! 1502: /* Remove the reference held by the thread: */ ! 1503: act_deallocate(thr_act); ! 1504: } ! 1505: ! 1506: static thread_call_data_t thread_reaper_call_data; ! 1507: ! 1508: /* ! 1509: * reaper_thread: ! 1510: * ! 1511: * This kernel thread runs forever looking for threads to destroy ! 1512: * (when they request that they be destroyed, of course). ! 1513: * ! 1514: * The reaper thread will disappear in the next revision of thread ! 1515: * control when it's function will be moved into thread_dispatch. ! 1516: */ ! 1517: void ! 1518: thread_reaper(void) ! 1519: { ! 1520: register thread_t thread; ! 1521: spl_t s; ! 1522: ! 1523: s = splsched(); ! 1524: simple_lock(&reaper_lock); ! 1525: ! 1526: if (thread_reaper_call == NULL) { ! 1527: thread_call_setup(&thread_reaper_call_data, thread_reaper, NULL); ! 1528: thread_reaper_call = &thread_reaper_call_data; ! 1529: } ! 1530: ! 1531: while ((thread = (thread_t) dequeue_head(&reaper_queue)) != THREAD_NULL) { ! 1532: simple_unlock(&reaper_lock); ! 1533: ! 1534: /* ! 1535: * wait for run bit to clear ! 1536: */ ! 1537: thread_lock(thread); ! 1538: if (thread->state & TH_RUN) ! 1539: panic("thread reaper: TH_RUN"); ! 1540: thread_unlock(thread); ! 1541: splx(s); ! 1542: ! 1543: thread_doreap(thread); ! 1544: ! 1545: s = splsched(); ! 1546: simple_lock(&reaper_lock); ! 1547: } ! 1548: ! 1549: simple_unlock(&reaper_lock); ! 1550: splx(s); ! 1551: } ! 1552: ! 1553: #if MACH_HOST ! 1554: /* ! 1555: * thread_assign: ! 1556: * ! 1557: * Change processor set assignment. ! 1558: * Caller must hold an extra reference to the thread (if this is ! 1559: * called directly from the ipc interface, this is an operation ! 1560: * in progress reference). Caller must hold no locks -- this may block. ! 1561: */ ! 1562: ! 1563: kern_return_t ! 1564: thread_assign( ! 1565: thread_act_t thr_act, ! 1566: processor_set_t new_pset) ! 1567: { ! 1568: thread_t thread; ! 1569: ! 1570: if (thr_act == THR_ACT_NULL || new_pset == PROCESSOR_SET_NULL) ! 1571: return(KERN_INVALID_ARGUMENT); ! 1572: thread = act_lock_thread(thr_act); ! 1573: if (thread == THREAD_NULL) { ! 1574: act_unlock_thread(thr_act); ! 1575: return(KERN_INVALID_ARGUMENT); ! 1576: } ! 1577: ! 1578: thread_freeze(thread); ! 1579: thread_doassign(thread, new_pset, TRUE); ! 1580: act_unlock_thread(thr_act); ! 1581: return(KERN_SUCCESS); ! 1582: } ! 1583: ! 1584: /* ! 1585: * thread_freeze: ! 1586: * ! 1587: * Freeze thread's assignment. Prelude to assigning thread. ! 1588: * Only one freeze may be held per thread. ! 1589: */ ! 1590: void ! 1591: thread_freeze( ! 1592: thread_t thread) ! 1593: { ! 1594: spl_t s; ! 1595: ! 1596: /* ! 1597: * Freeze the assignment, deferring to a prior freeze. ! 1598: */ ! 1599: ! 1600: s = splsched(); ! 1601: thread_lock(thread); ! 1602: while (thread->may_assign == FALSE) { ! 1603: thread->assign_active = TRUE; ! 1604: thread_sleep_simple_lock((event_t) &thread->assign_active, ! 1605: simple_lock_addr(thread->lock), TRUE); ! 1606: thread_lock(thread); ! 1607: } ! 1608: thread->may_assign = FALSE; ! 1609: thread_unlock(thread); ! 1610: splx(s); ! 1611: ! 1612: } ! 1613: ! 1614: /* ! 1615: * thread_unfreeze: release freeze on thread's assignment. ! 1616: */ ! 1617: void ! 1618: thread_unfreeze( ! 1619: thread_t thread) ! 1620: { ! 1621: spl_t s; ! 1622: ! 1623: s = splsched(); ! 1624: thread_lock(thread); ! 1625: thread->may_assign = TRUE; ! 1626: if (thread->assign_active) { ! 1627: thread->assign_active = FALSE; ! 1628: thread_unlock(thread); ! 1629: splx(s); ! 1630: thread_wakeup((event_t)&thread->assign_active); ! 1631: return; ! 1632: } ! 1633: thread_unlock(thread); ! 1634: splx(s); ! 1635: } ! 1636: ! 1637: /* ! 1638: * thread_doassign: ! 1639: * ! 1640: * Actually do thread assignment. thread_will_assign must have been ! 1641: * called on the thread. release_freeze argument indicates whether ! 1642: * to release freeze on thread. ! 1643: * ! 1644: * Called with "appropriate" thread-related locks held on thread (see ! 1645: * act_lock_thread()). Returns with thread unlocked. ! 1646: */ ! 1647: ! 1648: void ! 1649: thread_doassign( ! 1650: register thread_t thread, ! 1651: register processor_set_t new_pset, ! 1652: boolean_t release_freeze) ! 1653: { ! 1654: register boolean_t old_empty, new_empty; ! 1655: register processor_set_t pset; ! 1656: boolean_t recompute_pri = FALSE; ! 1657: int max_priority; ! 1658: spl_t s; ! 1659: thread_act_t thr_act = thread->top_act; ! 1660: ! 1661: /* ! 1662: * Check for silly no-op. ! 1663: */ ! 1664: pset = thread->processor_set; ! 1665: if (pset == new_pset) { ! 1666: if (release_freeze) ! 1667: thread_unfreeze(thread); ! 1668: return; ! 1669: } ! 1670: /* ! 1671: * Suspend the thread and stop it if it's not the current thread. ! 1672: */ ! 1673: thread_hold(thr_act); ! 1674: act_locked_act_reference(thr_act); ! 1675: act_unlock_thread(thr_act); ! 1676: if (thread != current_thread()) { ! 1677: if (thread_stop_wait(thread) == FALSE ){ ! 1678: (void)act_lock_thread(thr_act); ! 1679: thread_release(thr_act); ! 1680: act_locked_act_deallocate(thr_act); ! 1681: act_unlock_thread(thr_act); ! 1682: if (release_freeze ) ! 1683: thread_unfreeze(thread); ! 1684: return; ! 1685: } ! 1686: } ! 1687: /* ! 1688: * Had to release thread-related locks before acquiring pset ! 1689: * locks. ! 1690: */ ! 1691: ! 1692: /* ! 1693: * Lock both psets now, use ordering to avoid deadlocks. ! 1694: */ ! 1695: Restart: ! 1696: if (pset < new_pset) { ! 1697: pset_lock(pset); ! 1698: pset_lock(new_pset); ! 1699: } else { ! 1700: pset_lock(new_pset); ! 1701: pset_lock(pset); ! 1702: } ! 1703: ! 1704: /* ! 1705: * Check if new_pset is ok to assign to. If not, reassign ! 1706: * to default_pset. ! 1707: */ ! 1708: if (!new_pset->active) { ! 1709: pset_unlock(pset); ! 1710: pset_unlock(new_pset); ! 1711: new_pset = &default_pset; ! 1712: goto Restart; ! 1713: } ! 1714: ! 1715: /* ! 1716: * Grab the thread lock and move the thread. ! 1717: * Then drop the lock on the old pset and the thread's ! 1718: * reference to it. ! 1719: */ ! 1720: ! 1721: s = splsched(); ! 1722: thread_lock(thread); ! 1723: ! 1724: thread_change_psets(thread, pset, new_pset); ! 1725: ! 1726: old_empty = pset->empty; ! 1727: new_empty = new_pset->empty; ! 1728: ! 1729: pset_unlock(pset); ! 1730: pset_deallocate(pset); ! 1731: ! 1732: /* ! 1733: * Reset policy and priorities if needed. ! 1734: * ! 1735: * There are three rules for threads under assignment: ! 1736: * ! 1737: * (1) If the new pset has the old policy enabled, keep the ! 1738: * old policy. Otherwise, use the default policy for the pset. ! 1739: * (2) The new limits will be the pset limits for the new policy. ! 1740: * (3) The new base will be the same as the old base unless either ! 1741: * (a) the new policy changed to the pset default policy; ! 1742: * in this case, the new base is the default policy ! 1743: * base, ! 1744: * or ! 1745: * (b) the new limits are different from the old limits; ! 1746: * in this case, the new base is the new limits. ! 1747: */ ! 1748: /*** ??? fix me to fit into MK Scheduling Framework ***/ ! 1749: max_priority = pset_max_priority(new_pset, thread->policy); ! 1750: if ((thread->policy & new_pset->policies) == 0) { ! 1751: thread->policy = new_pset->policy_default; ! 1752: thread->sched_data = ! 1753: pset_sched_data(new_pset, thread->policy); ! 1754: thread->unconsumed_quantum = thread->sched_data; ! 1755: thread->priority = ! 1756: pset_base_priority(new_pset, thread->policy); ! 1757: max_priority = pset_max_priority(new_pset, thread->policy); ! 1758: recompute_pri = TRUE; ! 1759: } ! 1760: else if (thread->max_priority != max_priority) { ! 1761: thread->priority = max_priority; ! 1762: recompute_pri = TRUE; ! 1763: } ! 1764: ! 1765: thread->max_priority = max_priority; ! 1766: if ((thread->depress_priority >= 0) && ! 1767: (thread->depress_priority > thread->max_priority)) { ! 1768: thread->depress_priority = thread->max_priority; ! 1769: } ! 1770: ! 1771: pset_unlock(new_pset); ! 1772: ! 1773: if (recompute_pri) ! 1774: compute_priority(thread, TRUE); ! 1775: ! 1776: if (release_freeze) { ! 1777: boolean_t need_wakeup = FALSE; ! 1778: thread->may_assign = TRUE; ! 1779: if (thread->assign_active) { ! 1780: thread->assign_active = FALSE; ! 1781: need_wakeup = TRUE; ! 1782: } ! 1783: thread_unlock(thread); ! 1784: splx(s); ! 1785: if (need_wakeup) ! 1786: thread_wakeup((event_t)&thread->assign_active); ! 1787: } else { ! 1788: thread_unlock(thread); ! 1789: splx(s); ! 1790: } ! 1791: if (thread != current_thread()) ! 1792: thread_unstop(thread); ! 1793: /* ! 1794: * Figure out hold status of thread. Threads assigned to empty ! 1795: * psets must be held. Therefore: ! 1796: * If old pset was empty release its hold. ! 1797: * Release our hold from above unless new pset is empty. ! 1798: */ ! 1799: ! 1800: (void)act_lock_thread(thr_act); ! 1801: if (old_empty) ! 1802: thread_release(thr_act); ! 1803: if (!new_empty) ! 1804: thread_release(thr_act); ! 1805: act_locked_act_deallocate(thr_act); ! 1806: act_unlock_thread(thr_act); ! 1807: ! 1808: /* ! 1809: * If current_thread is assigned, context switch to force ! 1810: * assignment to happen. This also causes hold to take ! 1811: * effect if the new pset is empty. ! 1812: */ ! 1813: if (thread == current_thread()) { ! 1814: s = splsched(); ! 1815: mp_disable_preemption(); ! 1816: ast_on(AST_BLOCK); ! 1817: mp_enable_preemption(); ! 1818: splx(s); ! 1819: } ! 1820: } ! 1821: ! 1822: #else /* MACH_HOST */ ! 1823: ! 1824: kern_return_t ! 1825: thread_assign( ! 1826: thread_act_t thr_act, ! 1827: processor_set_t new_pset) ! 1828: { ! 1829: #ifdef lint ! 1830: thread++; new_pset++; ! 1831: #endif /* lint */ ! 1832: return(KERN_FAILURE); ! 1833: } ! 1834: #endif /* MACH_HOST */ ! 1835: ! 1836: /* ! 1837: * thread_assign_default: ! 1838: * ! 1839: * Special version of thread_assign for assigning threads to default ! 1840: * processor set. ! 1841: */ ! 1842: kern_return_t ! 1843: thread_assign_default( ! 1844: thread_act_t thr_act) ! 1845: { ! 1846: return (thread_assign(thr_act, &default_pset)); ! 1847: } ! 1848: ! 1849: /* ! 1850: * thread_get_assignment ! 1851: * ! 1852: * Return current assignment for this thread. ! 1853: */ ! 1854: kern_return_t ! 1855: thread_get_assignment( ! 1856: thread_act_t thr_act, ! 1857: processor_set_t *pset) ! 1858: { ! 1859: thread_t thread; ! 1860: ! 1861: if (thr_act == THR_ACT_NULL) ! 1862: return(KERN_INVALID_ARGUMENT); ! 1863: thread = act_lock_thread(thr_act); ! 1864: if (thread == THREAD_NULL) { ! 1865: act_unlock_thread(thr_act); ! 1866: return(KERN_INVALID_ARGUMENT); ! 1867: } ! 1868: *pset = thread->processor_set; ! 1869: act_unlock_thread(thr_act); ! 1870: pset_reference(*pset); ! 1871: return(KERN_SUCCESS); ! 1872: } ! 1873: ! 1874: /* ! 1875: * thread_wire: ! 1876: * ! 1877: * Specify that the target thread must always be able ! 1878: * to run and to allocate memory. ! 1879: */ ! 1880: kern_return_t ! 1881: thread_wire( ! 1882: host_t host, ! 1883: thread_act_t thr_act, ! 1884: boolean_t wired) ! 1885: { ! 1886: spl_t s; ! 1887: thread_t thread; ! 1888: extern void vm_page_free_reserve(int pages); ! 1889: ! 1890: if (thr_act == THR_ACT_NULL || host == HOST_NULL) ! 1891: return (KERN_INVALID_ARGUMENT); ! 1892: thread = act_lock_thread(thr_act); ! 1893: if (thread ==THREAD_NULL) { ! 1894: act_unlock_thread(thr_act); ! 1895: return(KERN_INVALID_ARGUMENT); ! 1896: } ! 1897: ! 1898: /* ! 1899: * This implementation only works for the current thread. ! 1900: * See stack_privilege. ! 1901: */ ! 1902: if (thr_act != current_act()) ! 1903: return KERN_INVALID_ARGUMENT; ! 1904: ! 1905: s = splsched(); ! 1906: thread_lock(thread); ! 1907: ! 1908: if (wired) { ! 1909: if (thread->vm_privilege == FALSE) ! 1910: vm_page_free_reserve(1); /* XXX */ ! 1911: thread->vm_privilege = TRUE; ! 1912: } else { ! 1913: if (thread->vm_privilege == TRUE) ! 1914: vm_page_free_reserve(-1); /* XXX */ ! 1915: thread->vm_privilege = FALSE; ! 1916: } ! 1917: ! 1918: thread_unlock(thread); ! 1919: splx(s); ! 1920: act_unlock_thread(thr_act); ! 1921: ! 1922: /* ! 1923: * Make the thread unswappable. ! 1924: */ ! 1925: thread_swappable(thr_act, FALSE); ! 1926: ! 1927: return KERN_SUCCESS; ! 1928: } ! 1929: ! 1930: /* ! 1931: * thread_collect_scan: ! 1932: * ! 1933: * Attempt to free resources owned by threads. ! 1934: */ ! 1935: ! 1936: void ! 1937: thread_collect_scan(void) ! 1938: { ! 1939: /* This code runs very quickly! */ ! 1940: } ! 1941: ! 1942: boolean_t thread_collect_allowed = TRUE; ! 1943: unsigned thread_collect_last_tick = 0; ! 1944: unsigned thread_collect_max_rate = 0; /* in ticks */ ! 1945: ! 1946: /* ! 1947: * consider_thread_collect: ! 1948: * ! 1949: * Called by the pageout daemon when the system needs more free pages. ! 1950: */ ! 1951: ! 1952: void ! 1953: consider_thread_collect(void) ! 1954: { ! 1955: /* ! 1956: * By default, don't attempt thread collection more frequently ! 1957: * than once a second (one scheduler tick). ! 1958: */ ! 1959: ! 1960: if (thread_collect_max_rate == 0) ! 1961: thread_collect_max_rate = 2; /* sched_tick is a 1 second resolution 2 here insures at least 1 second interval */ ! 1962: ! 1963: if (thread_collect_allowed && ! 1964: (sched_tick > ! 1965: (thread_collect_last_tick + thread_collect_max_rate))) { ! 1966: thread_collect_last_tick = sched_tick; ! 1967: thread_collect_scan(); ! 1968: } ! 1969: } ! 1970: ! 1971: #if MACH_DEBUG ! 1972: #if STACK_USAGE ! 1973: ! 1974: vm_size_t ! 1975: stack_usage( ! 1976: register vm_offset_t stack) ! 1977: { ! 1978: int i; ! 1979: ! 1980: for (i = 0; i < KERNEL_STACK_SIZE/sizeof(unsigned int); i++) ! 1981: if (((unsigned int *)stack)[i] != STACK_MARKER) ! 1982: break; ! 1983: ! 1984: return KERNEL_STACK_SIZE - i * sizeof(unsigned int); ! 1985: } ! 1986: ! 1987: /* ! 1988: * Machine-dependent code should call stack_init ! 1989: * before doing its own initialization of the stack. ! 1990: */ ! 1991: ! 1992: static void ! 1993: stack_init( ! 1994: register vm_offset_t stack, ! 1995: unsigned int bytes) ! 1996: { ! 1997: if (stack_check_usage) { ! 1998: int i; ! 1999: ! 2000: for (i = 0; i < bytes / sizeof(unsigned int); i++) ! 2001: ((unsigned int *)stack)[i] = STACK_MARKER; ! 2002: } ! 2003: } ! 2004: ! 2005: /* ! 2006: * Machine-dependent code should call stack_finalize ! 2007: * before releasing the stack memory. ! 2008: */ ! 2009: ! 2010: void ! 2011: stack_finalize( ! 2012: register vm_offset_t stack) ! 2013: { ! 2014: if (stack_check_usage) { ! 2015: vm_size_t used = stack_usage(stack); ! 2016: ! 2017: simple_lock(&stack_usage_lock); ! 2018: if (used > stack_max_usage) ! 2019: stack_max_usage = used; ! 2020: simple_unlock(&stack_usage_lock); ! 2021: if (used > stack_max_use) { ! 2022: printf("stack usage = %x\n", used); ! 2023: panic("stack overflow"); ! 2024: } ! 2025: } ! 2026: } ! 2027: ! 2028: #endif /*STACK_USAGE*/ ! 2029: #endif /* MACH_DEBUG */ ! 2030: ! 2031: kern_return_t ! 2032: host_stack_usage( ! 2033: host_t host, ! 2034: vm_size_t *reservedp, ! 2035: unsigned int *totalp, ! 2036: vm_size_t *spacep, ! 2037: vm_size_t *residentp, ! 2038: vm_size_t *maxusagep, ! 2039: vm_offset_t *maxstackp) ! 2040: { ! 2041: #if !MACH_DEBUG ! 2042: return KERN_NOT_SUPPORTED; ! 2043: #else ! 2044: unsigned int total; ! 2045: vm_size_t maxusage; ! 2046: ! 2047: if (host == HOST_NULL) ! 2048: return KERN_INVALID_HOST; ! 2049: ! 2050: simple_lock(&stack_usage_lock); ! 2051: maxusage = stack_max_usage; ! 2052: simple_unlock(&stack_usage_lock); ! 2053: ! 2054: stack_statistics(&total, &maxusage); ! 2055: ! 2056: *reservedp = 0; ! 2057: *totalp = total; ! 2058: *spacep = *residentp = total * round_page(KERNEL_STACK_SIZE); ! 2059: *maxusagep = maxusage; ! 2060: *maxstackp = 0; ! 2061: return KERN_SUCCESS; ! 2062: ! 2063: #endif /* MACH_DEBUG */ ! 2064: } ! 2065: ! 2066: /* ! 2067: * Return info on stack usage for threads in a specific processor set ! 2068: */ ! 2069: kern_return_t ! 2070: processor_set_stack_usage( ! 2071: processor_set_t pset, ! 2072: unsigned int *totalp, ! 2073: vm_size_t *spacep, ! 2074: vm_size_t *residentp, ! 2075: vm_size_t *maxusagep, ! 2076: vm_offset_t *maxstackp) ! 2077: { ! 2078: #if !MACH_DEBUG ! 2079: return KERN_NOT_SUPPORTED; ! 2080: #else ! 2081: unsigned int total; ! 2082: vm_size_t maxusage; ! 2083: vm_offset_t maxstack; ! 2084: ! 2085: register thread_t *threads; ! 2086: register thread_t thread; ! 2087: ! 2088: unsigned int actual; /* this many things */ ! 2089: unsigned int i; ! 2090: ! 2091: vm_size_t size, size_needed; ! 2092: vm_offset_t addr; ! 2093: ! 2094: if (pset == PROCESSOR_SET_NULL) ! 2095: return KERN_INVALID_ARGUMENT; ! 2096: ! 2097: size = 0; addr = 0; ! 2098: ! 2099: for (;;) { ! 2100: pset_lock(pset); ! 2101: if (!pset->active) { ! 2102: pset_unlock(pset); ! 2103: return KERN_INVALID_ARGUMENT; ! 2104: } ! 2105: ! 2106: actual = pset->thread_count; ! 2107: ! 2108: /* do we have the memory we need? */ ! 2109: ! 2110: size_needed = actual * sizeof(thread_t); ! 2111: if (size_needed <= size) ! 2112: break; ! 2113: ! 2114: /* unlock the pset and allocate more memory */ ! 2115: pset_unlock(pset); ! 2116: ! 2117: if (size != 0) ! 2118: kfree(addr, size); ! 2119: ! 2120: assert(size_needed > 0); ! 2121: size = size_needed; ! 2122: ! 2123: addr = kalloc(size); ! 2124: if (addr == 0) ! 2125: return KERN_RESOURCE_SHORTAGE; ! 2126: } ! 2127: ! 2128: /* OK, have memory and the processor_set is locked & active */ ! 2129: ! 2130: threads = (thread_t *) addr; ! 2131: for (i = 0, thread = (thread_t) queue_first(&pset->threads); ! 2132: i < actual; ! 2133: i++, ! 2134: thread = (thread_t) queue_next(&thread->pset_threads)) { ! 2135: thread_reference(thread); ! 2136: threads[i] = thread; ! 2137: } ! 2138: assert(queue_end(&pset->threads, (queue_entry_t) thread)); ! 2139: ! 2140: /* can unlock processor set now that we have the thread refs */ ! 2141: pset_unlock(pset); ! 2142: ! 2143: /* calculate maxusage and free thread references */ ! 2144: ! 2145: total = 0; ! 2146: maxusage = 0; ! 2147: maxstack = 0; ! 2148: for (i = 0; i < actual; i++) { ! 2149: int cpu; ! 2150: thread_t thread = threads[i]; ! 2151: vm_offset_t stack = 0; ! 2152: ! 2153: /* ! 2154: * thread->kernel_stack is only accurate if the ! 2155: * thread isn't swapped and is not executing. ! 2156: * ! 2157: * Of course, we don't have the appropriate locks ! 2158: * for these shenanigans. ! 2159: */ ! 2160: ! 2161: stack = thread->kernel_stack; ! 2162: ! 2163: for (cpu = 0; cpu < NCPUS; cpu++) ! 2164: if (cpu_data[cpu].active_thread == thread) { ! 2165: stack = active_stacks[cpu]; ! 2166: break; ! 2167: } ! 2168: ! 2169: if (stack != 0) { ! 2170: total++; ! 2171: ! 2172: if (stack_check_usage) { ! 2173: vm_size_t usage = stack_usage(stack); ! 2174: ! 2175: if (usage > maxusage) { ! 2176: maxusage = usage; ! 2177: maxstack = (vm_offset_t) thread; ! 2178: } ! 2179: } ! 2180: } ! 2181: ! 2182: thread_deallocate(thread); ! 2183: } ! 2184: ! 2185: if (size != 0) ! 2186: kfree(addr, size); ! 2187: ! 2188: *totalp = total; ! 2189: *residentp = *spacep = total * round_page(KERNEL_STACK_SIZE); ! 2190: *maxusagep = maxusage; ! 2191: *maxstackp = maxstack; ! 2192: return KERN_SUCCESS; ! 2193: ! 2194: #endif /* MACH_DEBUG */ ! 2195: } ! 2196: ! 2197: ! 2198: /* ! 2199: * We consider a thread not preemptable if it is marked as either ! 2200: * suspended or waiting. ! 2201: */ ! 2202: ! 2203: boolean_t thread_not_preemptable( ! 2204: thread_t thread) ! 2205: { ! 2206: ! 2207: /* XXX - when scheduling framework and such is done, the ! 2208: thread state check can be eliminated */ ! 2209: ! 2210: if ((thread->state & (TH_WAIT|TH_SUSP)) || thread->preempt) ! 2211: return (TRUE); ! 2212: else ! 2213: return (FALSE); ! 2214: } ! 2215: ! 2216: ! 2217: /* ! 2218: * thread_set_sched ! 2219: * ! 2220: * Set scheduling policy and parameters for the given thread. ! 2221: * Policy must be a policy which is enabled for the ! 2222: * processor set. ! 2223: * (This should replace `thread_set_policy()' with the addition ! 2224: * of the MK Scheduling Framework to the kernel.) ! 2225: */ ! 2226: kern_return_t ! 2227: thread_set_sched( ! 2228: thread_act_t thr_act, ! 2229: policy_t policy_id, ! 2230: sched_attr_t sched_attr, ! 2231: mach_msg_type_number_t sched_attrCnt) ! 2232: { ! 2233: thread_t thread; ! 2234: processor_set_t pset; ! 2235: kern_return_t result = KERN_SUCCESS; ! 2236: sched_policy_t *policy; ! 2237: sf_return_t sfr; ! 2238: boolean_t do_dispatch = FALSE; ! 2239: spl_t s; ! 2240: ! 2241: if (thr_act == THR_ACT_NULL) ! 2242: return (KERN_INVALID_ARGUMENT); ! 2243: ! 2244: thread = act_lock_thread(thr_act); ! 2245: if ( thread == THREAD_NULL || ! 2246: (sched_attrCnt * sizeof(int)) != ! 2247: sched_policy[policy_id].sched_attributes_size ) { ! 2248: act_unlock_thread(thr_act); ! 2249: return(KERN_INVALID_ARGUMENT); ! 2250: } ! 2251: ! 2252: if (invalid_policy(policy_id)) { ! 2253: act_unlock_thread(thr_act); ! 2254: return(KERN_INVALID_POLICY); ! 2255: } ! 2256: ! 2257: /* coordinate changes to thread scheduling state with others */ ! 2258: s = splsched(); ! 2259: thread_lock(thread); ! 2260: ! 2261: /* see if thread's policy is to be changed */ ! 2262: if (thread->policy != policy_id) { ! 2263: /* it is; see if the target is executing */ ! 2264: if (thread != current_thread()) { /*** fix for SMP ***/ ! 2265: /* it is not; detach from old policy */ ! 2266: policy = &sched_policy[thread->policy]; ! 2267: sfr = policy->sp_ops.sp_thread_detach(policy, thread); ! 2268: if (sfr != SF_SUCCESS) ! 2269: panic("thread_set_sched: sp_thread_detach"); ! 2270: ! 2271: /* attach to this policy */ ! 2272: policy = &sched_policy[policy_id]; ! 2273: sfr = policy->sp_ops.sp_thread_attach(policy, thread); ! 2274: if (sfr != SF_SUCCESS) { ! 2275: thread_unlock(thread); ! 2276: splx(s); ! 2277: act_unlock_thread(thr_act); ! 2278: return(KERN_FAILURE); ! 2279: } ! 2280: ! 2281: /* remember to dispatch thread after setting parms */ ! 2282: do_dispatch = TRUE; ! 2283: } ! 2284: else { ! 2285: /* target is currently executing */ ! 2286: /* defer policy change until thread leaves processor */ ! 2287: thread->pending_policy = policy_id; ! 2288: bcopy((char *)sched_attr, ! 2289: (char *)thread->pending_sched_attr, ! 2290: (sched_attrCnt * sizeof(int))); ! 2291: ! 2292: /* try to get off processor to effect change */ ! 2293: thread_unlock(thread); ! 2294: splx(s); ! 2295: act_unlock_thread(thr_act); ! 2296: thread_block((void (*)(void)) 0); ! 2297: ! 2298: /* by now, new attributes have been installed */ ! 2299: act_lock_thread(thr_act); ! 2300: /*** check to see it's same thread? ***/ ! 2301: ! 2302: s = splsched(); ! 2303: thread_lock(thread); ! 2304: result = (thread->change_sfr == SF_SUCCESS)? ! 2305: KERN_SUCCESS : KERN_FAILURE; ! 2306: thread_unlock(thread); ! 2307: splx(s); ! 2308: act_unlock_thread(thr_act); ! 2309: return(result); ! 2310: } ! 2311: ! 2312: } ! 2313: ! 2314: /* call policy-specific routine to install new scheduling parameters */ ! 2315: policy = &sched_policy[policy_id]; ! 2316: sfr = policy->sp_ops.sp_thread_set( ! 2317: policy, thread, (sp_attributes_t)sched_attr); ! 2318: ! 2319: /* dispatch thread under new policy, if appropriate */ ! 2320: if (do_dispatch == TRUE && sfr == SF_SUCCESS) { ! 2321: sfr = policy->sp_ops.sp_thread_dispatch(policy, thread); ! 2322: } ! 2323: ! 2324: thread_unlock(thread); ! 2325: splx(s); ! 2326: ! 2327: if (sfr != SF_SUCCESS) ! 2328: result = KERN_FAILURE; ! 2329: ! 2330: act_unlock_thread(thr_act); ! 2331: return(result); ! 2332: } ! 2333: ! 2334: ! 2335: /* ! 2336: * thread_get_sched ! 2337: * ! 2338: * Get scheduling policy and parameters for the given thread. ! 2339: * (This was added as part of the MK Scheduling Framework.) ! 2340: */ ! 2341: kern_return_t ! 2342: thread_get_sched( ! 2343: thread_act_t thr_act, ! 2344: policy_t *policy_id_out, ! 2345: sched_attr_t sched_attr, ! 2346: mach_msg_type_number_t *sched_attrCnt) ! 2347: { ! 2348: thread_t thread; ! 2349: kern_return_t result = KERN_SUCCESS; ! 2350: policy_t policy_id; ! 2351: sched_policy_t *policy; ! 2352: sf_return_t sfr; ! 2353: int size; ! 2354: spl_t s; ! 2355: ! 2356: if (thr_act == THR_ACT_NULL) ! 2357: return (KERN_INVALID_ARGUMENT); ! 2358: ! 2359: thread = act_lock_thread(thr_act); ! 2360: if (thread == THREAD_NULL) { ! 2361: act_unlock_thread(thr_act); ! 2362: *policy_id_out = POLICY_NULL; ! 2363: return(KERN_INVALID_ARGUMENT); ! 2364: } ! 2365: ! 2366: size = *sched_attrCnt * sizeof(int); ! 2367: ! 2368: /* coordinate changes to thread scheduling state with others */ ! 2369: s = splsched(); ! 2370: thread_lock(thread); ! 2371: ! 2372: policy_id = thread->policy; ! 2373: if (size < sched_policy[policy_id].sched_attributes_size) { ! 2374: thread_unlock(thread); ! 2375: splx(s); ! 2376: act_unlock_thread(thr_act); ! 2377: *policy_id_out = policy_id; ! 2378: return(KERN_INVALID_ARGUMENT); ! 2379: } ! 2380: ! 2381: /* note policy for caller */ ! 2382: *policy_id_out = policy_id; ! 2383: ! 2384: /* call policy-specific routine */ ! 2385: policy = &sched_policy[policy_id]; ! 2386: sfr = policy->sp_ops.sp_thread_get( ! 2387: policy, thread, (sp_attributes_t)sched_attr, size); ! 2388: ! 2389: if (sfr != SF_SUCCESS) ! 2390: result = KERN_FAILURE; ! 2391: ! 2392: *sched_attrCnt = policy->sched_attributes_size / sizeof(int); ! 2393: ! 2394: thread_unlock(thread); ! 2395: splx(s); ! 2396: act_unlock_thread(thr_act); ! 2397: return(result); ! 2398: } ! 2399: ! 2400: boolean_t ! 2401: thread_get_funneled( ! 2402: void) ! 2403: { ! 2404: return((current_thread()->funnel_state & TH_FN_OWNED) == TH_FN_OWNED); ! 2405: } ! 2406: ! 2407: boolean_t ! 2408: thread_set_funneled( ! 2409: boolean_t funneled) ! 2410: { ! 2411: thread_t cur_thread; ! 2412: boolean_t funnel_state_prev; ! 2413: ! 2414: cur_thread = current_thread(); ! 2415: funnel_state_prev = ((cur_thread->funnel_state & TH_FN_OWNED) == TH_FN_OWNED); ! 2416: ! 2417: if (funnel_state_prev != funneled) { ! 2418: if (funneled == TRUE) { ! 2419: mutex_lock(&funnel_lock); ! 2420: cur_thread->funnel_state |= TH_FN_OWNED; ! 2421: } else { ! 2422: cur_thread->funnel_state &= ~TH_FN_OWNED; ! 2423: mutex_unlock(&funnel_lock); ! 2424: } ! 2425: } ! 2426: return(funnel_state_prev); ! 2427: } ! 2428: ! 2429: void ! 2430: thread_set_cont_arg(int arg) ! 2431: { ! 2432: thread_t th = current_thread(); ! 2433: th->cont_arg = arg; ! 2434: } ! 2435: ! 2436: int ! 2437: thread_get_cont_arg(void) ! 2438: { ! 2439: thread_t th = current_thread(); ! 2440: return(th->cont_arg); ! 2441: } ! 2442: ! 2443: /* ! 2444: * Export routines to other components for things that are done as macros ! 2445: * within the osfmk component. ! 2446: */ ! 2447: #undef thread_should_halt ! 2448: boolean_t ! 2449: thread_should_halt( ! 2450: thread_shuttle_t th) ! 2451: { ! 2452: return(thread_should_halt_fast(th)); ! 2453: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.