Annotation of OSKit-Mach/kern/act.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1993,1994 The University of Utah and
        !             3:  * the Computer Systems Laboratory (CSL).  All rights reserved.
        !             4:  *
        !             5:  * Permission to use, copy, modify and distribute this software and its
        !             6:  * documentation is hereby granted, provided that both the copyright
        !             7:  * notice and this permission notice appear in all copies of the
        !             8:  * software, derivative works or modified versions, and any portions
        !             9:  * thereof, and that both notices appear in supporting documentation.
        !            10:  *
        !            11:  * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
        !            12:  * IS" CONDITION.  THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF
        !            13:  * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
        !            14:  *
        !            15:  * CSL requests users of this software to return to [email protected] any
        !            16:  * improvements that they make and grant CSL redistribution rights.
        !            17:  *
        !            18:  *     Author: Bryan Ford, University of Utah CSL
        !            19:  */
        !            20: /*
        !            21:  *     File:   act.c
        !            22:  *
        !            23:  *     Activation management routines
        !            24:  *
        !            25:  */
        !            26: 
        !            27: #ifdef MIGRATING_THREADS
        !            28: 
        !            29: #include <mach_ipc_compat.h> /* XXX */
        !            30: #include <mach/kern_return.h>
        !            31: #include <mach/alert.h>
        !            32: #include <kern/mach_param.h> /* XXX INCALL_... */
        !            33: #include <kern/zalloc.h>
        !            34: #include <kern/thread.h>
        !            35: #include <kern/task.h>
        !            36: #include <kern/act.h>
        !            37: #include <kern/current.h>
        !            38: #include "ipc_target.h"
        !            39: 
        !            40: static void special_handler(ReturnHandler *rh, struct Act *act);
        !            41: 
        !            42: #ifdef ACT_STATIC_KLUDGE
        !            43: #undef ACT_STATIC_KLUDGE
        !            44: #define ACT_STATIC_KLUDGE 300
        !            45: #endif
        !            46: 
        !            47: #ifndef ACT_STATIC_KLUDGE
        !            48: static zone_t act_zone;
        !            49: #else
        !            50: static Act *act_freelist;
        !            51: static Act free_acts[ACT_STATIC_KLUDGE];
        !            52: #endif
        !            53: 
        !            54: /* This is a rather special activation
        !            55:    which resides at the top and bottom of every thread.
        !            56:    When the last "real" activation on a thread is destroyed,
        !            57:    the null_act on the bottom gets invoked, destroying the thread.
        !            58:    At the top, the null_act acts as an "invalid" cached activation,
        !            59:    which will always fail the cached-activation test on RPC paths.
        !            60: 
        !            61:    As you might expect, most of its members have no particular value.
        !            62:    alerts is zero.  */
        !            63: Act null_act;
        !            64: 
        !            65: void
        !            66: global_act_init()
        !            67: {
        !            68: #ifndef ACT_STATIC_KLUDGE
        !            69:        act_zone = zinit(
        !            70:                        sizeof(struct Act),
        !            71:                        ACT_MAX * sizeof(struct Act), /* XXX */
        !            72:                        ACT_CHUNK * sizeof(struct Act),
        !            73:                        0, "activations");
        !            74: #else
        !            75:        int i;
        !            76: 
        !            77: printf("activations: [%x-%x]\n", &free_acts[0], &free_acts[ACT_STATIC_KLUDGE]);
        !            78:        act_freelist = &free_acts[0];
        !            79:        free_acts[0].ipt_next = 0;
        !            80:        for (i = 1; i < ACT_STATIC_KLUDGE; i++) {
        !            81:                free_acts[i].ipt_next = act_freelist;
        !            82:                act_freelist = &free_acts[i];
        !            83:        }
        !            84:        /* XXX simple_lock_init(&act_freelist->lock); */
        !            85: #endif
        !            86: 
        !            87: #if 0
        !            88:        simple_lock_init(&null_act.lock);
        !            89:        refcount_init(&null_act.ref_count, 1);
        !            90: #endif
        !            91: 
        !            92:        act_machine_init();
        !            93: }
        !            94: 
        !            95: /* Create a new activation in a specific task.
        !            96:    Locking: Task */
        !            97: kern_return_t act_create(task_t task, vm_offset_t user_stack,
        !            98:                         vm_offset_t user_rbuf, vm_size_t user_rbuf_size,
        !            99:                         struct Act **new_act)
        !           100: {
        !           101:        Act *act;
        !           102:        int rc;
        !           103: 
        !           104: #ifndef ACT_STATIC_KLUDGE
        !           105:        act = (Act*)zalloc(act_zone);
        !           106:        if (act == 0)
        !           107:                return(KERN_RESOURCE_SHORTAGE);
        !           108: #else
        !           109:        /* XXX ipt_lock(act_freelist); */
        !           110:        act = act_freelist;
        !           111:        if (act == 0) panic("out of activations");
        !           112:        act_freelist = act->ipt_next;
        !           113:        /* XXX ipt_unlock(act_freelist); */
        !           114:        act->ipt_next = 0;
        !           115: #endif
        !           116:        bzero(act, sizeof(*act)); /*XXX shouldn't be needed */
        !           117: 
        !           118: #ifdef DEBUG
        !           119:        act->lower = act->higher = 0;
        !           120: #endif
        !           121: 
        !           122:        /* Start with one reference for being active, another for the caller */
        !           123:        simple_lock_init(&act->lock);
        !           124:        refcount_init(&act->ref_count, 2);
        !           125: 
        !           126:        /* Latch onto the task.  */
        !           127:        act->task = task;
        !           128:        task_reference(task);
        !           129: 
        !           130:        /* Other simple setup */
        !           131:        act->ipt = 0;
        !           132:        act->thread = 0;
        !           133:        act->suspend_count = 0;
        !           134:        act->active = 1;
        !           135:        act->handlers = 0;
        !           136: 
        !           137:        /* The special_handler will always be last on the returnhandlers list.  */
        !           138:        act->special_handler.next = 0;
        !           139:        act->special_handler.handler = special_handler;
        !           140: 
        !           141:        ipc_act_init(task, act);
        !           142:        act_machine_create(task, act, user_stack, user_rbuf, user_rbuf_size);
        !           143: 
        !           144:        task_lock(task);
        !           145: 
        !           146:        /* Chain the act onto the task's list */
        !           147:        act->task_links.next = task->acts.next;
        !           148:        act->task_links.prev = &task->acts;
        !           149:        task->acts.next->prev = &act->task_links;
        !           150:        task->acts.next = &act->task_links;
        !           151:        task->act_count++;
        !           152: 
        !           153:        task_unlock(task);
        !           154: 
        !           155:        *new_act = act;
        !           156:        return KERN_SUCCESS;
        !           157: }
        !           158: 
        !           159: /* This is called when an act's ref_count drops to zero.
        !           160:    This can only happen when thread is zero (not in use),
        !           161:    ipt is zero (not attached to any ipt),
        !           162:    and active is false (terminated).  */
        !           163: static void act_free(Act *inc)
        !           164: {
        !           165:        act_machine_destroy(inc);
        !           166:        ipc_act_destroy(inc);
        !           167: 
        !           168:        /* Drop the task reference.  */
        !           169:        task_deallocate(inc->task);
        !           170: 
        !           171:        /* Put the act back on the act zone */
        !           172: #ifndef ACT_STATIC_KLUDGE
        !           173:        zfree(act_zone, (vm_offset_t)inc);
        !           174: #else
        !           175:        /* XXX ipt_lock(act_freelist); */
        !           176:        inc->ipt_next = act_freelist;
        !           177:        act_freelist = inc;
        !           178:        /* XXX ipt_unlock(act_freelist); */
        !           179: #endif
        !           180: }
        !           181: 
        !           182: void act_deallocate(Act *inc)
        !           183: {
        !           184:        refcount_drop(&inc->ref_count, act_free(inc));
        !           185: }
        !           186: 
        !           187: /* Attach an act to the top of a thread ("push the stack").
        !           188:    The thread must be either the current one or a brand-new one.
        !           189:    Assumes the act is active but not in use.
        !           190:    Assumes that if it is attached to an ipt (i.e. the ipt pointer is nonzero),
        !           191:    the act has already been taken off the ipt's list.
        !           192: 
        !           193:    Already locked: cur_thread, act */
        !           194: void act_attach(Act *act, thread_t thread, unsigned init_alert_mask)
        !           195: {
        !           196:        Act *lower;
        !           197: 
        !           198:        act->thread = thread;
        !           199: 
        !           200:        /* The thread holds a reference to the activation while using it.  */
        !           201:        refcount_take(&act->ref_count);
        !           202: 
        !           203:        /* XXX detach any cached activations from above the target */
        !           204: 
        !           205:        /* Chain the act onto the thread's act stack.  */
        !           206:        lower = thread->top_act;
        !           207:        act->lower = lower;
        !           208:        lower->higher = act;
        !           209:        thread->top_act = act;
        !           210: 
        !           211:        act->alert_mask = init_alert_mask;
        !           212:        act->alerts = lower->alerts & init_alert_mask;
        !           213: }
        !           214: 
        !           215: /* Remove the current act from the top of the current thread ("pop the stack").
        !           216:    Return it to the ipt it lives on, if any.
        !           217:    Locking: Thread > Act(not on ipt) > ipc_target */
        !           218: void act_detach(Act *cur_act)
        !           219: {
        !           220:        thread_t cur_thread = cur_act->thread;
        !           221: 
        !           222:        thread_lock(cur_thread);
        !           223:        act_lock(cur_act);
        !           224: 
        !           225:        /* Unlink the act from the thread's act stack */
        !           226:        cur_thread->top_act = cur_act->lower;
        !           227:        cur_act->thread = 0;
        !           228: #ifdef DEBUG
        !           229:        cur_act->lower = cur_act->higher = 0;
        !           230: #endif
        !           231: 
        !           232:        thread_unlock(cur_thread);
        !           233: 
        !           234:        /* Return it to the ipt's list */
        !           235:        if (cur_act->ipt)
        !           236:        {
        !           237:                ipt_lock(cur_act->ipt);
        !           238:                cur_act->ipt_next = cur_act->ipt->ipt_acts;
        !           239:                cur_act->ipt->ipt_acts = cur_act;
        !           240:                ipt_unlock(cur_act->ipt);
        !           241: #if 0
        !           242:        printf("  return to ipt %x\n", cur_act->ipt);
        !           243: #endif
        !           244:        }
        !           245: 
        !           246:        act_unlock(cur_act);
        !           247: 
        !           248:        /* Drop the act reference taken for being in use.  */
        !           249:        refcount_drop(&cur_act->ref_count, act_free(cur_act));
        !           250: }
        !           251: 
        !           252: 
        !           253: 
        !           254: /*** Activation control support routines ***/
        !           255: 
        !           256: /* This is called by system-dependent code
        !           257:    when it detects that act->handlers is non-null
        !           258:    while returning into user mode.
        !           259:    Activations linked onto an ipt always have null act->handlers,
        !           260:    so RPC entry paths need not check it.
        !           261: 
        !           262:    Locking: Act */
        !           263: void act_execute_returnhandlers()
        !           264: {
        !           265:        Act *act = current_act();
        !           266: 
        !           267: #if 0
        !           268:        printf("execute_returnhandlers\n");
        !           269: #endif
        !           270:        while (1) {
        !           271:                ReturnHandler *rh;
        !           272: 
        !           273:                /* Grab the next returnhandler */
        !           274:                act_lock(act);
        !           275:                rh = act->handlers;
        !           276:                if (!rh) {
        !           277:                        act_unlock(act);
        !           278:                        return;
        !           279:                }
        !           280:                act->handlers = rh->next;
        !           281:                act_unlock(act);
        !           282: 
        !           283:                /* Execute it */
        !           284:                (*rh->handler)(rh, act);
        !           285:        }
        !           286: }
        !           287: 
        !           288: /* Try to nudge an act into executing its returnhandler chain.
        !           289:    Ensures that the activation will execute its returnhandlers
        !           290:    before it next executes any of its user-level code.
        !           291:    Also ensures that it is safe to break the thread's activation chain
        !           292:    immediately above this activation,
        !           293:    by rolling out of any outstanding two-way-optimized RPC.
        !           294: 
        !           295:    The target activation is not necessarily active
        !           296:    or even in use by a thread.
        !           297:    If it isn't, this routine does nothing.
        !           298: 
        !           299:    Already locked: Act */
        !           300: static void act_nudge(struct Act *act)
        !           301: {
        !           302:        /* If it's suspended, wake it up.  */
        !           303:        thread_wakeup(&act->suspend_count);
        !           304: 
        !           305:        /* Do a machine-dependent low-level nudge.
        !           306:           If we're on a multiprocessor,
        !           307:           this may mean sending an interprocessor interrupt.
        !           308:           In any case, it means rolling out of two-way-optimized RPC paths.  */
        !           309:        act_machine_nudge(act);
        !           310: }
        !           311: 
        !           312: /* Install the special returnhandler that handles suspension and termination,
        !           313:    if it hasn't been installed already.
        !           314: 
        !           315:    Already locked: Act */
        !           316: static void install_special_handler(struct Act *act)
        !           317: {
        !           318:        ReturnHandler **rh;
        !           319: 
        !           320:        /* The work handler must always be the last ReturnHandler on the list,
        !           321:           because it can do tricky things like detach the act.  */
        !           322:        for (rh = &act->handlers; *rh; rh = &(*rh)->next);
        !           323:        if (rh != &act->special_handler.next) {
        !           324:                *rh = &act->special_handler;
        !           325:        }
        !           326: 
        !           327:        /* Nudge the target activation,
        !           328:           to ensure that it will see the returnhandler we're adding.  */
        !           329:        act_nudge(act);
        !           330: }
        !           331: 
        !           332: /* Locking: Act */
        !           333: static void special_handler(ReturnHandler *rh, struct Act *cur_act)
        !           334: {
        !           335:       retry:
        !           336: 
        !           337:        act_lock(cur_act);
        !           338: 
        !           339:        /* If someone has killed this invocation,
        !           340:           invoke the return path with a terminated exception.  */
        !           341:        if (!cur_act->active) {
        !           342:                act_unlock(cur_act);
        !           343:                act_machine_return(KERN_TERMINATED);
        !           344:                /* XXX should just set the activation's reentry_routine
        !           345:                   and then return from special_handler().
        !           346:                   The magic reentry_routine should just pop its own activation
        !           347:                   and chain to the reentry_routine of the _lower_ activation.
        !           348:                   If that lower activation is the null_act,
        !           349:                   the thread will then be terminated.  */
        !           350:        }
        !           351: 
        !           352:        /* If we're suspended, go to sleep and wait for someone to wake us up.  */
        !           353:        if (cur_act->suspend_count) {
        !           354:                act_unlock(cur_act);
        !           355:                /* XXX mp unsafe */
        !           356:                thread_wait((int)&cur_act->suspend_count, FALSE);
        !           357: 
        !           358:                act_lock(cur_act);
        !           359: 
        !           360:                /* If we're still (or again) suspended,
        !           361:                   go to sleep again after executing any new returnhandlers that may have appeared.  */
        !           362:                if (cur_act->suspend_count)
        !           363:                        install_special_handler(cur_act);
        !           364:        }
        !           365: 
        !           366:        act_unlock(cur_act);
        !           367: }
        !           368: 
        !           369: #if 0 /************************ OLD SEMI-OBSOLETE CODE *********************/
        !           370: static __dead void act_throughcall_return(Act *act)
        !           371: {
        !           372:        /* Done - destroy the act and return */
        !           373:        act_detach(act);
        !           374:        act_terminate(act);
        !           375:        act_deallocate(act);
        !           376: 
        !           377:        /* XXX */
        !           378:        thread_terminate_self();
        !           379: }
        !           380: 
        !           381: __dead void act_throughcall(task_t task, void (*infunc)())
        !           382: {
        !           383:        thread_t thread = current_thread();
        !           384:        Act *act;
        !           385:        ReturnHandler rh;
        !           386:        int rc;
        !           387: 
        !           388:        rc = act_create(task, 0, 0, 0, &act);
        !           389:        if (rc) return rc;
        !           390: 
        !           391:        act->return_routine = act_throughcall_return;
        !           392: 
        !           393:        thread_lock(thread);
        !           394:        act_lock(act);
        !           395: 
        !           396:        act_attach(thread, act, 0);
        !           397: 
        !           398:        rh.handler = infunc;
        !           399:        rh.next = act->handlers;
        !           400:        act->handlers = &rh;
        !           401: 
        !           402:        act_unlock(act);
        !           403:        thread_unlock(thread);
        !           404: 
        !           405:        /* Call through the act into the returnhandler list */
        !           406:        act_machine_throughcall(act);
        !           407: }
        !           408: 
        !           409: 
        !           410: /* Grab an act from the specified pool, to pass to act_upcall.
        !           411:    Returns with the act locked, since it's in an inconsistent state
        !           412:    (not on its ipt but not on a thread either).
        !           413:    Returns null if no acts are available on the ipt.
        !           414: 
        !           415:    Locking: ipc_target > Act(on ipt) */
        !           416: Act *act_grab(struct ipc_target *ipt)
        !           417: {
        !           418:        Act *act;
        !           419: 
        !           420:        ipt_lock(ipt);
        !           421: 
        !           422:       retry:
        !           423: 
        !           424:        /* Pull an act off the ipt's list.  */
        !           425:        act = ipt->acts;
        !           426:        if (!act)
        !           427:                goto none_avail;
        !           428:        ipt->acts = act->ipt_next;
        !           429: 
        !           430:        act_lock(act);
        !           431: 
        !           432:        /* If it's been terminated, drop it and get another one.  */
        !           433:        if (!act->active) {
        !           434: #if 0
        !           435:                printf("dropping terminated act %08x\n", act);
        !           436: #endif
        !           437:                /* XXX ipt_deallocate(ipt); */
        !           438:                act->ipt = 0;
        !           439:                act_unlock(act);
        !           440:                act_deallocate(act);
        !           441:                goto retry;
        !           442:        }
        !           443: 
        !           444: none_avail:
        !           445:        ipt_unlock(ipt);
        !           446: 
        !           447:        return act;
        !           448: }
        !           449: 
        !           450: /* Try to make an upcall with an act on the specified ipt.
        !           451:    If the ipt is empty, returns KERN_RESOURCE_SHORTAGE.  XXX???
        !           452: 
        !           453:    Locking: ipc_target > Act > Thread */
        !           454: kern_return_t  act_upcall(struct Act *act, unsigned init_alert_mask,
        !           455:                              vm_offset_t user_entrypoint, vm_offset_t user_data)
        !           456: {
        !           457:        thread_t cur_thread = current_thread();
        !           458:        int rc;
        !           459: 
        !           460:        /* XXX locking */
        !           461: 
        !           462:        act_attach(cur_thread, act, init_alert_mask);
        !           463: 
        !           464:        /* Make the upcall into the destination task */
        !           465:        rc = act_machine_upcall(act, user_entrypoint, user_data);
        !           466: 
        !           467:        /* Done - detach the act and return */
        !           468:        act_detach(act);
        !           469: 
        !           470:        return rc;
        !           471: }
        !           472: #endif /************************ END OF OLD SEMI-OBSOLETE CODE *********************/
        !           473: 
        !           474: 
        !           475: 
        !           476: 
        !           477: /*** Act service routines ***/
        !           478: 
        !           479: /* Lock this act and its current thread.
        !           480:    We can only find the thread from the act
        !           481:    and the thread must be locked before the act,
        !           482:    requiring a little icky juggling.
        !           483: 
        !           484:    If the thread is not currently on any thread,
        !           485:    returns with only the act locked.
        !           486: 
        !           487:    Note that this routine is not called on any performance-critical path.
        !           488:    It is only for explicit act operations
        !           489:    which don't happen often.
        !           490: 
        !           491:    Locking: Thread > Act */
        !           492: static thread_t act_lock_thread(Act *act)
        !           493: {
        !           494:        thread_t thread;
        !           495: 
        !           496:       retry:
        !           497: 
        !           498:        /* Find the thread */
        !           499:        act_lock(act);
        !           500:        thread = act->thread;
        !           501:        if (thread == 0)
        !           502:        {
        !           503:                act_unlock(act);
        !           504:                return 0;
        !           505:        }
        !           506:        thread_reference(thread);
        !           507:        act_unlock(act);
        !           508: 
        !           509:        /* Lock the thread and re-lock the act,
        !           510:           and make sure the thread didn't change.  */
        !           511:        thread_lock(thread);
        !           512:        act_lock(act);
        !           513:        if (act->thread != thread)
        !           514:        {
        !           515:                act_unlock(act);
        !           516:                thread_unlock(thread);
        !           517:                thread_deallocate(thread);
        !           518:                goto retry;
        !           519:        }
        !           520: 
        !           521:        thread_deallocate(thread);
        !           522: 
        !           523:        return thread;
        !           524: }
        !           525: 
        !           526: /* Already locked: act->task
        !           527:    Locking: Task > Act */
        !           528: kern_return_t act_terminate_task_locked(struct Act *act)
        !           529: {
        !           530:        act_lock(act);
        !           531: 
        !           532:        if (act->active)
        !           533:        {
        !           534:                /* Unlink the act from the task's act list,
        !           535:                   so it doesn't appear in calls to task_acts and such.
        !           536:                   The act still keeps its ref on the task, however,
        !           537:                   until it loses all its own references and is freed.  */
        !           538:                act->task_links.next->prev = act->task_links.prev;
        !           539:                act->task_links.prev->next = act->task_links.next;
        !           540:                act->task->act_count--;
        !           541: 
        !           542:                /* Remove it from any ipc_target.  XXX is this right?  */
        !           543:                act_set_target(act, 0);
        !           544: 
        !           545:                /* This will allow no more control operations on this act.  */
        !           546:                act->active = 0;
        !           547: 
        !           548:                /* When the special_handler gets executed,
        !           549:                   it will see the terminated condition and exit immediately.  */
        !           550:                install_special_handler(act);
        !           551: 
        !           552:                /* Drop the act reference taken for being active.
        !           553:                   (There is still at least one reference left: the one we were passed.)  */
        !           554:                act_deallocate(act);
        !           555:        }
        !           556: 
        !           557:        act_unlock(act);
        !           558: 
        !           559:        return KERN_SUCCESS;
        !           560: }
        !           561: 
        !           562: /* Locking: Task > Act */
        !           563: kern_return_t act_terminate(struct Act *act)
        !           564: {
        !           565:        task_t task = act->task;
        !           566:        kern_return_t rc;
        !           567: 
        !           568:        /* act->task never changes,
        !           569:           so we can read it before locking the act.  */
        !           570:        task_lock(act->task);
        !           571: 
        !           572:        rc = act_terminate_task_locked(act);
        !           573: 
        !           574:        task_unlock(act->task);
        !           575: 
        !           576:        return rc;
        !           577: }
        !           578: 
        !           579: /* If this Act is on a Thread and is not the topmost,
        !           580:    yank it and everything below it off of the thread's stack
        !           581:    and put it all on a new thread forked from the original one.
        !           582:    May fail due to resource shortage, but can always be retried.
        !           583: 
        !           584:    Locking: Thread > Act */
        !           585: kern_return_t act_yank(Act *act)
        !           586: {
        !           587:        thread_t thread = act_lock_thread(act);
        !           588: 
        !           589: #if 0
        !           590:        printf("act_yank inc %08x thread %08x\n", act, thread);
        !           591: #endif
        !           592:        if (thread)
        !           593:        {
        !           594:                if (thread->top_act != act)
        !           595:                {
        !           596:                        printf("detaching act %08x from thread %08x\n", act, thread);
        !           597: 
        !           598:                        /* Nudge the activation into a clean point for detachment.  */
        !           599:                        act_nudge(act);
        !           600: 
        !           601:                        /* Now detach the activation
        !           602:                           and give the orphan its own flow of control.  */
        !           603:                        /*XXX*/
        !           604:                }
        !           605: 
        !           606:                thread_unlock(thread);
        !           607:        }
        !           608:        act_unlock(act);
        !           609: 
        !           610:        /* Ask the thread to return as quickly as possible,
        !           611:           because its results are now useless.  */
        !           612:        act_abort(act);
        !           613: 
        !           614:        return KERN_SUCCESS;
        !           615: }
        !           616: 
        !           617: /* Assign an activation to a specific ipc_target.
        !           618:    Fails if the activation is already assigned to another pool.
        !           619:    If ipt == 0, we remove the from its ipt.
        !           620: 
        !           621:    Locking: Act(not on ipt) > ipc_target > Act(on ipt) */
        !           622: kern_return_t act_set_target(Act *act, struct ipc_target *ipt)
        !           623: {
        !           624:        act_lock(act);
        !           625: 
        !           626:        if (ipt == 0)
        !           627:        {
        !           628:                Act **lact;
        !           629: 
        !           630:                ipt = act->ipt;
        !           631:                if (ipt == 0)
        !           632:                        return;
        !           633: 
        !           634:                /* XXX This is a violation of the locking order.  */
        !           635:                ipt_lock(ipt);
        !           636:                for (lact = &ipt->ipt_acts; *lact; lact = &((*lact)->ipt_next))
        !           637:                        if (act == *lact)
        !           638:                        {
        !           639:                                *lact = act->ipt_next;
        !           640:                                break;
        !           641:                        }
        !           642:                ipt_unlock(ipt);
        !           643: 
        !           644:                act->ipt = 0;
        !           645:                /* XXX ipt_deallocate(ipt); */
        !           646:                act_deallocate(act);
        !           647:                return;
        !           648:        }
        !           649:        if (act->ipt != ipt)
        !           650:        {
        !           651:                if (act->ipt != 0)
        !           652:                {
        !           653:                        act_unlock(act);
        !           654:                        return KERN_FAILURE; /*XXX*/
        !           655:                }
        !           656:                act->ipt = ipt;
        !           657:                ipt->ipt_type |= IPT_TYPE_MIGRATE_RPC;
        !           658: 
        !           659:                /* They get references to each other.  */
        !           660:                act_reference(act);
        !           661:                ipt_reference(ipt);
        !           662: 
        !           663:                /* If it is available,
        !           664:                   add it to the ipt's available-activation list.  */
        !           665:                if ((act->thread == 0) && (act->suspend_count == 0))
        !           666:                {
        !           667:                        ipt_lock(ipt);
        !           668:                        act->ipt_next = ipt->ipt_acts;
        !           669:                        act->ipt->ipt_acts = act;
        !           670:                        ipt_unlock(ipt);
        !           671:                }
        !           672:        }
        !           673:        act_unlock(act);
        !           674: 
        !           675:        return KERN_SUCCESS;
        !           676: }
        !           677: 
        !           678: /* Register an alert from this activation.
        !           679:    Each set bit is propagated upward from (but not including) this activation,
        !           680:    until the top of the chain is reached or the bit is masked.
        !           681: 
        !           682:    Locking: Thread > Act */
        !           683: kern_return_t act_alert(struct Act *act, unsigned alerts)
        !           684: {
        !           685:        thread_t thread = act_lock_thread(act);
        !           686: 
        !           687: #if 0
        !           688:        printf("act_alert %08x: %08x\n", act, alerts);
        !           689: #endif
        !           690:        if (thread)
        !           691:        {
        !           692:                struct Act *act_up = act;
        !           693:                while ((alerts) && (act_up != thread->top_act))
        !           694:                {
        !           695:                        act_up = act_up->higher;
        !           696:                        alerts &= act_up->alert_mask;
        !           697:                        act_up->alerts |= alerts;
        !           698:                }
        !           699: 
        !           700:                /* XXX If we reach the top, and it is blocked in glue code, do something.  */
        !           701: 
        !           702:                thread_unlock(thread);
        !           703:        }
        !           704:        act_unlock(act);
        !           705: 
        !           706:        return KERN_SUCCESS;
        !           707: }
        !           708: 
        !           709: /* Locking: Thread > Act */
        !           710: kern_return_t act_abort(struct Act *act)
        !           711: {
        !           712:        return act_alert(act, ALERT_ABORT_STRONG);
        !           713: }
        !           714: 
        !           715: /* Locking: Thread > Act */
        !           716: kern_return_t act_abort_safely(struct Act *act)
        !           717: {
        !           718:        return act_alert(act, ALERT_ABORT_SAFE);
        !           719: }
        !           720: 
        !           721: /* Locking: Thread > Act */
        !           722: kern_return_t act_alert_mask(struct Act *act, unsigned alert_mask)
        !           723: {
        !           724:        panic("act_alert_mask\n");
        !           725:        return KERN_SUCCESS;
        !           726: }
        !           727: 
        !           728: /* Locking: Thread > Act */
        !           729: kern_return_t act_suspend(struct Act *act)
        !           730: {
        !           731:        thread_t thread = act_lock_thread(act);
        !           732:        kern_return_t rc = KERN_SUCCESS;
        !           733: 
        !           734: #if 0
        !           735:        printf("act_suspend %08x\n", act);
        !           736: #endif
        !           737:        if (act->active)
        !           738:        {
        !           739:                if (act->suspend_count++ == 0)
        !           740:                {
        !           741:                        /* XXX remove from ipt */
        !           742:                        install_special_handler(act);
        !           743:                        act_nudge(act);
        !           744:                }
        !           745:        }
        !           746:        else
        !           747:                rc = KERN_TERMINATED;
        !           748: 
        !           749:        if (thread)
        !           750:                thread_unlock(thread);
        !           751:        act_unlock(act);
        !           752: 
        !           753:        return rc;
        !           754: }
        !           755: 
        !           756: /* Locking: Act */
        !           757: kern_return_t act_resume(struct Act *act)
        !           758: {
        !           759: #if 0
        !           760:        printf("act_resume %08x from %d\n", act, act->suspend_count);
        !           761: #endif
        !           762: 
        !           763:        act_lock(act);
        !           764:        if (!act->active)
        !           765:        {
        !           766:                act_unlock(act);
        !           767:                return KERN_TERMINATED;
        !           768:        }
        !           769: 
        !           770:        if (act->suspend_count > 0) {
        !           771:                if (--act->suspend_count == 0) {
        !           772:                        thread_wakeup(&act->suspend_count);
        !           773:                        /* XXX return to ipt */
        !           774:                }
        !           775:        }
        !           776: 
        !           777:        act_unlock(act);
        !           778: 
        !           779:        return KERN_SUCCESS;
        !           780: }
        !           781: 
        !           782: typedef struct GetSetState {
        !           783:        struct ReturnHandler rh;
        !           784:        int flavor;
        !           785:        void *state;
        !           786:        int *pcount;
        !           787:        int result;
        !           788: } GetSetState;
        !           789: 
        !           790: /* Locking: Thread */
        !           791: kern_return_t get_set_state(struct Act *act, int flavor, void *state, int *pcount,
        !           792:                            void (*handler)(ReturnHandler *rh, struct Act *act))
        !           793: {
        !           794:        GetSetState gss;
        !           795: 
        !           796:        /* Initialize a small parameter structure */
        !           797:        gss.rh.handler = handler;
        !           798:        gss.flavor = flavor;
        !           799:        gss.state = state;
        !           800:        gss.pcount = pcount;
        !           801: 
        !           802:        /* Add it to the act's return handler list */
        !           803:        act_lock(act);
        !           804:        gss.rh.next = act->handlers;
        !           805:        act->handlers = &gss.rh;
        !           806: 
        !           807:        act_nudge(act);
        !           808: 
        !           809:        act_unlock(act);
        !           810:        /* XXX mp unsafe */
        !           811:        thread_wait((int)&gss, 0); /* XXX could be interruptible */
        !           812: 
        !           813:        return gss.result;
        !           814: }
        !           815: 
        !           816: static void get_state_handler(ReturnHandler *rh, struct Act *act)
        !           817: {
        !           818:        GetSetState *gss = (GetSetState*)rh;
        !           819: 
        !           820:        gss->result = act_machine_get_state(act, gss->flavor, gss->state, gss->pcount);
        !           821:        thread_wakeup((int)gss);
        !           822: }
        !           823: 
        !           824: /* Locking: Thread */
        !           825: kern_return_t act_get_state(struct Act *act, int flavor, natural_t *state, natural_t *pcount)
        !           826: {
        !           827:        return get_set_state(act, flavor, state, pcount, get_state_handler);
        !           828: }
        !           829: 
        !           830: static void set_state_handler(ReturnHandler *rh, struct Act *act)
        !           831: {
        !           832:        GetSetState *gss = (GetSetState*)rh;
        !           833: 
        !           834:        gss->result = act_machine_set_state(act, gss->flavor, gss->state, *gss->pcount);
        !           835:        thread_wakeup((int)gss);
        !           836: }
        !           837: 
        !           838: /* Locking: Thread */
        !           839: kern_return_t act_set_state(struct Act *act, int flavor, natural_t *state, natural_t count)
        !           840: {
        !           841:        return get_set_state(act, flavor, state, &count, set_state_handler);
        !           842: }
        !           843: 
        !           844: 
        !           845: 
        !           846: /*** backward compatibility hacks ***/
        !           847: 
        !           848: #include <mach/thread_info.h>
        !           849: #include <mach/thread_special_ports.h>
        !           850: #include <ipc/ipc_port.h>
        !           851: 
        !           852: kern_return_t act_thread_info(Act *act, int flavor,
        !           853:                                 thread_info_t thread_info_out, unsigned *thread_info_count)
        !           854: {
        !           855:        return thread_info(act->thread, flavor, thread_info_out, thread_info_count);
        !           856: }
        !           857: 
        !           858: kern_return_t
        !           859: act_thread_assign(Act *act, processor_set_t new_pset)
        !           860: {
        !           861:        return thread_assign(act->thread, new_pset);
        !           862: }
        !           863: 
        !           864: kern_return_t
        !           865: act_thread_assign_default(Act *act)
        !           866: {
        !           867:        return thread_assign_default(act->thread);
        !           868: }
        !           869: 
        !           870: kern_return_t
        !           871: act_thread_get_assignment(Act *act, processor_set_t *pset)
        !           872: {
        !           873:        return thread_get_assignment(act->thread, pset);
        !           874: }
        !           875: 
        !           876: kern_return_t
        !           877: act_thread_priority(Act *act, int priority, boolean_t set_max)
        !           878: {
        !           879:        return thread_priority(act->thread, priority, set_max);
        !           880: }
        !           881: 
        !           882: kern_return_t
        !           883: act_thread_max_priority(Act *act, processor_set_t *pset, int max_priority)
        !           884: {
        !           885:        return thread_max_priority(act->thread, pset, max_priority);
        !           886: }
        !           887: 
        !           888: kern_return_t
        !           889: act_thread_policy(Act *act, int policy, int data)
        !           890: {
        !           891:        return thread_policy(act->thread, policy, data);
        !           892: }
        !           893: 
        !           894: kern_return_t
        !           895: act_thread_wire(struct host *host, Act *act, boolean_t wired)
        !           896: {
        !           897:        return thread_wire(host, act->thread, wired);
        !           898: }
        !           899: 
        !           900: kern_return_t
        !           901: act_thread_depress_abort(Act *act)
        !           902: {
        !           903:        return thread_depress_abort(act->thread);
        !           904: }
        !           905: 
        !           906: /*
        !           907:  *     Routine:        act_get_special_port [kernel call]
        !           908:  *     Purpose:
        !           909:  *             Clones a send right for one of the thread's
        !           910:  *             special ports.
        !           911:  *     Conditions:
        !           912:  *             Nothing locked.
        !           913:  *     Returns:
        !           914:  *             KERN_SUCCESS            Extracted a send right.
        !           915:  *             KERN_INVALID_ARGUMENT   The thread is null.
        !           916:  *             KERN_FAILURE            The thread is dead.
        !           917:  *             KERN_INVALID_ARGUMENT   Invalid special port.
        !           918:  */
        !           919: 
        !           920: kern_return_t
        !           921: act_get_special_port(Act *act, int which, ipc_port_t *portp)
        !           922: {
        !           923:        ipc_port_t *whichp;
        !           924:        ipc_port_t port;
        !           925: 
        !           926: #if 0
        !           927:        printf("act_get_special_port\n");
        !           928: #endif
        !           929:        if (act == 0)
        !           930:                return KERN_INVALID_ARGUMENT;
        !           931: 
        !           932:        switch (which) {
        !           933: #if    MACH_IPC_COMPAT
        !           934:            case THREAD_REPLY_PORT:
        !           935:                whichp = &act->reply_port;
        !           936:                break;
        !           937: #endif /* MACH_IPC_COMPAT */
        !           938: 
        !           939:            case THREAD_KERNEL_PORT:
        !           940:                whichp = &act->self_port;
        !           941:                break;
        !           942: 
        !           943:            case THREAD_EXCEPTION_PORT:
        !           944:                whichp = &act->exception_port;
        !           945:                break;
        !           946: 
        !           947:            default:
        !           948:                return KERN_INVALID_ARGUMENT;
        !           949:        }
        !           950: 
        !           951:        thread_lock(act->thread);
        !           952: 
        !           953:        if (act->self_port == IP_NULL) {
        !           954:                thread_unlock(act->thread);
        !           955:                return KERN_FAILURE;
        !           956:        }
        !           957: 
        !           958:        port = ipc_port_copy_send(*whichp);
        !           959:        thread_unlock(act->thread);
        !           960: 
        !           961:        *portp = port;
        !           962:        return KERN_SUCCESS;
        !           963: }
        !           964: 
        !           965: /*
        !           966:  *     Routine:        act_set_special_port [kernel call]
        !           967:  *     Purpose:
        !           968:  *             Changes one of the thread's special ports,
        !           969:  *             setting it to the supplied send right.
        !           970:  *     Conditions:
        !           971:  *             Nothing locked.  If successful, consumes
        !           972:  *             the supplied send right.
        !           973:  *     Returns:
        !           974:  *             KERN_SUCCESS            Changed the special port.
        !           975:  *             KERN_INVALID_ARGUMENT   The thread is null.
        !           976:  *             KERN_FAILURE            The thread is dead.
        !           977:  *             KERN_INVALID_ARGUMENT   Invalid special port.
        !           978:  */
        !           979: 
        !           980: kern_return_t
        !           981: act_set_special_port(Act *act, int which, ipc_port_t port)
        !           982: {
        !           983:        ipc_port_t *whichp;
        !           984:        ipc_port_t old;
        !           985: 
        !           986: #if 0
        !           987:        printf("act_set_special_port\n");
        !           988: #endif
        !           989:        if (act == 0)
        !           990:                return KERN_INVALID_ARGUMENT;
        !           991: 
        !           992:        switch (which) {
        !           993: #if    MACH_IPC_COMPAT
        !           994:            case THREAD_REPLY_PORT:
        !           995:                whichp = &act->reply_port;
        !           996:                break;
        !           997: #endif /* MACH_IPC_COMPAT */
        !           998: 
        !           999:            case THREAD_KERNEL_PORT:
        !          1000:                whichp = &act->self_port;
        !          1001:                break;
        !          1002: 
        !          1003:            case THREAD_EXCEPTION_PORT:
        !          1004:                whichp = &act->exception_port;
        !          1005:                break;
        !          1006: 
        !          1007:            default:
        !          1008:                return KERN_INVALID_ARGUMENT;
        !          1009:        }
        !          1010: 
        !          1011:        thread_lock(act->thread);
        !          1012:        if (act->self_port == IP_NULL) {
        !          1013:                thread_unlock(act->thread);
        !          1014:                return KERN_FAILURE;
        !          1015:        }
        !          1016: 
        !          1017:        old = *whichp;
        !          1018:        *whichp = port;
        !          1019:        thread_unlock(act->thread);
        !          1020: 
        !          1021:        if (IP_VALID(old))
        !          1022:                ipc_port_release_send(old);
        !          1023:        return KERN_SUCCESS;
        !          1024: }
        !          1025: 
        !          1026: /*
        !          1027:  *     XXX lame, non-blocking ways to get/set state.
        !          1028:  *     Return thread's machine-dependent state.
        !          1029:  */
        !          1030: kern_return_t
        !          1031: act_get_state_immediate(act, flavor, old_state, old_state_count)
        !          1032:        register Act            *act;
        !          1033:        int                     flavor;
        !          1034:        void                    *old_state;     /* pointer to OUT array */
        !          1035:        unsigned int            *old_state_count;       /*IN/OUT*/
        !          1036: {
        !          1037:        kern_return_t           ret;
        !          1038: 
        !          1039:        act_lock(act);
        !          1040:        /* not the top activation, return current state */
        !          1041:        if (act->thread && act->thread->top_act != act) {
        !          1042:                ret = act_machine_get_state(act, flavor,
        !          1043:                                            old_state, old_state_count);
        !          1044:                act_unlock(act);
        !          1045:                return ret;
        !          1046:        }
        !          1047:        act_unlock(act);
        !          1048: 
        !          1049:        /* not sure this makes sense */
        !          1050:        return act_get_state(act, flavor, old_state, old_state_count);
        !          1051: }
        !          1052: 
        !          1053: /*
        !          1054:  *     Change thread's machine-dependent state.
        !          1055:  */
        !          1056: kern_return_t
        !          1057: act_set_state_immediate(act, flavor, new_state, new_state_count)
        !          1058:        register Act            *act;
        !          1059:        int                     flavor;
        !          1060:        void                    *new_state;
        !          1061:        unsigned int            new_state_count;
        !          1062: {
        !          1063:        kern_return_t           ret;
        !          1064: 
        !          1065:        act_lock(act);
        !          1066:        /* not the top activation, set it now */
        !          1067:        if (act->thread && act->thread->top_act != act) {
        !          1068:                ret = act_machine_set_state(act, flavor,
        !          1069:                                            new_state, new_state_count);
        !          1070:                act_unlock(act);
        !          1071:                return ret;
        !          1072:        }
        !          1073:        act_unlock(act);
        !          1074: 
        !          1075:        /* not sure this makes sense */
        !          1076:        return act_set_state(act, flavor, new_state, new_state_count);
        !          1077: }
        !          1078: 
        !          1079: void act_count()
        !          1080: {
        !          1081:        int i;
        !          1082:        Act *act;
        !          1083:        static int amin = ACT_STATIC_KLUDGE;
        !          1084: 
        !          1085:        i = 0;
        !          1086:        for (act = act_freelist; act; act = act->ipt_next)
        !          1087:                i++;
        !          1088:        if (i < amin)
        !          1089:                amin = i;
        !          1090:        printf("%d of %d activations in use, %d max\n",
        !          1091:               ACT_STATIC_KLUDGE-i, ACT_STATIC_KLUDGE, ACT_STATIC_KLUDGE-amin);
        !          1092: }
        !          1093: 
        !          1094: dump_act(act)
        !          1095:        Act *act;
        !          1096: {
        !          1097:        act_count();
        !          1098:        kact_count();
        !          1099:        while (act) {
        !          1100:                printf("%08.8x: thread=%x, task=%x, hi=%x, lo=%x, ref=%x\n",
        !          1101:                       act, act->thread, act->task,
        !          1102:                       act->higher, act->lower, act->ref_count);
        !          1103:                printf("\talerts=%x, mask=%x, susp=%x, active=%x\n",
        !          1104:                       act->alerts, act->alert_mask,
        !          1105:                       act->suspend_count, act->active);
        !          1106:                machine_dump_act(&act->mact);
        !          1107:                if (act == act->lower)
        !          1108:                        break;
        !          1109:                act = act->lower;
        !          1110:        }
        !          1111: }
        !          1112: 
        !          1113: #ifdef ACTWATCH
        !          1114: Act *
        !          1115: get_next_act(sp)
        !          1116:        int sp;
        !          1117: {
        !          1118:        static int i;
        !          1119:        Act *act;
        !          1120: 
        !          1121:        while (1) {
        !          1122:                if (i == ACT_STATIC_KLUDGE) {
        !          1123:                        i = 0;
        !          1124:                        return 0;
        !          1125:                }
        !          1126:                act = &free_acts[i];
        !          1127:                i++;
        !          1128:                if (act->mact.space == sp)
        !          1129:                        return act;
        !          1130:        }
        !          1131: }
        !          1132: #endif
        !          1133: 
        !          1134: #endif /* MIGRATING_THREADS */

unix.superglobalmegacorp.com

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