Annotation of XNU/osfmk/kern/thread_act.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:  * Copyright (c) 1993 The University of Utah and
        !            27:  * the Center for Software Science (CSS).  All rights reserved.
        !            28:  *
        !            29:  * Permission to use, copy, modify and distribute this software and its
        !            30:  * documentation is hereby granted, provided that both the copyright
        !            31:  * notice and this permission notice appear in all copies of the
        !            32:  * software, derivative works or modified versions, and any portions
        !            33:  * thereof, and that both notices appear in supporting documentation.
        !            34:  *
        !            35:  * THE UNIVERSITY OF UTAH AND CSS ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
        !            36:  * IS" CONDITION.  THE UNIVERSITY OF UTAH AND CSS DISCLAIM ANY LIABILITY OF
        !            37:  * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
        !            38:  *
        !            39:  * CSS requests users of this software to return to [email protected] any
        !            40:  * improvements that they make and grant CSS redistribution rights.
        !            41:  *
        !            42:  *     Author: Bryan Ford, University of Utah CSS
        !            43:  *
        !            44:  *     Thread_Activation management routines
        !            45:  */
        !            46: 
        !            47: #include <cpus.h>
        !            48: #include <task_swapper.h>
        !            49: #include <mach/kern_return.h>
        !            50: #include <mach/alert.h>
        !            51: #include <kern/etap_macros.h>
        !            52: #include <kern/mach_param.h>
        !            53: #include <kern/zalloc.h>
        !            54: #include <kern/thread.h>
        !            55: #include <kern/thread_swap.h>
        !            56: #include <kern/task.h>
        !            57: #include <kern/task_swap.h>
        !            58: #include <kern/thread_act.h>
        !            59: #include <kern/thread_pool.h>
        !            60: #include <kern/sched_prim.h>
        !            61: #include <kern/misc_protos.h>
        !            62: #include <kern/assert.h>
        !            63: #include <kern/exception.h>
        !            64: #include <kern/ipc_mig.h>
        !            65: #include <kern/ipc_tt.h>
        !            66: #include <kern/profile.h>
        !            67: #include <kern/machine.h>
        !            68: #include <kern/spl.h>
        !            69: #include <kern/syscall_subr.h>
        !            70: #include <kern/sync_lock.h>
        !            71: #include <kern/sf.h>
        !            72: #include <kern/mk_sp.h>        /*** ??? fix so this can be removed ***/
        !            73: #include <mach_prof.h>
        !            74: #include <mach/rpc.h>
        !            75: 
        !            76: /*
        !            77:  * Debugging printf control
        !            78:  */
        !            79: #if    MACH_ASSERT
        !            80: unsigned int   watchacts =       0 /* WA_ALL */
        !            81:                                    ;   /* Do-it-yourself & patchable */
        !            82: #endif
        !            83: 
        !            84: /*
        !            85:  * Track the number of times we need to swapin a thread to deallocate it.
        !            86:  */
        !            87: int act_free_swapin = 0;
        !            88: extern boolean_t thread_swap_unwire_stack;
        !            89: 
        !            90: #if    THREAD_SWAP_UNWIRE_USER_STACK
        !            91: extern boolean_t thread_swap_unwire_user_stack;
        !            92: #else  /* THREAD_SWAP_UNWIRE_USER_STACK */
        !            93: #define thread_swap_unwire_user_stack  FALSE
        !            94: #endif /* THREAD_SWAP_UNWIRE_USER_STACK */
        !            95: 
        !            96: /*
        !            97:  * Forward declarations for functions local to this file.
        !            98:  */
        !            99: kern_return_t  act_abort( thread_act_t, int);
        !           100: void           special_handler(ReturnHandler *, thread_act_t);
        !           101: void           nudge(thread_act_t);
        !           102: kern_return_t  act_set_state_locked(thread_act_t, int,
        !           103:                                        thread_state_t,
        !           104:                                        mach_msg_type_number_t);
        !           105: kern_return_t  act_get_state_locked(thread_act_t, int,
        !           106:                                        thread_state_t,
        !           107:                                        mach_msg_type_number_t *);
        !           108: void           act_set_apc(thread_act_t);
        !           109: void           act_clr_apc(thread_act_t);
        !           110: void           act_user_to_kernel(thread_act_t);
        !           111: void           act_ulock_release_all(thread_act_t thr_act);
        !           112: 
        !           113: kern_return_t  terminate_empty_act(thread_act_t);
        !           114: void           install_special_handler_locked(thread_act_t);
        !           115: 
        !           116: static zone_t  thr_act_zone;
        !           117: 
        !           118: /*
        !           119:  * Thread interfaces accessed via a thread_activation:
        !           120:  */
        !           121: 
        !           122: /*
        !           123:  * Terminate a thread.  Called with nothing locked.
        !           124:  * Returns same way.
        !           125:  */
        !           126: kern_return_t
        !           127: thread_terminate(
        !           128:        register thread_act_t   thr_act)
        !           129: {
        !           130:        thread_t        thread;
        !           131:        task_t          task;
        !           132:        struct ipc_port *iplock;
        !           133:        kern_return_t   ret = KERN_INVALID_ARGUMENT;
        !           134: #if    NCPUS > 1
        !           135:        boolean_t       held;
        !           136: #endif /* NCPUS > 1 */
        !           137: 
        !           138:        if (thr_act == THR_ACT_NULL)
        !           139:                return(ret);
        !           140: 
        !           141:        if (((thr_act->task == kernel_task) || (thr_act->kernel_loaded == TRUE))
        !           142:            && (current_act() != thr_act)) {
        !           143:                return(KERN_FAILURE);
        !           144:         }
        !           145: 
        !           146: #if    THREAD_SWAPPER
        !           147:        thread_swap_disable(thr_act);
        !           148: #endif /* THREAD_SWAPPER */
        !           149: 
        !           150:        /*
        !           151:         * Lock task containing target thread before (really)
        !           152:         * getting thread locks.
        !           153:         */
        !           154:        act_lock(thr_act);
        !           155:        task = thr_act->task;
        !           156:        act_unlock(thr_act);
        !           157:        task_lock(task);
        !           158: 
        !           159:        thread = act_lock_thread(thr_act);
        !           160:        if (!thr_act->active) {
        !           161:                act_unlock_thread(thr_act);
        !           162:                task_unlock(task);
        !           163:                return(KERN_TERMINATED);
        !           164:        }
        !           165: 
        !           166:        /*
        !           167:         *      Break IPC control over the thread.
        !           168:         */
        !           169:        ipc_thr_act_disable_act_locked(thr_act);
        !           170: 
        !           171: #if    NCPUS > 1
        !           172:        /* 
        !           173:         * Make sure this thread enters the kernel
        !           174:         */
        !           175:        if (thread != THREAD_NULL && thread != current_thread()) {
        !           176:                thread_hold(thr_act);
        !           177:                act_unlock_thread(thr_act);
        !           178: #if 1 /* Grenoble */
        !           179:                if (!thread_stop_wait(thread)) {
        !           180:                        ret = KERN_ABORTED;
        !           181:                        (void)act_lock_thread(thr_act);
        !           182:                        thread_release(thr_act);
        !           183:                        act_unlock_thread(thr_act);
        !           184:                        task_unlock(task);
        !           185:                        return (ret);
        !           186:                }
        !           187: #else
        !           188:                thread_stop_wait(thread);
        !           189: #endif
        !           190:                held = TRUE;
        !           191:                (void)act_lock_thread(thr_act);
        !           192:        } else {
        !           193:                held = FALSE;
        !           194:        }
        !           195: #endif /* NCPUS > 1 */
        !           196: 
        !           197: #if 0 /* Grenoble */
        !           198:        /*
        !           199:         * Lock task containing target.
        !           200:         * Use mutex_try to respect lock ordering.
        !           201:         */
        !           202: 
        !           203:        task = thr_act->task;
        !           204:        if (!mutex_try(&task->lock)) {
        !           205:                act_unlock_thread(thr_act);
        !           206:                task_lock(task);
        !           207:                thread = act_lock_thread(thr_act);
        !           208:        }
        !           209:                
        !           210: 
        !           211:        if (!thr_act->active) {
        !           212:                act_unlock_thread(thr_act);
        !           213:                task_unlock(task);
        !           214:                ret = KERN_TERMINATED;
        !           215:                goto out;
        !           216:        }
        !           217: 
        !           218:        /*
        !           219:         *      Break IPC control over the thread.
        !           220:         */
        !           221:        ipc_thr_act_disable_act_locked(thr_act);
        !           222: 
        !           223: #endif
        !           224:        /*
        !           225:         * Check for terminating an empty thread_act -- detach it from
        !           226:         * its task, then deallocate its remaining refs here.
        !           227:         */
        !           228:        if (thr_act->thread == THREAD_NULL) {
        !           229:                iplock = thr_act->pool_port;    /* remember for unlock call */
        !           230:                ret = terminate_empty_act( thr_act );
        !           231: 
        !           232:                /*
        !           233:                 * Release locks individually. (`act_unlock_thread()'
        !           234:                 * will not work since `pool_port' field has changed.)
        !           235:                 */
        !           236:                ip_unlock(iplock);
        !           237:                act_unlock(thr_act);
        !           238:        }
        !           239:        else {
        !           240:                assert(thr_act->active);
        !           241:                act_disable_task_locked(thr_act);
        !           242:                ret = act_abort(thr_act,FALSE);
        !           243:                act_unlock_thread(thr_act);
        !           244:        }
        !           245: 
        !           246:        task_unlock(task);
        !           247: 
        !           248:        if (((thr_act->task == kernel_task) || (thr_act->kernel_loaded == TRUE))
        !           249:            && (current_act() == thr_act)) {
        !           250:                ast_taken(FALSE, AST_APC, 0);
        !           251:                panic("thread_terminate(): returning from ast_taken() for %x kernel activation\n", thr_act);
        !           252:         }
        !           253: 
        !           254: #if 0 /* Grenoble */
        !           255: out:
        !           256: #endif
        !           257: 
        !           258: #if    NCPUS > 1
        !           259:        if (held) {
        !           260:                thread_unstop(thread);
        !           261:                (void)act_lock_thread(thr_act);
        !           262:                thread_release(thr_act);
        !           263:                act_unlock_thread(thr_act);
        !           264:        }
        !           265: #endif /* NCPUS > 1 */
        !           266:        return(ret);
        !           267: }
        !           268: 
        !           269: /*
        !           270:  * Called with empty thread activation and its pool port locked.
        !           271:  * Activation is currently "active."
        !           272:  * Task containing activation is also locked.
        !           273:  * Returns the same way.
        !           274:  */
        !           275: kern_return_t
        !           276: terminate_empty_act( thread_act_t thr_act ) {
        !           277:        /*
        !           278:         * remove the activation from the pool port
        !           279:         * (this prevents it from being used)
        !           280:         */
        !           281:        if (thr_act->pool_port) {
        !           282:                act_locked_act_set_thread_pool(thr_act, IP_NULL);
        !           283:        }
        !           284: 
        !           285:        /*
        !           286:         * disassociate the thread from the task
        !           287:         */
        !           288:        assert(thr_act->active);
        !           289:        act_disable_task_locked( thr_act );
        !           290: 
        !           291:        return KERN_SUCCESS;
        !           292: }
        !           293: 
        !           294: /*
        !           295:  *     thread_hold:
        !           296:  *
        !           297:  *     Suspend execution of the specified thread.
        !           298:  *     This is a recursive-style suspension of the thread, a count of
        !           299:  *     suspends is maintained.
        !           300:  *
        !           301:  *     Called with thr_act locked "appropriately" for synchrony with
        !           302:  *     RPC (see act_lock_thread()).  Returns same way.
        !           303:  */
        !           304: void
        !           305: thread_hold(
        !           306:        register thread_act_t   thr_act)
        !           307: {
        !           308:        if (thr_act->suspend_count++ == 0) {
        !           309:                install_special_handler(thr_act);
        !           310:                nudge(thr_act);
        !           311:        }
        !           312: }
        !           313: 
        !           314: /*
        !           315:  * Decrement internal suspension count for thr_act, setting thread
        !           316:  * runnable when count falls to zero.
        !           317:  *
        !           318:  * Called with thr_act locked "appropriately" for synchrony
        !           319:  * with RPC (see act_lock_thread()).
        !           320:  */
        !           321: void
        !           322: thread_release(
        !           323:        register thread_act_t   thr_act)
        !           324: {
        !           325:        if( thr_act->suspend_count &&
        !           326:                (--thr_act->suspend_count == 0) )
        !           327:                nudge( thr_act );
        !           328: }
        !           329: 
        !           330: kern_return_t
        !           331: thread_suspend(
        !           332:        register thread_act_t   thr_act)
        !           333: {
        !           334:        thread_t                thread;
        !           335: 
        !           336:        if (thr_act == THR_ACT_NULL) {
        !           337:                return(KERN_INVALID_ARGUMENT);
        !           338:        }
        !           339:        thread = act_lock_thread(thr_act);
        !           340:        if (!thr_act->active) {
        !           341:                act_unlock_thread(thr_act);
        !           342:                return(KERN_TERMINATED);
        !           343:        }
        !           344:        if (thr_act->user_stop_count++ == 0 &&
        !           345:                thr_act->suspend_count++ == 0 ) {
        !           346:                install_special_handler(thr_act);
        !           347:                if (thread &&
        !           348:                        thr_act == thread->top_act && thread != current_thread()) {
        !           349:                        nudge(thr_act);
        !           350:                        act_unlock_thread(thr_act);
        !           351:                        (void)thread_wait(thread);
        !           352:                }
        !           353:                else {
        !           354:                        /*
        !           355:                         * No need to wait for target thread
        !           356:                         */
        !           357:                        act_unlock_thread(thr_act);
        !           358:                }
        !           359:        }
        !           360:        else {
        !           361:                /*
        !           362:                 * Thread is already suspended
        !           363:                 */
        !           364:                act_unlock_thread(thr_act);
        !           365:        }
        !           366:        return(KERN_SUCCESS);
        !           367: }
        !           368: 
        !           369: kern_return_t
        !           370: thread_resume(
        !           371:        register thread_act_t   thr_act)
        !           372: {
        !           373:        register kern_return_t  ret;
        !           374:        spl_t                   s;
        !           375:        thread_t                thread;
        !           376: 
        !           377:        if (thr_act == THR_ACT_NULL)
        !           378:                return(KERN_INVALID_ARGUMENT);
        !           379:        thread = act_lock_thread(thr_act);
        !           380:        ret = KERN_SUCCESS;
        !           381: 
        !           382:        if (thr_act->active) {
        !           383:                if (thr_act->user_stop_count > 0) {
        !           384:                        if( --thr_act->user_stop_count == 0 ) {
        !           385:                                --thr_act->suspend_count;
        !           386:                                nudge( thr_act );
        !           387:                        }
        !           388:                }
        !           389:                else
        !           390:                        ret = KERN_FAILURE;
        !           391:        }
        !           392:        else
        !           393:                ret = KERN_TERMINATED;
        !           394:        act_unlock_thread( thr_act );
        !           395:        return ret;
        !           396: }
        !           397: 
        !           398: /* 
        !           399:  * This routine walks toward the head of an RPC chain starting at
        !           400:  * a specified thread activation. An alert bit is set and a special 
        !           401:  * handler is installed for each thread it encounters.
        !           402:  *
        !           403:  * The target thread act and thread shuttle are already locked.
        !           404:  */
        !           405: kern_return_t
        !           406: post_alert( 
        !           407:        register thread_act_t   thr_act,
        !           408:        unsigned                alert_bits )
        !           409: {
        !           410:        thread_act_t    next;
        !           411:        thread_t        thread;
        !           412: 
        !           413:        /* 
        !           414:         * Chase the chain, setting alert bits and installing
        !           415:         * special handlers for each thread act.
        !           416:         */
        !           417:        /*** Not yet SMP safe ***/
        !           418:        /*** Worse, where's the activation locking as the chain is walked? ***/
        !           419:        for (next = thr_act; next != THR_ACT_NULL; next = next->higher) {
        !           420:                next->alerts |= alert_bits;
        !           421:                install_special_handler_locked(next);
        !           422:        }
        !           423: 
        !           424:        return(KERN_SUCCESS);
        !           425: }
        !           426: 
        !           427: /*
        !           428:  *     thread_depress_abort:
        !           429:  *
        !           430:  *     Prematurely abort priority depression if there is one.
        !           431:  */
        !           432: kern_return_t
        !           433: thread_depress_abort(
        !           434:        register thread_act_t   thr_act)
        !           435: {
        !           436:     register thread_t          thread;
        !           437:        kern_return_t                   result;
        !           438:     sched_policy_t                     *policy;
        !           439:     spl_t                                      s;
        !           440: 
        !           441:     if (thr_act == THR_ACT_NULL)
        !           442:                return (KERN_INVALID_ARGUMENT);
        !           443: 
        !           444:     thread = act_lock_thread(thr_act);
        !           445:     /* if activation is terminating, this operation is not meaningful */
        !           446:     if (!thr_act->active) {
        !           447:                act_unlock_thread(thr_act);
        !           448: 
        !           449:                return (KERN_TERMINATED);
        !           450:     }
        !           451: 
        !           452:     if (thread == THREAD_NULL) {
        !           453:                act_unlock_thread(thr_act);
        !           454: 
        !           455:                return (KERN_INVALID_ARGUMENT);
        !           456:     }
        !           457: 
        !           458:     s = splsched();
        !           459:     thread_lock(thread);
        !           460:     policy = &sched_policy[thread->policy];
        !           461:     thread_unlock(thread);
        !           462:     splx(s);
        !           463: 
        !           464:     result = policy->sp_ops.sp_thread_depress_abort(policy, thread);
        !           465: 
        !           466:     act_unlock_thread(thr_act);
        !           467: 
        !           468:        return (result);
        !           469: }
        !           470: 
        !           471: 
        !           472: /*
        !           473:  * Already locked: all RPC-related locks for thr_act (see
        !           474:  * act_lock_thread()).
        !           475:  */
        !           476: kern_return_t
        !           477: act_abort( thread_act_t thr_act, int chain_break )
        !           478: {
        !           479:        spl_t                   spl;
        !           480:        thread_t                thread;
        !           481:        struct ipc_port         *iplock = thr_act->pool_port;
        !           482:        thread_act_t            orphan;
        !           483:        kern_return_t           kr;
        !           484:        etap_data_t             probe_data;
        !           485: 
        !           486:        /*
        !           487:         * mark the activation for abort,
        !           488:         * update the suspend count,
        !           489:         * always install the special handler
        !           490:         */
        !           491:        install_special_handler(thr_act);
        !           492: 
        !           493:        ETAP_DATA_LOAD(probe_data[0], thr_act);
        !           494:        ETAP_DATA_LOAD(probe_data[1], thr_act->thread);
        !           495:        ETAP_PROBE_DATA(ETAP_P_ACT_ABORT,
        !           496:                        0,
        !           497:                        current_thread(),
        !           498:                        &probe_data,
        !           499:                        ETAP_DATA_ENTRY*2);
        !           500: 
        !           501:        spl = splsched();
        !           502:        thread_lock( thr_act->thread );
        !           503: 
        !           504:        /*
        !           505:         *  If the target thread activation is not the head... 
        !           506:         */
        !           507:        if ( thr_act->thread->top_act != thr_act ) {
        !           508: #ifdef AGRESSIVE_ABORT
        !           509:                /* release state buffer for target's outstanding invocation */
        !           510:                if (unwind_invoke_state(thr_act) != KERN_SUCCESS) {
        !           511:                        panic("unwind_invoke_state failure");
        !           512:                }
        !           513: 
        !           514:                /* release state buffer for target's incoming invocation */
        !           515:                if (thr_act->lower != THR_ACT_NULL) {
        !           516:                        if (unwind_invoke_state(thr_act->lower)
        !           517:                            != KERN_SUCCESS) {
        !           518:                                panic("unwind_invoke_state failure");
        !           519:                        }
        !           520:                }
        !           521: 
        !           522:                /* unlink target thread activation from shuttle chain */
        !           523:                if ( thr_act->lower == THR_ACT_NULL ) {
        !           524:                        /*
        !           525:                         * This is the root thread activation of the chain.
        !           526:                         * Unlink the root thread act from the bottom of
        !           527:                         * the chain.
        !           528:                         */
        !           529:                        thr_act->higher->lower = THR_ACT_NULL;
        !           530:                } else {
        !           531:                        /*
        !           532:                         * This thread act is in the middle of the chain.
        !           533:                         * Unlink the thread act from the middle of the chain.
        !           534:                         */
        !           535:                        thr_act->higher->lower = thr_act->lower;
        !           536:                        thr_act->lower->higher = thr_act->higher;
        !           537: 
        !           538:                        /* set the terminated bit for RPC return processing */
        !           539:                        thr_act->lower->alerts |= SERVER_TERMINATED;
        !           540:                }
        !           541: 
        !           542:                orphan = thr_act->higher;
        !           543: 
        !           544:                /* remove the activation from its thread pool */
        !           545:                /* (note: this is okay for "rooted threads," too) */
        !           546:                act_locked_act_set_thread_pool(thr_act, IP_NULL);
        !           547: 
        !           548:                /* (just to be thorough) release the IP lock */
        !           549:                if (iplock != IP_NULL) ip_unlock(iplock);
        !           550: 
        !           551:                /* release one more reference for a rooted thread */
        !           552:                if (iplock == IP_NULL) act_locked_act_deallocate(thr_act);
        !           553: 
        !           554:                /* Presumably, the only reference to this activation is
        !           555:                 * now held by the caller of this routine. */
        !           556:                assert(thr_act->ref_count == 1);
        !           557: #else /*AGRESSIVE_ABORT*/
        !           558:                /* If there is a lower activation in the RPC chain... */
        !           559:                if (thr_act->lower != THR_ACT_NULL) {
        !           560:                        /* ...indicate the server activation was terminated */
        !           561:                        thr_act->lower->alerts |= SERVER_TERMINATED;
        !           562:                }
        !           563:                /* Mark (and process) any orphaned activations */
        !           564:                orphan = thr_act->higher;
        !           565: #endif /*AGRESSIVE_ABORT*/
        !           566: 
        !           567:                /* indicate client of orphaned chain has been terminated */
        !           568:                orphan->alerts |= CLIENT_TERMINATED;
        !           569: 
        !           570:                /* 
        !           571:                 * Set up posting of alert to headward portion of
        !           572:                 * the RPC chain.
        !           573:                 */
        !           574:                /*** fix me -- orphan act is not locked ***/
        !           575:                post_alert(orphan, ORPHANED);
        !           576: 
        !           577:                /*
        !           578:                 * Get attention of head of RPC chain.
        !           579:                 */
        !           580:                thread_unlock(thr_act->thread);
        !           581:                nudge(thr_act->thread->top_act);
        !           582:                splx(spl);
        !           583:                return (KERN_SUCCESS);
        !           584:        }
        !           585: 
        !           586:        /*
        !           587:         * If the target thread is the end of the chain, the thread
        !           588:         * has to be marked for abort and rip it out of any wait.
        !           589:         */
        !           590:        if (thr_act->thread->top_act == thr_act) {
        !           591:            thr_act->thread->state |= TH_ABORT;
        !           592:            thread_unlock(thr_act->thread);
        !           593:            install_special_handler(thr_act);
        !           594:            nudge( thr_act );
        !           595: 
        !           596:            /*
        !           597:             * if it's waiting, clear it.
        !           598:             */
        !           599:            if( thr_act->thread->state & TH_WAIT ){
        !           600:                clear_wait(thr_act->thread, THREAD_INTERRUPTED, TRUE);
        !           601:                splx(spl);
        !           602:                return KERN_SUCCESS;
        !           603:            }
        !           604:        }
        !           605:        else {
        !           606:                thread_unlock(thr_act->thread);
        !           607:        }
        !           608:        splx(spl);
        !           609:        return KERN_SUCCESS;
        !           610: }
        !           611:        
        !           612: kern_return_t
        !           613: thread_abort(
        !           614:        register thread_act_t   thr_act)
        !           615: {
        !           616:        int             ret;
        !           617:        thread_t                thread;
        !           618: 
        !           619:        if (thr_act == THR_ACT_NULL || thr_act == current_act())
        !           620:                return (KERN_INVALID_ARGUMENT);
        !           621:        /*
        !           622:         *      Lock the target thread and the current thread now,
        !           623:         *      in case thread_halt() ends up being called below.
        !           624:         */
        !           625:        thread = act_lock_thread(thr_act);
        !           626:        if (!thr_act->active) {
        !           627:                act_unlock_thread(thr_act);
        !           628:                return(KERN_TERMINATED);
        !           629:        }
        !           630: 
        !           631:        if( thread == THREAD_NULL ) {
        !           632:                act_unlock_thread(thr_act);
        !           633:                return KERN_NO_THREAD;
        !           634:        }
        !           635: 
        !           636:        ret = act_abort( thr_act, FALSE );
        !           637:        act_unlock_thread( thr_act );
        !           638:        return ret;
        !           639: }
        !           640: 
        !           641: kern_return_t
        !           642: thread_abort_safely(
        !           643:        register thread_act_t   thr_act)
        !           644: {
        !           645:        boolean_t               r;
        !           646:        thread_t                cur_thr = current_thread();
        !           647:        thread_t                thread, othread;
        !           648:        thread_act_t            cur_thr_act = current_act();
        !           649:        spl_t                   spl;
        !           650: 
        !           651:        if (thr_act == THR_ACT_NULL || thr_act == current_act())
        !           652:                return(KERN_INVALID_ARGUMENT);
        !           653: 
        !           654:        othread = act_lock_thread(thr_act);
        !           655:        if (othread == THREAD_NULL) {
        !           656:                act_unlock_thread(thr_act);
        !           657:                return(KERN_INVALID_ARGUMENT);
        !           658:        }
        !           659:        if (!thr_act->active) {
        !           660:                act_unlock_thread(thr_act);
        !           661:                return(KERN_TERMINATED);
        !           662:        }
        !           663:        if (othread->top_act != thr_act) {
        !           664:                act_unlock_thread(thr_act);
        !           665:                return(KERN_FAILURE);
        !           666:        }
        !           667: 
        !           668:        /*
        !           669:         * This is the head of the chain.  Stop it and check to see if
        !           670:         * it's in a condition which can be interrupted and restarted and,
        !           671:         * if so, clear the wait.
        !           672:         */
        !           673:        thread_hold(thr_act);
        !           674:        act_unlock_thread(thr_act);
        !           675:        r = thread_stop_wait(othread);
        !           676:        if ((thread = act_lock_thread(thr_act)) != othread || !r) {
        !           677:                thread_release(thr_act);
        !           678:                act_unlock_thread(thr_act);
        !           679:                if (r) {
        !           680:                        thread_unstop(othread);
        !           681:                        return (KERN_FAILURE);
        !           682:                }
        !           683:                else
        !           684:                    return(KERN_ABORTED);
        !           685:        }
        !           686: 
        !           687:        assert(thread == thr_act->thread);
        !           688: 
        !           689:        spl = splsched();
        !           690:        thread_lock(thread);
        !           691:        
        !           692:        if( (thread->state&(TH_RUN|TH_UNINT|TH_WAIT)) == TH_WAIT ){
        !           693:            if ( thread->at_safe_point ) {
        !           694:                        /*
        !           695:                         * It's an interruptible wait, clear it, then
        !           696:                         * let the thread go and return successfully.
        !           697:                         */
        !           698:                        thread_unlock(thread);
        !           699:                        splx(spl);
        !           700:                        clear_wait(thread, THREAD_INTERRUPTED, TRUE);
        !           701:                        thread_unstop(thread);
        !           702:                        thread_release(thr_act);
        !           703:                        act_unlock_thread(thr_act);
        !           704:                        return KERN_SUCCESS;
        !           705:            }
        !           706:        }
        !           707:        /*
        !           708:         * if not stopped at a safepoint, just let it go and return failure.
        !           709:         */
        !           710:        thread_unlock(thread);
        !           711:        splx(spl);
        !           712:        thread_unstop(thread);
        !           713:        thread_release(thr_act);
        !           714:        act_unlock_thread(thr_act);
        !           715:        return KERN_FAILURE;
        !           716: }
        !           717: 
        !           718: /*** backward compatibility hacks ***/
        !           719: #include <mach/thread_info.h>
        !           720: #include <mach/thread_special_ports.h>
        !           721: #include <ipc/ipc_port.h>
        !           722: #include <mach/thread_act_server.h>
        !           723: 
        !           724: kern_return_t
        !           725: thread_info(
        !           726:        thread_act_t                    thr_act,
        !           727:        thread_flavor_t                 flavor,
        !           728:        thread_info_t                   thread_info_out,
        !           729:        mach_msg_type_number_t  *thread_info_count)
        !           730: {
        !           731:        register thread_t               thread;
        !           732:        kern_return_t                   result;
        !           733: 
        !           734:        if (thr_act == THR_ACT_NULL)
        !           735:                return (KERN_INVALID_ARGUMENT);
        !           736: 
        !           737:        thread = act_lock_thread(thr_act);
        !           738:        if (!thr_act->active) {
        !           739:                act_unlock_thread(thr_act);
        !           740: 
        !           741:                return (KERN_TERMINATED);
        !           742:        }
        !           743: 
        !           744:        if (thread == THREAD_NULL) {
        !           745:                act_unlock_thread(thr_act);
        !           746: 
        !           747:                return (KERN_NO_THREAD);
        !           748:        }
        !           749: 
        !           750:        result = thread_info_shuttle(thr_act, flavor,
        !           751:                                        thread_info_out, thread_info_count);
        !           752: 
        !           753:        act_unlock_thread(thr_act);
        !           754: 
        !           755:        return (result);
        !           756: }
        !           757: 
        !           758: /*
        !           759:  *     Routine:        thread_get_special_port [kernel call]
        !           760:  *     Purpose:
        !           761:  *             Clones a send right for one of the thread's
        !           762:  *             special ports.
        !           763:  *     Conditions:
        !           764:  *             Nothing locked.
        !           765:  *     Returns:
        !           766:  *             KERN_SUCCESS            Extracted a send right.
        !           767:  *             KERN_INVALID_ARGUMENT   The thread is null.
        !           768:  *             KERN_FAILURE            The thread is dead.
        !           769:  *             KERN_INVALID_ARGUMENT   Invalid special port.
        !           770:  */
        !           771: 
        !           772: kern_return_t
        !           773: thread_get_special_port(
        !           774:        thread_act_t    thr_act,
        !           775:        int             which,
        !           776:        ipc_port_t      *portp)
        !           777: {
        !           778:        ipc_port_t      *whichp;
        !           779:        ipc_port_t      port;
        !           780:        thread_t        thread;
        !           781: 
        !           782: #if    MACH_ASSERT
        !           783:        if (watchacts & WA_PORT)
        !           784:            printf("thread_get_special_port(thr_act=%x, which=%x port@%x=%x\n",
        !           785:                thr_act, which, portp, (portp ? *portp : 0));
        !           786: #endif /* MACH_ASSERT */
        !           787: 
        !           788:        if (!thr_act)
        !           789:                return KERN_INVALID_ARGUMENT;
        !           790:        thread = act_lock_thread(thr_act);
        !           791:        switch (which) {
        !           792:                case THREAD_KERNEL_PORT:
        !           793:                        whichp = &thr_act->ith_sself;
        !           794:                        break;
        !           795: 
        !           796:                default:
        !           797:                        act_unlock_thread(thr_act);
        !           798:                        return KERN_INVALID_ARGUMENT;
        !           799:        }
        !           800: 
        !           801:        if (!thr_act->active) {
        !           802:                act_unlock_thread(thr_act);
        !           803:                return KERN_FAILURE;
        !           804:        }
        !           805: 
        !           806:        port = ipc_port_copy_send(*whichp);
        !           807:        act_unlock_thread(thr_act);
        !           808: 
        !           809:        *portp = port;
        !           810:        return KERN_SUCCESS;
        !           811: }
        !           812: 
        !           813: /*
        !           814:  *     Routine:        thread_set_special_port [kernel call]
        !           815:  *     Purpose:
        !           816:  *             Changes one of the thread's special ports,
        !           817:  *             setting it to the supplied send right.
        !           818:  *     Conditions:
        !           819:  *             Nothing locked.  If successful, consumes
        !           820:  *             the supplied send right.
        !           821:  *     Returns:
        !           822:  *             KERN_SUCCESS            Changed the special port.
        !           823:  *             KERN_INVALID_ARGUMENT   The thread is null.
        !           824:  *             KERN_FAILURE            The thread is dead.
        !           825:  *             KERN_INVALID_ARGUMENT   Invalid special port.
        !           826:  */
        !           827: 
        !           828: kern_return_t
        !           829: thread_set_special_port(
        !           830:        thread_act_t    thr_act,
        !           831:        int             which,
        !           832:        ipc_port_t      port)
        !           833: {
        !           834:        ipc_port_t      *whichp;
        !           835:        ipc_port_t      old;
        !           836:        thread_t        thread;
        !           837: 
        !           838: #if    MACH_ASSERT
        !           839:        if (watchacts & WA_PORT)
        !           840:                printf("thread_set_special_port(thr_act=%x,which=%x,port=%x\n",
        !           841:                        thr_act, which, port);
        !           842: #endif /* MACH_ASSERT */
        !           843: 
        !           844:        if (thr_act == 0)
        !           845:                return KERN_INVALID_ARGUMENT;
        !           846: 
        !           847:        thread = act_lock_thread(thr_act);
        !           848:        switch (which) {
        !           849:                case THREAD_KERNEL_PORT:
        !           850:                        whichp = &thr_act->ith_self;
        !           851:                        break;
        !           852: 
        !           853:                default:
        !           854:                        act_unlock_thread(thr_act);
        !           855:                        return KERN_INVALID_ARGUMENT;
        !           856:        }
        !           857: 
        !           858:        if (!thr_act->active) {
        !           859:                act_unlock_thread(thr_act);
        !           860:                return KERN_FAILURE;
        !           861:        }
        !           862: 
        !           863:        old = *whichp;
        !           864:        *whichp = port;
        !           865:        act_unlock_thread(thr_act);
        !           866: 
        !           867:        if (IP_VALID(old))
        !           868:                ipc_port_release_send(old);
        !           869:        return KERN_SUCCESS;
        !           870: }
        !           871: 
        !           872: /*
        !           873:  *  thread state should always be accessible by locking the thread
        !           874:  *  and copying it.  The activation messes things up so for right
        !           875:  *  now if it's not the top of the chain, use a special handler to
        !           876:  *  get the information when the shuttle returns to the activation.
        !           877:  */
        !           878: kern_return_t
        !           879: thread_get_state(
        !           880:        register thread_act_t   thr_act,
        !           881:        int                     flavor,
        !           882:        thread_state_t          state,  /* pointer to OUT array */
        !           883:        mach_msg_type_number_t  *state_count)   /*IN/OUT*/
        !           884: {
        !           885:        kern_return_t           ret;
        !           886:        thread_t                thread, nthread;
        !           887: 
        !           888: #if 0 /* Grenoble - why?? */
        !           889:        if (thr_act == THR_ACT_NULL || thr_act == current_act())
        !           890: #else
        !           891:        if (thr_act == THR_ACT_NULL)
        !           892: #endif
        !           893:                return (KERN_INVALID_ARGUMENT);
        !           894: 
        !           895:        thread = act_lock_thread(thr_act);
        !           896:        if (!thr_act->active) {
        !           897:                act_unlock_thread(thr_act);
        !           898:                return(KERN_TERMINATED);
        !           899:        }
        !           900: 
        !           901:        thread_hold(thr_act);
        !           902:        while (1) {
        !           903:                if (!thread || thr_act != thread->top_act)
        !           904:                        break;
        !           905:                act_unlock_thread(thr_act);
        !           906:                (void)thread_stop_wait(thread);
        !           907:                nthread = act_lock_thread(thr_act);
        !           908:                if (nthread == thread)
        !           909:                        break;
        !           910:                thread_unstop(thread);
        !           911:                thread = nthread;
        !           912:        }
        !           913:        ret = act_machine_get_state(thr_act, flavor,
        !           914:                                        state, state_count);
        !           915:        if (thread && thr_act == thread->top_act)
        !           916:            thread_unstop(thread);
        !           917:        thread_release(thr_act);
        !           918:        act_unlock_thread(thr_act);
        !           919: 
        !           920:        return(ret);
        !           921: }
        !           922: 
        !           923: /*
        !           924:  *     Change thread's machine-dependent state.  Called with nothing
        !           925:  *     locked.  Returns same way.
        !           926:  */
        !           927: kern_return_t
        !           928: thread_set_state(
        !           929:        register thread_act_t   thr_act,
        !           930:        int                     flavor,
        !           931:        thread_state_t          state,
        !           932:        mach_msg_type_number_t  state_count)
        !           933: {
        !           934:        kern_return_t           ret;
        !           935:        thread_t                thread, nthread;
        !           936: 
        !           937: #if 0 /* Grenoble - why?? */
        !           938:        if (thr_act == THR_ACT_NULL || thr_act == current_act())
        !           939: #else
        !           940:        if (thr_act == THR_ACT_NULL)
        !           941: #endif
        !           942:                return (KERN_INVALID_ARGUMENT);
        !           943:        /*
        !           944:         * We have no kernel activations, so Utah's MO fails for signals etc.
        !           945:         *
        !           946:         * If we're blocked in the kernel, use non-blocking method, else
        !           947:         * pass locked thr_act+thread in to "normal" act_[gs]et_state().
        !           948:         */
        !           949: 
        !           950:        thread = act_lock_thread(thr_act);
        !           951:        if (!thr_act->active) {
        !           952:                act_unlock_thread(thr_act);
        !           953:                return(KERN_TERMINATED);
        !           954:        }
        !           955: 
        !           956:        thread_hold(thr_act);
        !           957:        while (1) {
        !           958:                if (!thread || thr_act != thread->top_act)
        !           959:                        break;
        !           960:                act_unlock_thread(thr_act);
        !           961:                (void)thread_stop_wait(thread);
        !           962:                nthread = act_lock_thread(thr_act);
        !           963:                if (nthread == thread)
        !           964:                        break;
        !           965:                thread_unstop(thread);
        !           966:                thread = nthread;
        !           967:        }
        !           968:        ret = act_machine_set_state(thr_act, flavor,
        !           969:                                        state, state_count);
        !           970:        if (thread && thr_act == thread->top_act)
        !           971:            thread_unstop(thread);
        !           972:        thread_release(thr_act);
        !           973:        act_unlock_thread(thr_act);
        !           974: 
        !           975:        return(ret);
        !           976: }
        !           977: 
        !           978: /*
        !           979:  * Kernel-internal "thread" interfaces used outside this file:
        !           980:  */
        !           981: 
        !           982: kern_return_t
        !           983: thread_dup(
        !           984:        thread_act_t source_thr_act, 
        !           985:        thread_act_t target_thr_act)
        !           986: {
        !           987:        kern_return_t           ret;
        !           988:        thread_t                thread, nthread;
        !           989: 
        !           990:        if (target_thr_act == THR_ACT_NULL || target_thr_act == current_act())
        !           991:                return (KERN_INVALID_ARGUMENT);
        !           992: 
        !           993:        thread = act_lock_thread(target_thr_act);
        !           994:        if (!target_thr_act->active) {
        !           995:                act_unlock_thread(target_thr_act);
        !           996:                return(KERN_TERMINATED);
        !           997:        }
        !           998: 
        !           999:        thread_hold(target_thr_act);
        !          1000:        while (1) {
        !          1001:                if (!thread || target_thr_act != thread->top_act)
        !          1002:                        break;
        !          1003:                act_unlock_thread(target_thr_act);
        !          1004:                (void)thread_stop_wait(thread);
        !          1005:                nthread = act_lock_thread(target_thr_act);
        !          1006:                if (nthread == thread)
        !          1007:                        break;
        !          1008:                thread_unstop(thread);
        !          1009:                thread = nthread;
        !          1010:        }
        !          1011:        ret = act_thread_dup(source_thr_act, target_thr_act);
        !          1012:        if (thread && target_thr_act == thread->top_act)
        !          1013:            thread_unstop(thread);
        !          1014:        thread_release(target_thr_act);
        !          1015:        act_unlock_thread(target_thr_act);
        !          1016: 
        !          1017:        return(ret);
        !          1018: }
        !          1019: 
        !          1020: 
        !          1021: /*
        !          1022:  *     thread_setstatus:
        !          1023:  *
        !          1024:  *     Set the status of the specified thread.
        !          1025:  *     Called with (and returns with) no locks held.
        !          1026:  */
        !          1027: kern_return_t
        !          1028: thread_setstatus(
        !          1029:        thread_act_t            thr_act,
        !          1030:        int                     flavor,
        !          1031:        thread_state_t          tstate,
        !          1032:        mach_msg_type_number_t  count)
        !          1033: {
        !          1034:        kern_return_t           kr;
        !          1035:        thread_t                thread;
        !          1036: 
        !          1037:        thread = act_lock_thread(thr_act);
        !          1038:        assert(thread);
        !          1039:        assert(thread->top_act == thr_act);
        !          1040:        kr = act_machine_set_state(thr_act, flavor, tstate, count);
        !          1041:        act_unlock_thread(thr_act);
        !          1042:        return(kr);
        !          1043: }
        !          1044: 
        !          1045: /*
        !          1046:  *     thread_getstatus:
        !          1047:  *
        !          1048:  *     Get the status of the specified thread.
        !          1049:  */
        !          1050: kern_return_t
        !          1051: thread_getstatus(
        !          1052:        thread_act_t            thr_act,
        !          1053:        int                     flavor,
        !          1054:        thread_state_t          tstate,
        !          1055:        mach_msg_type_number_t  *count)
        !          1056: {
        !          1057:        kern_return_t           kr;
        !          1058:        thread_t                thread;
        !          1059: 
        !          1060:        thread = act_lock_thread(thr_act);
        !          1061:        assert(thread);
        !          1062:        assert(thread->top_act == thr_act);
        !          1063:        kr = act_machine_get_state(thr_act, flavor, tstate, count);
        !          1064:        act_unlock_thread(thr_act);
        !          1065:        return(kr);
        !          1066: }
        !          1067: 
        !          1068: /*
        !          1069:  * Kernel-internal thread_activation interfaces used outside this file:
        !          1070:  */
        !          1071: 
        !          1072: /*
        !          1073:  * act_init()  - Initialize activation handling code
        !          1074:  */
        !          1075: void
        !          1076: act_init()
        !          1077: {
        !          1078:        thr_act_zone = zinit(
        !          1079:                        sizeof(struct thread_activation),
        !          1080:                        ACT_MAX * sizeof(struct thread_activation), /* XXX */
        !          1081:                        ACT_CHUNK * sizeof(struct thread_activation),
        !          1082:                        "activations");
        !          1083:        act_machine_init();
        !          1084: }
        !          1085: 
        !          1086: 
        !          1087: /*
        !          1088:  * act_create  - Create a new activation in a specific task.
        !          1089:  */
        !          1090: kern_return_t
        !          1091: act_create(task_t task,
        !          1092:            thread_act_params_t params,
        !          1093:            thread_act_t *new_act)
        !          1094: {
        !          1095:        thread_act_t thr_act;
        !          1096:        int rc;
        !          1097:        vm_map_t map;
        !          1098: 
        !          1099:        thr_act = (thread_act_t)zalloc(thr_act_zone);
        !          1100:        if (thr_act == 0)
        !          1101:                return(KERN_RESOURCE_SHORTAGE);
        !          1102: 
        !          1103: #if    MACH_ASSERT
        !          1104:        if (watchacts & WA_ACT_LNK)
        !          1105:                printf("act_create(task=%x,stk=%x,thr_act@%x=%x)\n",
        !          1106:                        task, params ? params->stack : 0, new_act, thr_act);
        !          1107: #endif /* MACH_ASSERT */
        !          1108: 
        !          1109:        /* Start by zeroing everything; then init non-zero items only */
        !          1110:        bzero((char *)thr_act, sizeof(*thr_act));
        !          1111: 
        !          1112:        /* Start with one reference for being active, another for the caller */
        !          1113:        act_lock_init(thr_act);
        !          1114:        thr_act->ref_count = 2;
        !          1115: 
        !          1116:        /* Latch onto the task.  */
        !          1117:        thr_act->task = task;
        !          1118:        task_reference(task);
        !          1119:        thr_act->active = 1;
        !          1120: 
        !          1121:        /* Initialize sigbufp for High-Watermark buffer allocation */
        !          1122:         thr_act->r_sigbufp = (routine_descriptor_t) &thr_act->r_sigbuf;
        !          1123:         thr_act->r_sigbuf_size = sizeof(thr_act->r_sigbuf);
        !          1124: 
        !          1125:        /* Initialize thread stack */
        !          1126:         if (params)
        !          1127:         {
        !          1128:                 thr_act->user_stack = params->stack;
        !          1129:                 thr_act->user_stack_size = params->stack_size;
        !          1130:                 thr_act->user_entry = params->entry_func;
        !          1131:         }
        !          1132:         else
        !          1133:         {
        !          1134:                 thr_act->user_stack = 0;
        !          1135:                 thr_act->user_stack_size = 0;
        !          1136:                 thr_act->user_entry = 0;
        !          1137:         }
        !          1138: 
        !          1139: #if    THREAD_SWAPPER
        !          1140:        thr_act->swap_state = TH_SW_IN;
        !          1141: #if    MACH_ASSERT
        !          1142:        thr_act->kernel_stack_swapped_in = TRUE;
        !          1143: #if    THREAD_SWAP_UNWIRE_USER_STACK
        !          1144:        thr_act->user_stack_swapped_in = TRUE;
        !          1145: #endif /* THREAD_SWAP_UNWIRE_USER_STACK */
        !          1146: #endif /* MACH_ASSERT */
        !          1147: #endif /* THREAD_SWAPPER */
        !          1148: 
        !          1149:        /* special_handler will always be last on the returnhandlers list.  */
        !          1150:        thr_act->special_handler.next = 0;
        !          1151:        thr_act->special_handler.handler = special_handler;
        !          1152: 
        !          1153: #if    MACH_PROF
        !          1154:        thr_act->act_profiled = FALSE;
        !          1155:        thr_act->act_profiled_own = FALSE;
        !          1156:        thr_act->profil_buffer = NULLPROFDATA;
        !          1157: #endif
        !          1158: 
        !          1159:        /* Initialize the held_ulocks queue as empty */
        !          1160:        queue_init(&thr_act->held_ulocks);
        !          1161: 
        !          1162:        /* Inherit the profiling status of the parent task */
        !          1163:        act_prof_init(thr_act, task);
        !          1164: 
        !          1165:        ipc_thr_act_init(task, thr_act);
        !          1166:        act_machine_create(task, thr_act);
        !          1167: 
        !          1168:        /*
        !          1169:         * If thr_act created in kernel-loaded task, alter its saved
        !          1170:         * state to so indicate
        !          1171:         */
        !          1172:        if (task->kernel_loaded) {
        !          1173:                act_user_to_kernel(thr_act);
        !          1174:                /*
        !          1175:                 * If a user_stack was given, assume this is not a "base"
        !          1176:                 * activation -- assert that it's fully kernel-loaded
        !          1177:                 * already.
        !          1178:                 */
        !          1179:                if (thr_act->user_stack != 0) {
        !          1180:                        thr_act->kernel_loading = FALSE;
        !          1181:                        thr_act->kernel_loaded = TRUE;
        !          1182:                }
        !          1183:        }
        !          1184: 
        !          1185:        task_lock(task);
        !          1186: 
        !          1187:        /* Chain the thr_act onto the task's list */
        !          1188:        mutex_lock(&task->act_list_lock);
        !          1189:        queue_enter(&task->thr_acts, thr_act, thread_act_t, thr_acts);
        !          1190:        task->thr_act_count++;
        !          1191:        /* no need to check for transition from 0 -> 1 here */
        !          1192:        task->res_act_count++;
        !          1193:        mutex_unlock(&task->act_list_lock);
        !          1194: 
        !          1195:        task_unlock(task);
        !          1196: 
        !          1197:        /* Cache the task's map and take a reference to it */
        !          1198:        thr_act->map = task->map;
        !          1199: 
        !          1200:        /* Inline vm_map_reference cause we don't want to increment res_count */
        !          1201:        map = task->map;
        !          1202:        mutex_lock(&map->s_lock);
        !          1203: #if    TASK_SWAPPER
        !          1204:        assert(map->res_count > 0);
        !          1205:        assert(map->ref_count >= map->res_count);
        !          1206: #endif /* TASK_SWAPPER */
        !          1207:        map->ref_count++;
        !          1208:        mutex_unlock(&map->s_lock);
        !          1209: 
        !          1210:        *new_act = thr_act;
        !          1211:        return KERN_SUCCESS;
        !          1212: }
        !          1213: 
        !          1214: /*
        !          1215:  * act_free    - called when an thr_act's ref_count drops to zero.
        !          1216:  *
        !          1217:  * This can only happen when thread is zero (not in use),
        !          1218:  * thread_pool is zero (not attached to any thread_pool),
        !          1219:  * and active is false (terminated).  Called with act locked,
        !          1220:  * so that its shuttle pointer can be zeroed atomically.
        !          1221:  */
        !          1222: #if    MACH_ASSERT
        !          1223: int    dangerous_bzero = 1;    /* paranoia & safety */
        !          1224: #endif
        !          1225: 
        !          1226: void
        !          1227: act_free(thread_act_t thr_act)
        !          1228: {
        !          1229:        thread_t        thr;
        !          1230:        vm_map_t        map;
        !          1231:        unsigned int    ref;
        !          1232: 
        !          1233: #if    MACH_ASSERT
        !          1234:        if (watchacts & WA_EXIT)
        !          1235:                printf("act_free(%x(%d)) thr=%x tsk=%x(%d) pport=%x%sactive\n",
        !          1236:                        thr_act, thr_act->ref_count, thr_act->thread,
        !          1237:                        thr_act->task,
        !          1238:                        thr_act->task ? thr_act->task->ref_count : 0,
        !          1239:                        thr_act->pool_port,
        !          1240:                        thr_act->active ? " " : " !");
        !          1241: #endif /* MACH_ASSERT */
        !          1242: 
        !          1243:        /* Drop final ref to shuttle (not really ours, but we're
        !          1244:         * allowed to handle it). */
        !          1245:        if (thr = thr_act->thread) {
        !          1246:                thr_act->thread = 0;
        !          1247:                act_unlock(thr_act);
        !          1248:                thread_deallocate(thr);
        !          1249:        }
        !          1250:        else
        !          1251:                act_unlock(thr_act);
        !          1252: 
        !          1253: #if    THREAD_SWAPPER
        !          1254:        thread_swap_disable(thr_act);
        !          1255:        assert(thr_act->kernel_stack_swapped_in);
        !          1256: #endif /* THREAD_SWAPPER */
        !          1257: 
        !          1258:        assert(!thr_act->active);
        !          1259:        assert(!thr_act->pool_port);
        !          1260: 
        !          1261:        act_machine_destroy(thr_act);
        !          1262:        ipc_thr_act_disable(thr_act);
        !          1263:        ipc_thr_act_terminate(thr_act);
        !          1264: 
        !          1265:        act_prof_deallocate(thr_act);
        !          1266: 
        !          1267:        /*
        !          1268:         * Drop the cached map reference.
        !          1269:         * Inline version of vm_map_deallocate() because we
        !          1270:         * don't want to decrement the map's residence count here.
        !          1271:         */
        !          1272:        map = thr_act->map;
        !          1273:        mutex_lock(&map->s_lock);
        !          1274: #if    TASK_SWAPPER
        !          1275:        assert(map->res_count >= 0);
        !          1276:        assert(map->ref_count > map->res_count);
        !          1277: #endif /* TASK_SWAPPER */
        !          1278:        ref = --map->ref_count;
        !          1279:        mutex_unlock(&map->s_lock);
        !          1280: 
        !          1281:        /*
        !          1282:         * The task must still have a reference on the map.  Also, if
        !          1283:         * the reference count drops to two (one remaining act and the
        !          1284:         * task itself), then someone may be waiting in task_halt_wait.
        !          1285:         * Wake them up, if needed.
        !          1286:         */
        !          1287:        if (ref == 0)
        !          1288:                panic("thread_deallocate: released last reference on map");
        !          1289:        else if (ref == 2)
        !          1290:                thread_wakeup(&map->ref_count);
        !          1291:                
        !          1292:        /* Drop the task reference.  */
        !          1293:        task_deallocate(thr_act->task);
        !          1294: 
        !          1295: #if    MACH_ASSERT
        !          1296:        if (dangerous_bzero)    /* dangerous if we're still using it! */
        !          1297:                bzero((char *)thr_act, sizeof(*thr_act));
        !          1298: #endif /* MACH_ASSERT */
        !          1299:        /* Put the thr_act back on the thr_act zone */
        !          1300:        zfree(thr_act_zone, (vm_offset_t)thr_act);
        !          1301: }
        !          1302: 
        !          1303: 
        !          1304: /*
        !          1305:  * act_attach  - Attach an thr_act to the top of a thread ("push the stack").
        !          1306:  *
        !          1307:  * The thread_shuttle must be either the current one or a brand-new one.
        !          1308:  * Assumes the thr_act is active but not in use, also, that if it is
        !          1309:  * attached to an thread_pool (i.e. the thread_pool pointer is nonzero),
        !          1310:  * the thr_act has already been taken off the thread_pool's list.
        !          1311:  *
        !          1312:  * Already locked: thr_act plus "appropriate" thread-related locks
        !          1313:  * (see act_lock_thread()).
        !          1314:  */
        !          1315: void 
        !          1316: act_attach(
        !          1317:        thread_act_t    thr_act,
        !          1318:        thread_t        thread,
        !          1319:        unsigned        init_alert_mask)
        !          1320: {
        !          1321:         thread_act_t    lower;
        !          1322: 
        !          1323: #if    MACH_ASSERT
        !          1324:        assert(thread == current_thread() || thread->top_act == THR_ACT_NULL);
        !          1325:        if (watchacts & WA_ACT_LNK)
        !          1326:                printf("act_attach(thr_act %x(%d) thread %x(%d) mask %d)\n",
        !          1327:                       thr_act, thr_act->ref_count, thread, thread->ref_count,
        !          1328:                       init_alert_mask);
        !          1329: #endif /* MACH_ASSERT */
        !          1330: 
        !          1331:        /* 
        !          1332:         *      Chain the thr_act onto the thread's thr_act stack.  
        !          1333:         *      Set mask and auto-propagate alerts from below.
        !          1334:         */
        !          1335:        thr_act->thread = thread;
        !          1336:        thr_act->higher = THR_ACT_NULL;  /*safety*/
        !          1337:        thr_act->alerts = 0;
        !          1338:        thr_act->alert_mask = init_alert_mask;
        !          1339:        lower = thr_act->lower = thread->top_act;
        !          1340: 
        !          1341:         if (lower != THR_ACT_NULL) {
        !          1342:                 lower->higher = thr_act;
        !          1343:                 thr_act->alerts = (lower->alerts & init_alert_mask);
        !          1344:         }
        !          1345: 
        !          1346:        thread->top_act = thr_act;
        !          1347: }
        !          1348: 
        !          1349: /*
        !          1350:  *     act_detach      
        !          1351:  *
        !          1352:  *     Remove the current thr_act from the top of the current thread, i.e.
        !          1353:  *     "pop the stack". Assumes already locked: thr_act plus "appropriate"
        !          1354:  *     thread-related locks (see act_lock_thread).
        !          1355:  */
        !          1356: void 
        !          1357: act_detach(
        !          1358:        thread_act_t    cur_act)
        !          1359: {
        !          1360:        thread_t        cur_thread = cur_act->thread;
        !          1361: 
        !          1362: #if    MACH_ASSERT
        !          1363:        if (watchacts & (WA_EXIT|WA_ACT_LNK))
        !          1364:                printf("act_detach: thr_act %x(%d), thrd %x(%d) task=%x(%d)\n",
        !          1365:                       cur_act, cur_act->ref_count,
        !          1366:                       cur_thread, cur_thread->ref_count,
        !          1367:                       cur_act->task,
        !          1368:                       cur_act->task ? cur_act->task->ref_count : 0);
        !          1369: #endif /* MACH_ASSERT */
        !          1370: 
        !          1371:        /* Unlink the thr_act from the thread's thr_act stack */
        !          1372:        cur_thread->top_act = cur_act->lower;
        !          1373:        cur_act->thread = 0;
        !          1374: 
        !          1375:        thread_pool_put_act(cur_act);
        !          1376: 
        !          1377: #if    MACH_ASSERT
        !          1378:        cur_act->lower = cur_act->higher = THR_ACT_NULL; 
        !          1379:        if (cur_thread->top_act)
        !          1380:                cur_thread->top_act->higher = THR_ACT_NULL;
        !          1381: #endif /* MACH_ASSERT */
        !          1382: 
        !          1383:        return;
        !          1384: }
        !          1385: 
        !          1386: 
        !          1387: /*
        !          1388:  * Synchronize a thread operation with RPC.  Called with nothing
        !          1389:  * locked.   Returns with thr_act locked, plus one of four
        !          1390:  * combinations of other locks held:
        !          1391:  *     none - for new activation not yet associated with thread_pool
        !          1392:  *             or shuttle
        !          1393:  *     rpc_lock(thr_act->thread) only - for base activation (one
        !          1394:  *             without pool_port)
        !          1395:  *     ip_lock(thr_act->pool_port) only - for empty activation (one
        !          1396:  *             with no associated shuttle)
        !          1397:  *     both locks - for "active" activation (has shuttle, lives
        !          1398:  *             on thread_pool)
        !          1399:  * If thr_act has an associated shuttle, this function returns
        !          1400:  * its address.  Otherwise it returns zero.
        !          1401:  */
        !          1402: thread_t
        !          1403: act_lock_thread(
        !          1404:        thread_act_t thr_act)
        !          1405: {
        !          1406:        ipc_port_t pport;
        !          1407: 
        !          1408:        /*
        !          1409:         * Allow the shuttle cloning code (q.v., when it
        !          1410:         * exists :-}) to obtain ip_lock()'s while holding
        !          1411:         * an rpc_lock().
        !          1412:         */
        !          1413:        while (1) {
        !          1414:                act_lock(thr_act);
        !          1415:                pport = thr_act->pool_port;
        !          1416:                if (!pport || ip_lock_try(pport)) {
        !          1417:                        if (!thr_act->thread)
        !          1418:                                break;
        !          1419:                        if (rpc_lock_try(thr_act->thread))
        !          1420:                                break;
        !          1421:                        if (pport)
        !          1422:                                ip_unlock(pport);
        !          1423:                }
        !          1424:                act_unlock(thr_act);
        !          1425:                mutex_pause();
        !          1426:        }
        !          1427:        return (thr_act->thread);
        !          1428: }
        !          1429: 
        !          1430: /*
        !          1431:  * Unsynchronize with RPC (i.e., undo an act_lock_thread() call).
        !          1432:  * Called with thr_act locked, plus thread locks held that are
        !          1433:  * "correct" for thr_act's state.  Returns with nothing locked.
        !          1434:  */
        !          1435: void
        !          1436: act_unlock_thread(thread_act_t thr_act)
        !          1437: {
        !          1438:        if (thr_act->thread)
        !          1439:                rpc_unlock(thr_act->thread);
        !          1440:        if (thr_act->pool_port)
        !          1441:                ip_unlock(thr_act->pool_port);
        !          1442:        act_unlock(thr_act);
        !          1443: }
        !          1444: 
        !          1445: /*
        !          1446:  * Synchronize with RPC given a pointer to a shuttle (instead of an
        !          1447:  * activation).  Called with nothing locked; returns with all
        !          1448:  * "appropriate" thread-related locks held (see act_lock_thread()).
        !          1449:  */
        !          1450: thread_act_t
        !          1451: thread_lock_act(
        !          1452:        thread_t        thread)
        !          1453: {
        !          1454:        thread_act_t    thr_act;
        !          1455: 
        !          1456:        while (1) {
        !          1457:                rpc_lock(thread);
        !          1458:                thr_act = thread->top_act;
        !          1459:                if (!thr_act)
        !          1460:                        break;
        !          1461:                if (!act_lock_try(thr_act)) {
        !          1462:                        rpc_unlock(thread);
        !          1463:                        mutex_pause();
        !          1464:                        continue;
        !          1465:                }
        !          1466:                if (thr_act->pool_port &&
        !          1467:                        !ip_lock_try(thr_act->pool_port)) {
        !          1468:                        rpc_unlock(thread);
        !          1469:                        act_unlock(thr_act);
        !          1470:                        mutex_pause();
        !          1471:                        continue;
        !          1472:                }
        !          1473:                break;
        !          1474:        }
        !          1475:        return (thr_act);
        !          1476: }
        !          1477: 
        !          1478: /*
        !          1479:  * Unsynchronize with RPC starting from a pointer to a shuttle.
        !          1480:  * Called with RPC-related locks held that are appropriate to
        !          1481:  * shuttle's state; any activation is also locked.
        !          1482:  */
        !          1483: void
        !          1484: thread_unlock_act(
        !          1485:        thread_t        thread)
        !          1486: {
        !          1487:        thread_act_t    thr_act;
        !          1488: 
        !          1489:        if (thr_act = thread->top_act) {
        !          1490:                if (thr_act->pool_port)
        !          1491:                        ip_unlock(thr_act->pool_port);
        !          1492:                act_unlock(thr_act);
        !          1493:        }
        !          1494:        rpc_unlock(thread);
        !          1495: }
        !          1496: 
        !          1497: /*
        !          1498:  * switch_act
        !          1499:  *
        !          1500:  * If a new activation is given, switch to it. If not,
        !          1501:  * switch to the lower activation (pop). Returns the old
        !          1502:  * activation. This is for RPC support.
        !          1503:  */
        !          1504: thread_act_t
        !          1505: switch_act( 
        !          1506:        thread_act_t act)
        !          1507: {
        !          1508:        thread_t        thread;
        !          1509:        thread_act_t    old, new;
        !          1510:        unsigned        cpu;
        !          1511:        spl_t           spl;
        !          1512: 
        !          1513: 
        !          1514:        disable_preemption();
        !          1515: 
        !          1516:        cpu = cpu_number();
        !          1517:        thread  = current_thread();
        !          1518: 
        !          1519:        /*
        !          1520:         *      Find the old and new activation for switch.
        !          1521:         */
        !          1522:        old = thread->top_act;
        !          1523: 
        !          1524:        if (act) {
        !          1525:                new = act;
        !          1526:                 new->thread = thread;
        !          1527:        }
        !          1528:        else {
        !          1529:                new = old->lower;
        !          1530:        }
        !          1531: 
        !          1532:        assert(new != THR_ACT_NULL);
        !          1533: #if    THREAD_SWAPPER
        !          1534:        assert(new->swap_state != TH_SW_OUT &&
        !          1535:               new->swap_state != TH_SW_COMING_IN);
        !          1536: #endif /* THREAD_SWAPPER */
        !          1537: 
        !          1538:         assert(cpu_data[cpu].active_thread == thread);
        !          1539:        active_kloaded[cpu] = (new->kernel_loaded) ? new : 0;
        !          1540: 
        !          1541:        /* This is where all the work happens */
        !          1542:        machine_switch_act(thread, old, new, cpu);
        !          1543: 
        !          1544:        /*
        !          1545:         *      Push or pop an activation on the chain.
        !          1546:         */
        !          1547:        if (act) {
        !          1548:                act_attach(new, thread, 0);
        !          1549:        }
        !          1550:        else {
        !          1551:                act_detach(old);
        !          1552:        }
        !          1553: 
        !          1554:         enable_preemption();
        !          1555: 
        !          1556:        return(old);
        !          1557: }
        !          1558: 
        !          1559: /*
        !          1560:  * install_special_handler
        !          1561:  *     Install the special returnhandler that handles suspension and
        !          1562:  *     termination, if it hasn't been installed already.
        !          1563:  *
        !          1564:  * Already locked: RPC-related locks for thr_act, but not
        !          1565:  * scheduling lock (thread_lock()) of the associated thread.
        !          1566:  */
        !          1567: void
        !          1568: install_special_handler(
        !          1569:        thread_act_t    thr_act)
        !          1570: {
        !          1571:        spl_t           spl;
        !          1572:        thread_t        thread = thr_act->thread;
        !          1573: 
        !          1574: #if    MACH_ASSERT
        !          1575:        if (watchacts & WA_ACT_HDLR)
        !          1576:            printf("act_%x: install_special_hdlr(%x)\n",current_act(),thr_act);
        !          1577: #endif /* MACH_ASSERT */
        !          1578: 
        !          1579:        spl = splsched();
        !          1580:        if (thread)
        !          1581:                thread_lock(thread);
        !          1582:        install_special_handler_locked(thr_act);
        !          1583:        act_set_apc(thr_act);
        !          1584:        if (thread)
        !          1585:                thread_unlock(thread);
        !          1586:        splx(spl);
        !          1587: }
        !          1588: 
        !          1589: /*
        !          1590:  * install_special_handler_locked
        !          1591:  *     Do the work of installing the special_handler.
        !          1592:  *
        !          1593:  * Already locked: RPC-related locks for thr_act, plus the
        !          1594:  * scheduling lock (thread_lock()) of the associated thread.
        !          1595:  */
        !          1596: void
        !          1597: install_special_handler_locked(
        !          1598:        thread_act_t    thr_act)
        !          1599: {
        !          1600:        ReturnHandler   **rh;
        !          1601:        thread_t        thread = thr_act->thread;
        !          1602: 
        !          1603:        /* The work handler must always be the last ReturnHandler on the list,
        !          1604:           because it can do tricky things like detach the thr_act.  */
        !          1605:        for (rh = &thr_act->handlers; *rh; rh = &(*rh)->next)
        !          1606:                /* */ ;
        !          1607:        if (rh != &thr_act->special_handler.next) {
        !          1608:                *rh = &thr_act->special_handler;
        !          1609:        }
        !          1610:        if (thread && thr_act == thread->top_act) {
        !          1611:                /*
        !          1612:                 * Temporarily undepress, so target has
        !          1613:                 * a chance to do locking required to
        !          1614:                 * block itself in special_handler().
        !          1615:                 */
        !          1616:                /*** ??? fix me ***/
        !          1617:                assert(thread->sp_info != SP_INFO_NULL);
        !          1618:                if (((thread->policy == POLICY_TIMESHARE) ||
        !          1619:                     (thread->policy == POLICY_RR) ||
        !          1620:                     (thread->policy == POLICY_FIFO)) &&
        !          1621:                    ((mk_sp_info_t)thread->sp_info)->depress_priority >= 0) {
        !          1622:                        ((mk_sp_info_t)thread->sp_info)->priority = ((mk_sp_info_t)thread->sp_info)->depress_priority;
        !          1623:                        /* Use special value -2 to indicate need
        !          1624:                         * to redepress priority in special_handler
        !          1625:                         * as thread blocks
        !          1626:                         */
        !          1627:                        ((mk_sp_info_t)thread->sp_info)->depress_priority = -2;
        !          1628:                        compute_priority(thread, FALSE);
        !          1629:                }       
        !          1630:        }
        !          1631:        act_set_apc(thr_act);
        !          1632: }
        !          1633: 
        !          1634: /*
        !          1635:  * JMM -
        !          1636:  * These two routines will be enhanced over time to call the general handler registration
        !          1637:  * mechanism used by special handlers and alerts.  They are hack in for now to avoid
        !          1638:  * having to export the gory details of ASTs to the BSD code right now.
        !          1639:  */
        !          1640: extern thread_apc_handler_t bsd_ast;
        !          1641: 
        !          1642: kern_return_t
        !          1643: thread_apc_set(
        !          1644:        thread_act_t thr_act,
        !          1645:        thread_apc_handler_t apc)
        !          1646: {
        !          1647:        assert(apc == bsd_ast);
        !          1648:        thread_ast_set(thr_act, AST_BSD);
        !          1649:        if (thr_act == current_act())
        !          1650:                ast_propagate(thr_act->ast);
        !          1651:        return KERN_SUCCESS;
        !          1652: }
        !          1653: 
        !          1654: kern_return_t
        !          1655: thread_apc_clear(
        !          1656:        thread_act_t thr_act,
        !          1657:        thread_apc_handler_t apc)
        !          1658: {
        !          1659:        assert(apc == bsd_ast);
        !          1660:        thread_ast_clear(thr_act, AST_BSD);
        !          1661:        if (thr_act == current_act())
        !          1662:                ast_off(AST_BSD);
        !          1663:        return KERN_SUCCESS;
        !          1664: }
        !          1665: 
        !          1666: /*
        !          1667:  * act_set_thread_pool - Assign an activation to a specific thread_pool.
        !          1668:  * Fails if the activation is already assigned to another pool.
        !          1669:  * If thread_pool == 0, we remove the thr_act from its thread_pool.
        !          1670:  *
        !          1671:  * Called the port containing thread_pool already locked.
        !          1672:  * Returns the same way.
        !          1673:  */
        !          1674: kern_return_t act_set_thread_pool(
        !          1675:        thread_act_t    thr_act,
        !          1676:        ipc_port_t      pool_port)
        !          1677: {
        !          1678:        thread_pool_t   thread_pool;
        !          1679: 
        !          1680: #if    MACH_ASSERT
        !          1681:        if (watchacts & WA_ACT_LNK)
        !          1682:                printf("act_set_thread_pool: %x(%d) -> %x\n",
        !          1683:                        thr_act, thr_act->ref_count, thread_pool);
        !          1684: #endif /* MACH_ASSERT */
        !          1685: 
        !          1686:        if (pool_port == 0) {
        !          1687:                thread_act_t *lact;
        !          1688: 
        !          1689:                if (thr_act->pool_port == 0)
        !          1690:                        return KERN_SUCCESS;
        !          1691:                thread_pool = &thr_act->pool_port->ip_thread_pool;
        !          1692: 
        !          1693:                for (lact = &thread_pool->thr_acts; *lact;
        !          1694:                                        lact = &((*lact)->thread_pool_next)) {
        !          1695:                        if (thr_act == *lact) {
        !          1696:                                *lact = thr_act->thread_pool_next;
        !          1697:                                break;
        !          1698:                        }
        !          1699:                }
        !          1700:                act_lock(thr_act);
        !          1701:                thr_act->pool_port = 0;
        !          1702:                thr_act->thread_pool_next = 0;
        !          1703:                act_unlock(thr_act);
        !          1704:                act_deallocate(thr_act);
        !          1705:                return KERN_SUCCESS;
        !          1706:        }
        !          1707:        if (thr_act->pool_port != pool_port) {
        !          1708:                thread_pool = &pool_port->ip_thread_pool;
        !          1709:                if (thr_act->pool_port != 0) {
        !          1710: #if    MACH_ASSERT
        !          1711:                        if (watchacts & WA_ACT_LNK)
        !          1712:                            printf("act_set_thread_pool found %x!\n",
        !          1713:                                                        thr_act->pool_port);
        !          1714: #endif /* MACH_ASSERT */
        !          1715:                        return(KERN_FAILURE);
        !          1716:                }
        !          1717:                act_lock(thr_act);
        !          1718:                thr_act->pool_port = pool_port;
        !          1719: 
        !          1720:                /* The pool gets a ref to the activation -- have
        !          1721:                 * to inline operation because thr_act is already
        !          1722:                 * locked.
        !          1723:                 */
        !          1724:                act_locked_act_reference(thr_act);
        !          1725: 
        !          1726:                /* If it is available,
        !          1727:                 * add it to the thread_pool's available-activation list.
        !          1728:                 */
        !          1729:                if ((thr_act->thread == 0) && (thr_act->suspend_count == 0)) {
        !          1730:                        thr_act->thread_pool_next = thread_pool->thr_acts;
        !          1731:                        pool_port->ip_thread_pool.thr_acts = thr_act;
        !          1732:                        if (thread_pool->waiting)
        !          1733:                                thread_pool_wakeup(thread_pool);
        !          1734:                }
        !          1735:                act_unlock(thr_act);
        !          1736:        }
        !          1737: 
        !          1738:        return KERN_SUCCESS;
        !          1739: }
        !          1740: 
        !          1741: /*
        !          1742:  * act_locked_act_set_thread_pool- Assign activation to a specific thread_pool.
        !          1743:  * Fails if the activation is already assigned to another pool.
        !          1744:  * If thread_pool == 0, we remove the thr_act from its thread_pool.
        !          1745:  *
        !          1746:  * Called the port containing thread_pool already locked.
        !          1747:  * Also called with the thread activation locked.
        !          1748:  * Returns the same way.
        !          1749:  *
        !          1750:  * This routine is the same as `act_set_thread_pool()' except that it does
        !          1751:  * not call `act_deallocate(),' which unconditionally tries to obtain the
        !          1752:  * thread activation lock.
        !          1753:  */
        !          1754: kern_return_t act_locked_act_set_thread_pool(
        !          1755:        thread_act_t    thr_act,
        !          1756:        ipc_port_t      pool_port)
        !          1757: {
        !          1758:        thread_pool_t   thread_pool;
        !          1759: 
        !          1760: #if    MACH_ASSERT
        !          1761:        if (watchacts & WA_ACT_LNK)
        !          1762:                printf("act_set_thread_pool: %x(%d) -> %x\n",
        !          1763:                        thr_act, thr_act->ref_count, thread_pool);
        !          1764: #endif /* MACH_ASSERT */
        !          1765: 
        !          1766:        if (pool_port == 0) {
        !          1767:                thread_act_t *lact;
        !          1768: 
        !          1769:                if (thr_act->pool_port == 0)
        !          1770:                        return KERN_SUCCESS;
        !          1771:                thread_pool = &thr_act->pool_port->ip_thread_pool;
        !          1772: 
        !          1773:                for (lact = &thread_pool->thr_acts; *lact;
        !          1774:                                        lact = &((*lact)->thread_pool_next)) {
        !          1775:                        if (thr_act == *lact) {
        !          1776:                                *lact = thr_act->thread_pool_next;
        !          1777:                                break;
        !          1778:                        }
        !          1779:                }
        !          1780: 
        !          1781:                thr_act->pool_port = 0;
        !          1782:                thr_act->thread_pool_next = 0;
        !          1783:                act_locked_act_deallocate(thr_act);
        !          1784:                return KERN_SUCCESS;
        !          1785:        }
        !          1786:        if (thr_act->pool_port != pool_port) {
        !          1787:                thread_pool = &pool_port->ip_thread_pool;
        !          1788:                if (thr_act->pool_port != 0) {
        !          1789: #if    MACH_ASSERT
        !          1790:                        if (watchacts & WA_ACT_LNK)
        !          1791:                            printf("act_set_thread_pool found %x!\n",
        !          1792:                                                        thr_act->pool_port);
        !          1793: #endif /* MACH_ASSERT */
        !          1794:                        return(KERN_FAILURE);
        !          1795:                }
        !          1796:                thr_act->pool_port = pool_port;
        !          1797: 
        !          1798:                /* The pool gets a ref to the activation -- have
        !          1799:                 * to inline operation because thr_act is already
        !          1800:                 * locked.
        !          1801:                 */
        !          1802:                act_locked_act_reference(thr_act);
        !          1803: 
        !          1804:                /* If it is available,
        !          1805:                 * add it to the thread_pool's available-activation list.
        !          1806:                 */
        !          1807:                if ((thr_act->thread == 0) && (thr_act->suspend_count == 0)) {
        !          1808:                        thr_act->thread_pool_next = thread_pool->thr_acts;
        !          1809:                        pool_port->ip_thread_pool.thr_acts = thr_act;
        !          1810:                        if (thread_pool->waiting)
        !          1811:                                thread_pool_wakeup(thread_pool);
        !          1812:                }
        !          1813:        }
        !          1814: 
        !          1815:        return KERN_SUCCESS;
        !          1816: }
        !          1817: 
        !          1818: /*
        !          1819:  * Activation control support routines internal to this file:
        !          1820:  */
        !          1821: 
        !          1822: /*
        !          1823:  * act_execute_returnhandlers()        - does just what the name says
        !          1824:  *
        !          1825:  * This is called by system-dependent code when it detects that
        !          1826:  * thr_act->handlers is non-null while returning into user mode.
        !          1827:  * Activations linked onto an thread_pool always have null thr_act->handlers,
        !          1828:  * so RPC entry paths need not check it.
        !          1829:  */
        !          1830: void act_execute_returnhandlers(
        !          1831:        void)
        !          1832: {
        !          1833:        spl_t           s;
        !          1834:        thread_t        thread;
        !          1835:        thread_act_t    thr_act = current_act();
        !          1836: 
        !          1837: #if    MACH_ASSERT
        !          1838:        if (watchacts & WA_ACT_HDLR)
        !          1839:                printf("execute_rtn_hdlrs: thr_act=%x\n", thr_act);
        !          1840: #endif /* MACH_ASSERT */
        !          1841: 
        !          1842:        s = splsched();
        !          1843:        act_clr_apc(thr_act);
        !          1844:        spllo();
        !          1845:        while (1) {
        !          1846:                ReturnHandler *rh;
        !          1847: 
        !          1848:                /* Grab the next returnhandler */
        !          1849:                thread = act_lock_thread(thr_act);
        !          1850:                (void)splsched();
        !          1851:                thread_lock(thread);
        !          1852:                rh = thr_act->handlers;
        !          1853:                if (!rh) {
        !          1854:                        thread_unlock(thread);
        !          1855:                        splx(s);
        !          1856:                        act_unlock_thread(thr_act);
        !          1857:                        return;
        !          1858:                }
        !          1859:                thr_act->handlers = rh->next;
        !          1860:                thread_unlock(thread);
        !          1861:                spllo();
        !          1862:                act_unlock_thread(thr_act);
        !          1863: 
        !          1864: #if    MACH_ASSERT
        !          1865:                if (watchacts & WA_ACT_HDLR)
        !          1866:                    printf( (rh == &thr_act->special_handler) ?
        !          1867:                        "\tspecial_handler\n" : "\thandler=%x\n",
        !          1868:                                    rh->handler);
        !          1869: #endif /* MACH_ASSERT */
        !          1870: 
        !          1871:                /* Execute it */
        !          1872:                (*rh->handler)(rh, thr_act);
        !          1873:        }
        !          1874: }
        !          1875: 
        !          1876: /*
        !          1877:  * special_handler     - handles suspension, termination.  Called
        !          1878:  * with nothing locked.  Returns (if it returns) the same way.
        !          1879:  */
        !          1880: void
        !          1881: special_handler(
        !          1882:        ReturnHandler   *rh,
        !          1883:        thread_act_t    cur_act)
        !          1884: {
        !          1885:        spl_t           s;
        !          1886:        thread_t        lthread;
        !          1887:        thread_t        thread = act_lock_thread(cur_act);
        !          1888:        unsigned        alert_bits;
        !          1889:        exception_data_type_t
        !          1890:                        codes[EXCEPTION_CODE_MAX];
        !          1891:        kern_return_t   kr;
        !          1892:        kern_return_t   exc_kr;
        !          1893: 
        !          1894:        assert(thread != THREAD_NULL);
        !          1895: #if    MACH_ASSERT
        !          1896:        if (watchacts & WA_ACT_HDLR)
        !          1897:            printf("\t\tspecial_handler(thr_act=%x(%d))\n", cur_act,
        !          1898:                                (cur_act ? cur_act->ref_count : 0));
        !          1899: #endif /* MACH_ASSERT */
        !          1900: 
        !          1901:        s = splsched();
        !          1902: 
        !          1903:        thread_lock(thread);
        !          1904:        thread->state &= ~TH_ABORT;     /* clear any aborts */
        !          1905:        thread_unlock(thread);
        !          1906: 
        !          1907:        /*
        !          1908:         * If someone has killed this invocation,
        !          1909:         * invoke the return path with a terminated exception.
        !          1910:         */
        !          1911:        if (!cur_act->active) {
        !          1912:                splx(s);
        !          1913:                act_unlock_thread(cur_act);
        !          1914:                act_machine_return(KERN_TERMINATED);
        !          1915:        }
        !          1916: 
        !          1917:        splx(s);
        !          1918: 
        !          1919:        /* strip server terminated bit */
        !          1920:        alert_bits = cur_act->alerts & (~SERVER_TERMINATED);
        !          1921: 
        !          1922:        /* clear server terminated bit */
        !          1923:        cur_act->alerts &= ~SERVER_TERMINATED;
        !          1924: 
        !          1925:        if ( alert_bits ) {
        !          1926:                /*
        !          1927:                 * currently necessary to coordinate with the exception 
        !          1928:                 * code -fdr
        !          1929:                 */
        !          1930:                act_unlock_thread(cur_act);
        !          1931: 
        !          1932:                /* upcall exception/alert port */
        !          1933:                codes[0] = alert_bits;
        !          1934: 
        !          1935:                /*
        !          1936:                 * Exception makes a lot of assumptions. If there is no
        !          1937:                 * exception handler or the exception reply is broken, the 
        !          1938:                 * thread will be terminated and exception will not return. If
        !          1939:                 * we decide we don't like that behavior, we need to check
        !          1940:                 * for the existence of an exception port before we call 
        !          1941:                 * exception.
        !          1942:                 */
        !          1943:                exc_kr = alert_exception( EXC_RPC_ALERT, codes, 1 );
        !          1944: 
        !          1945:                /* clear the orphaned and time constraint indications */
        !          1946:                cur_act->alerts &= ~(ORPHANED | TIME_CONSTRAINT_UNSATISFIED);
        !          1947: 
        !          1948:                /* if this orphaned activation should be terminated... */
        !          1949:                if (exc_kr == KERN_RPC_TERMINATE_ORPHAN) {
        !          1950:                        /*
        !          1951:                         * ... terminate the activation
        !          1952:                         *
        !          1953:                         * This is done in two steps.  First, the activation is
        !          1954:                         * disabled (prepared for termination); second, the
        !          1955:                         * `special_handler()' is executed again -- this time
        !          1956:                         * to terminate the activation.
        !          1957:                         * (`act_disable_task_locked()' arranges for the
        !          1958:                         * additional execution of the `special_handler().')
        !          1959:                         */
        !          1960: 
        !          1961: #if    THREAD_SWAPPER
        !          1962:                        thread_swap_disable(cur_act);
        !          1963: #endif /* THREAD_SWAPPER */
        !          1964: 
        !          1965:                        /* acquire appropriate locks */
        !          1966:                        task_lock(cur_act->task);
        !          1967:                        act_lock_thread(cur_act);
        !          1968: 
        !          1969:                        /* detach the activation from its task */
        !          1970:                        kr = act_disable_task_locked(cur_act);
        !          1971:                        assert( kr == KERN_SUCCESS );
        !          1972: 
        !          1973:                        /* release locks */
        !          1974:                        task_unlock(cur_act->task);
        !          1975:                }
        !          1976:                else {
        !          1977:                        /* acquire activation lock again (released below) */
        !          1978:                        act_lock_thread(cur_act);
        !          1979:                        s = splsched();
        !          1980:                        thread_lock(thread);
        !          1981:                        /*** ??? fix me ***/
        !          1982:                        assert(thread->sp_info != SP_INFO_NULL);
        !          1983:                        if (((thread->policy == POLICY_TIMESHARE) ||
        !          1984:                             (thread->policy == POLICY_RR) ||
        !          1985:                             (thread->policy == POLICY_FIFO)) &&
        !          1986:                            ((mk_sp_info_t)thread->sp_info)->depress_priority == -2) {
        !          1987:                                /* We were temporarily undepressed by
        !          1988:                                 * install_special_handler; restore priority
        !          1989:                                 * depression.
        !          1990:                                 */
        !          1991:                                ((mk_sp_info_t)thread->sp_info)->depress_priority = ((mk_sp_info_t)thread->sp_info)->priority;
        !          1992:                                ((mk_sp_info_t)thread->sp_info)->priority = DEPRESSPRI;
        !          1993:                                thread->sched_pri = DEPRESSPRI;
        !          1994:                        }
        !          1995:                        thread_unlock(thread);
        !          1996:                        splx(s);
        !          1997:                }
        !          1998:        }
        !          1999: 
        !          2000:        /*
        !          2001:         * If we're suspended, go to sleep and wait for someone to wake us up.
        !          2002:         */
        !          2003:        if (cur_act->suspend_count) {
        !          2004:                if( cur_act->handlers == NULL ) {
        !          2005:                        assert_wait((event_t)&cur_act->suspend_count,
        !          2006:                                    THREAD_ABORTSAFE);
        !          2007:                        act_unlock_thread(cur_act);
        !          2008:                        thread_block((void (*)(void))0);
        !          2009:                        act_lock_thread(cur_act);
        !          2010:                }
        !          2011: 
        !          2012:                /*
        !          2013:                 * If we're still (or again) suspended, go to sleep again
        !          2014:                 * after executing any new handlers that may have appeared.
        !          2015:                 */
        !          2016:                if (cur_act->suspend_count)
        !          2017:                        install_special_handler(cur_act);
        !          2018:                else {
        !          2019:                        s = splsched();
        !          2020:                        thread_lock(thread);
        !          2021:                        /*** ??? fix me ***/
        !          2022:                        assert(thread->sp_info != SP_INFO_NULL);
        !          2023:                        if (((thread->policy == POLICY_TIMESHARE) ||
        !          2024:                             (thread->policy == POLICY_RR) ||
        !          2025:                             (thread->policy == POLICY_FIFO)) &&
        !          2026:                            ((mk_sp_info_t)thread->sp_info)->depress_priority == -2) {
        !          2027:                                /* We were temporarily undepressed by
        !          2028:                                 * install_special_handler; restore priority
        !          2029:                                 * depression.
        !          2030:                                 */
        !          2031:                                ((mk_sp_info_t)thread->sp_info)->depress_priority = ((mk_sp_info_t)thread->sp_info)->priority;
        !          2032:                                ((mk_sp_info_t)thread->sp_info)->priority = DEPRESSPRI;
        !          2033:                                thread->sched_pri = DEPRESSPRI;
        !          2034:                        }
        !          2035:                        thread_unlock(thread);
        !          2036:                        splx(s);
        !          2037:                }
        !          2038:        }
        !          2039: 
        !          2040:        act_unlock_thread(cur_act);
        !          2041: }
        !          2042: 
        !          2043: /*
        !          2044:  * Try to nudge a thr_act into executing its returnhandler chain.
        !          2045:  * Ensures that the activation will execute its returnhandlers
        !          2046:  * before it next executes any of its user-level code.
        !          2047:  *
        !          2048:  * Called with thr_act's act_lock() and "appropriate" thread-related
        !          2049:  * locks held.  (See act_lock_thread().)  Returns same way.
        !          2050:  */
        !          2051: void
        !          2052: nudge(thread_act_t     thr_act)
        !          2053: {
        !          2054: #if    MACH_ASSERT
        !          2055:        if (watchacts & WA_ACT_HDLR)
        !          2056:            printf("\tact_%x: nudge(%x)\n", current_act(), thr_act);
        !          2057: #endif /* MACH_ASSERT */
        !          2058: 
        !          2059:        /*
        !          2060:         * Don't need to do anything at all if this thr_act isn't the topmost.
        !          2061:         */
        !          2062:        if (thr_act->thread && thr_act->thread->top_act == thr_act) {
        !          2063:                /*
        !          2064:                 * If it's suspended, wake it up. 
        !          2065:                 * This should nudge it even on another CPU.
        !          2066:                 */
        !          2067:                thread_wakeup((event_t)&thr_act->suspend_count);
        !          2068:        }
        !          2069: }
        !          2070: 
        !          2071: /*
        !          2072:  * Update activation that belongs to a task created via kernel_task_create().
        !          2073:  */
        !          2074: void
        !          2075: act_user_to_kernel(
        !          2076:        thread_act_t    thr_act)
        !          2077: {
        !          2078:        pcb_user_to_kernel(thr_act);
        !          2079:        thr_act->kernel_loading = TRUE;
        !          2080: }
        !          2081: 
        !          2082: /*
        !          2083:  * Already locked: thr_act->task, RPC-related locks for thr_act
        !          2084:  *
        !          2085:  * Detach an activation from its task, and prepare it to terminate
        !          2086:  * itself.
        !          2087:  */
        !          2088: kern_return_t
        !          2089: act_disable_task_locked(
        !          2090:        thread_act_t    thr_act)
        !          2091: {
        !          2092:        thread_t        thread = thr_act->thread;
        !          2093:        task_t          task = thr_act->task;
        !          2094: 
        !          2095: #if    MACH_ASSERT
        !          2096:        if (watchacts & WA_EXIT) {
        !          2097:                printf("act_%x: act_disable_tl(thr_act=%x(%d))%sactive task=%x(%d)",
        !          2098:                               current_act(), thr_act, thr_act->ref_count,
        !          2099:                               (thr_act->active ? " " : " !"),
        !          2100:                               thr_act->task, thr_act->task? thr_act->task->ref_count : 0);
        !          2101:                if (thr_act->pool_port)
        !          2102:                        printf(", pool_port %x", thr_act->pool_port);
        !          2103:                printf("\n");
        !          2104:                (void) dump_act(thr_act);
        !          2105:        }
        !          2106: #endif /* MACH_ASSERT */
        !          2107:        if (thr_act->thr_acts.next) {
        !          2108:                /* Unlink the thr_act from the task's thr_act list,
        !          2109:                 * so it doesn't appear in calls to task_threads and such.
        !          2110:                 * The thr_act still keeps its ref on the task, however.
        !          2111:                 */
        !          2112: #ifdef NOTEVER
        !          2113:                mutex_lock(&task->act_list_lock);
        !          2114: #if 1
        !          2115:                queue_remove(&task->thr_acts, thr_act, thread_act_t, thr_acts);
        !          2116: #else
        !          2117:                thr_act->thr_acts.next->prev = thr_act->thr_acts.prev;
        !          2118:                thr_act->thr_acts.prev->next = thr_act->thr_acts.next;
        !          2119: #endif /* 1 */
        !          2120:                thr_act->thr_acts.next = 0;
        !          2121:                task->thr_act_count--;
        !          2122: #if    THREAD_SWAPPER
        !          2123:                /*
        !          2124:                 * Thread is supposed to be unswappable by now...
        !          2125:                 */
        !          2126:                assert(thr_act->swap_state == TH_SW_UNSWAPPABLE ||
        !          2127:                       !(thread_swap_unwire_stack ||
        !          2128:                         thread_swap_unwire_user_stack));
        !          2129: #endif /* THREAD_SWAPPER */
        !          2130:                task->res_act_count--;
        !          2131:                mutex_unlock(&task->act_list_lock);
        !          2132: #endif /* NOTEVER */
        !          2133: 
        !          2134:                /* This will allow no more control ops on this thr_act. */
        !          2135:                thr_act->active = 0;
        !          2136: 
        !          2137:                /* Clean-up any ulocks that are still owned by the thread
        !          2138:                 * activation (acquired but not released or handed-off).
        !          2139:                 */
        !          2140:                act_ulock_release_all(thr_act);
        !          2141: 
        !          2142:                /* If not an empty activation, install special handler */
        !          2143:                if (thr_act->thread != THREAD_NULL) {
        !          2144: 
        !          2145:                        /* When the special_handler gets executed,
        !          2146:                         * it will see the terminated condition and exit
        !          2147:                         * immediately.
        !          2148:                         */
        !          2149:                        install_special_handler(thr_act);
        !          2150:                }
        !          2151: 
        !          2152:                /* If the target happens to be suspended,
        !          2153:                 * give it a nudge so it can exit.
        !          2154:                 */
        !          2155:                if (thr_act->suspend_count)
        !          2156:                        nudge(thr_act);
        !          2157:                /* Drop the thr_act reference taken for being active.
        !          2158:                 * (There is still at least one reference left:
        !          2159:                 * the one we were passed.)
        !          2160:                 * Inline the deallocate because thr_act is locked.
        !          2161:                 */
        !          2162:                act_locked_act_deallocate(thr_act);
        !          2163:        }
        !          2164: 
        !          2165:        return(KERN_SUCCESS);
        !          2166: }
        !          2167: 
        !          2168: /*
        !          2169:  * act_alert   - Register an alert from this activation.
        !          2170:  *
        !          2171:  * Each set bit is propagated upward from (but not including) this activation,
        !          2172:  * until the top of the chain is reached or the bit is masked.
        !          2173:  */
        !          2174: kern_return_t
        !          2175: act_alert(thread_act_t thr_act, unsigned alerts)
        !          2176: {
        !          2177:        thread_t thread = act_lock_thread(thr_act);
        !          2178: 
        !          2179: #if    MACH_ASSERT
        !          2180:        if (watchacts & WA_ACT_LNK)
        !          2181:                printf("act_alert %x: %x\n", thr_act, alerts);
        !          2182: #endif /* MACH_ASSERT */
        !          2183: 
        !          2184:        if (thread) {
        !          2185:                thread_act_t act_up = thr_act;
        !          2186:                while ((alerts) && (act_up != thread->top_act)) {
        !          2187:                        act_up = act_up->higher;
        !          2188:                        alerts &= act_up->alert_mask;
        !          2189:                        act_up->alerts |= alerts;
        !          2190:                }
        !          2191:                /*
        !          2192:                 * XXXX If we reach the top, and it is blocked in glue
        !          2193:                 * code, do something to kick it.  XXXX
        !          2194:                 */
        !          2195:        }
        !          2196:        act_unlock_thread(thr_act);
        !          2197: 
        !          2198:        return KERN_SUCCESS;
        !          2199: }
        !          2200: 
        !          2201: kern_return_t act_alert_mask(thread_act_t thr_act, unsigned alert_mask)
        !          2202: {
        !          2203:        panic("act_alert_mask NOT YET IMPLEMENTED\n");
        !          2204:        return KERN_SUCCESS;
        !          2205: }
        !          2206: 
        !          2207: typedef struct GetSetState {
        !          2208:        struct ReturnHandler rh;
        !          2209:        int flavor;
        !          2210:        void *state;
        !          2211:        int *pcount;
        !          2212:        int result;
        !          2213: } GetSetState;
        !          2214: 
        !          2215: /* Local Forward decls */
        !          2216: kern_return_t get_set_state(
        !          2217:                        thread_act_t thr_act, int flavor,
        !          2218:                        thread_state_t state, int *pcount,
        !          2219:                        void (*handler)(ReturnHandler *rh, thread_act_t thr_act));
        !          2220: void get_state_handler(ReturnHandler *rh, thread_act_t thr_act);
        !          2221: void set_state_handler(ReturnHandler *rh, thread_act_t thr_act);
        !          2222: 
        !          2223: /*
        !          2224:  * get_set_state(thr_act ...)
        !          2225:  *
        !          2226:  * General code to install g/set_state handler.
        !          2227:  * Called with thr_act's act_lock() and "appropriate"
        !          2228:  * thread-related locks held.  (See act_lock_thread().)
        !          2229:  */
        !          2230: kern_return_t
        !          2231: get_set_state(thread_act_t thr_act, int flavor, thread_state_t state, int *pcount,
        !          2232:                        void (*handler)(ReturnHandler *rh, thread_act_t thr_act))
        !          2233: {
        !          2234:        GetSetState gss;
        !          2235:        spl_t s;
        !          2236: 
        !          2237:        /* Initialize a small parameter structure */
        !          2238:        gss.rh.handler = handler;
        !          2239:        gss.flavor = flavor;
        !          2240:        gss.state = state;
        !          2241:        gss.pcount = pcount;
        !          2242:        gss.result = KERN_ABORTED;      /* iff wait below is interrupted */
        !          2243: 
        !          2244:        /* Add it to the thr_act's return handler list */
        !          2245:        gss.rh.next = thr_act->handlers;
        !          2246:        thr_act->handlers = &gss.rh;
        !          2247: 
        !          2248:        s = splsched();
        !          2249:        act_set_apc(thr_act);
        !          2250:        splx(s);
        !          2251: 
        !          2252: #if    MACH_ASSERT
        !          2253:        if (watchacts & WA_ACT_HDLR) {
        !          2254:            printf("act_%x: get_set_state(thr_act=%x flv=%x state=%x ptr@%x=%x)",
        !          2255:                    current_act(), thr_act, flavor, state,
        !          2256:                    pcount, (pcount ? *pcount : 0));
        !          2257:            printf((handler == get_state_handler ? "get_state_hdlr\n" :
        !          2258:                    (handler == set_state_handler ? "set_state_hdlr\n" :
        !          2259:                        "hndler=%x\n")), handler); 
        !          2260:        }
        !          2261: #endif /* MACH_ASSERT */
        !          2262: 
        !          2263:        assert(thr_act->thread);        /* Callers must ensure these */
        !          2264:        assert(thr_act != current_act());
        !          2265:        for (;;) {
        !          2266:                nudge(thr_act);
        !          2267:                /*
        !          2268:                 * Wait must be interruptible to avoid deadlock (e.g.) with
        !          2269:                 * task_suspend() when caller and target of get_set_state()
        !          2270:                 * are in same task.
        !          2271:                 */
        !          2272:                assert_wait((event_t)&gss, THREAD_ABORTSAFE);
        !          2273:                act_unlock_thread(thr_act);
        !          2274:                thread_block((void (*)(void))0);
        !          2275:                if (gss.result != KERN_ABORTED)
        !          2276:                        break;
        !          2277:                if (current_act()->handlers)
        !          2278:                        act_execute_returnhandlers();
        !          2279:                act_lock_thread(thr_act);
        !          2280:        }
        !          2281: 
        !          2282: #if    MACH_ASSERT
        !          2283:        if (watchacts & WA_ACT_HDLR)
        !          2284:            printf("act_%x: get_set_state returns %x\n",
        !          2285:                            current_act(), gss.result);
        !          2286: #endif /* MACH_ASSERT */
        !          2287: 
        !          2288:        return gss.result;
        !          2289: }
        !          2290: 
        !          2291: void
        !          2292: set_state_handler(ReturnHandler *rh, thread_act_t thr_act)
        !          2293: {
        !          2294:        GetSetState *gss = (GetSetState*)rh;
        !          2295: 
        !          2296: #if    MACH_ASSERT
        !          2297:        if (watchacts & WA_ACT_HDLR)
        !          2298:                printf("act_%x: set_state_handler(rh=%x,thr_act=%x)\n",
        !          2299:                        current_act(), rh, thr_act);
        !          2300: #endif /* MACH_ASSERT */
        !          2301: 
        !          2302:        gss->result = act_machine_set_state(thr_act, gss->flavor,
        !          2303:                                                gss->state, *gss->pcount);
        !          2304:        thread_wakeup((event_t)gss);
        !          2305: }
        !          2306: 
        !          2307: void
        !          2308: get_state_handler(ReturnHandler *rh, thread_act_t thr_act)
        !          2309: {
        !          2310:        GetSetState *gss = (GetSetState*)rh;
        !          2311: 
        !          2312: #if    MACH_ASSERT
        !          2313:        if (watchacts & WA_ACT_HDLR)
        !          2314:                printf("act_%x: get_state_handler(rh=%x,thr_act=%x)\n",
        !          2315:                        current_act(), rh, thr_act);
        !          2316: #endif /* MACH_ASSERT */
        !          2317: 
        !          2318:        gss->result = act_machine_get_state(thr_act, gss->flavor,
        !          2319:                        gss->state, 
        !          2320:                        (mach_msg_type_number_t *) gss->pcount);
        !          2321:        thread_wakeup((event_t)gss);
        !          2322: }
        !          2323: 
        !          2324: kern_return_t
        !          2325: act_get_state_locked(thread_act_t thr_act, int flavor, thread_state_t state,
        !          2326:                                        mach_msg_type_number_t *pcount)
        !          2327: {
        !          2328: #if    MACH_ASSERT
        !          2329:     if (watchacts & WA_ACT_HDLR)
        !          2330:        printf("act_%x: act_get_state_L(thr_act=%x,flav=%x,st=%x,pcnt@%x=%x)\n",
        !          2331:                current_act(), thr_act, flavor, state, pcount,
        !          2332:                (pcount? *pcount : 0));
        !          2333: #endif /* MACH_ASSERT */
        !          2334: 
        !          2335:     return(get_set_state(thr_act, flavor, state, (int*)pcount, get_state_handler));
        !          2336: }
        !          2337: 
        !          2338: kern_return_t
        !          2339: act_set_state_locked(thread_act_t thr_act, int flavor, thread_state_t state,
        !          2340:                                        mach_msg_type_number_t count)
        !          2341: {
        !          2342: #if    MACH_ASSERT
        !          2343:     if (watchacts & WA_ACT_HDLR)
        !          2344:        printf("act_%x: act_set_state_L(thr_act=%x,flav=%x,st=%x,pcnt@%x=%x)\n",
        !          2345:                current_act(), thr_act, flavor, state, count, count);
        !          2346: #endif /* MACH_ASSERT */
        !          2347: 
        !          2348:     return(get_set_state(thr_act, flavor, state, (int*)&count, set_state_handler));
        !          2349: }
        !          2350: 
        !          2351: kern_return_t
        !          2352: act_set_state(thread_act_t thr_act, int flavor, thread_state_t state,
        !          2353:                                        mach_msg_type_number_t count)
        !          2354: {
        !          2355:     if (thr_act == THR_ACT_NULL || thr_act == current_act())
        !          2356:            return(KERN_INVALID_ARGUMENT);
        !          2357: 
        !          2358:     if (act_lock_thread(thr_act) == THREAD_NULL) {
        !          2359:            act_unlock(thr_act);
        !          2360:            return(KERN_INVALID_ARGUMENT);
        !          2361:     }
        !          2362:     return(act_set_state_locked(thr_act, flavor, state, count));
        !          2363:     
        !          2364: }
        !          2365: 
        !          2366: kern_return_t
        !          2367: act_get_state(thread_act_t thr_act, int flavor, thread_state_t state,
        !          2368:                                        mach_msg_type_number_t *pcount)
        !          2369: {
        !          2370:     if (thr_act == THR_ACT_NULL || thr_act == current_act())
        !          2371:            return(KERN_INVALID_ARGUMENT);
        !          2372: 
        !          2373:     if (act_lock_thread(thr_act) == THREAD_NULL) {
        !          2374:            act_unlock(thr_act);
        !          2375:            return(KERN_INVALID_ARGUMENT);
        !          2376:     }
        !          2377:     return(act_get_state_locked(thr_act, flavor, state, pcount));
        !          2378: }
        !          2379: 
        !          2380: /*
        !          2381:  * These two should be called at splsched()
        !          2382:  * Set/clear indicator to run APC (layered on ASTs)
        !          2383:  */
        !          2384: void
        !          2385: act_set_apc(thread_act_t thr_act)
        !          2386: {
        !          2387:        thread_ast_set(thr_act, AST_APC);
        !          2388:        if (thr_act == current_act()) {
        !          2389:                mp_disable_preemption();
        !          2390:                ast_propagate(thr_act->ast);
        !          2391:                mp_enable_preemption();
        !          2392:        }
        !          2393: }
        !          2394: 
        !          2395: void
        !          2396: act_clr_apc(thread_act_t thr_act)
        !          2397: {
        !          2398:        thread_ast_clear(thr_act, AST_APC);
        !          2399: }
        !          2400: 
        !          2401: void
        !          2402: act_ulock_release_all(thread_act_t thr_act)
        !          2403: {
        !          2404:        ulock_t ulock;
        !          2405: 
        !          2406:        while (!queue_empty(&thr_act->held_ulocks)) {
        !          2407:                ulock = (ulock_t) queue_first(&thr_act->held_ulocks);
        !          2408:                (void) lock_make_unstable(ulock, thr_act);
        !          2409:                (void) lock_release_internal(ulock, thr_act);
        !          2410:        }
        !          2411: }
        !          2412: 
        !          2413: /*
        !          2414:  * Provide routines (for export to other components) of things that
        !          2415:  * are implemented as macros insternally.
        !          2416:  */
        !          2417: #undef current_act
        !          2418: thread_act_t
        !          2419: current_act(void)
        !          2420: {
        !          2421:        return(current_act_fast());
        !          2422: }

unix.superglobalmegacorp.com

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