Annotation of kernel/kern/thread.c, revision 1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.