Annotation of XNU/osfmk/kern/thread.c, revision 1.1

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

unix.superglobalmegacorp.com

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