Annotation of OSKit-Mach/kern/act.c, revision 1.1.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.