Annotation of Gnu-Mach/kern/act.c, revision 1.1.1.5

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