Annotation of researchv10no/cmd/cfront/libC/task/task.c, revision 1.1.1.1

1.1       root        1: /*ident        "%W%" */
                      2: /**************************************************************************
                      3:                        Copyright (c) 1984 AT&T
                      4:                          All Rights Reserved   
                      5: 
                      6:        THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T
                      7:        
                      8:        The copyright notice above does not evidence any        
                      9:        actual or intended publication of such source code.
                     10: 
                     11: *****************************************************************************/
                     12: 
                     13: #include <task.h>
                     14: #include "hw_stack.h"
                     15: #include <assert.h>
                     16: 
                     17: #define ABSV(x) ( (x) > 0 ? (x) : -(x) )
                     18: 
                     19: const int NEW_CHILD = 1;
                     20: 
                     21: int _hwm;
                     22: 
                     23: HW_REGS New_task_regs;   /* hardware regs for activating new child
                     24:                          * in task::task frame
                     25:                          */
                     26: 
                     27: // a team is a collection of tasks that share one stack
                     28: class team
                     29: {
                     30: friend task;
                     31:        int     no_of_tasks;
                     32:        task*   got_stack;
                     33:        int*    stack;
                     34:        int     size;   // of the stack
                     35:        team(task*, int =0);    // stacksize == zero ==> using the main stack
                     36:        ~team() { delete stack; }
                     37: };
                     38: 
                     39: team::team(task* t, int stacksize) {
                     40:        no_of_tasks = 1;
                     41:        got_stack = t;
                     42:        if (size = stacksize) {
                     43:                stack = new int[stacksize];
                     44:                while (stack == 0) object::task_error(E_STORE, (object*)0);
                     45:                if (_hwm) {
                     46:                        for (int x = 0; x < stacksize; x++)
                     47:                                stack[x] = UNTOUCHED;
                     48:                }
                     49:        }
                     50: }
                     51: 
                     52: 
                     53: static void
                     54: usemainstack()
                     55: /* fudge to allow simple stack overflow check */
                     56: {
                     57:        int* sp = TOP();
                     58: 
                     59:        if (_hwm) {
                     60:                /* WARNING:  This function used to declare an array of
                     61:                 * SIZE+100 and set each element to UNTOUCHED instead
                     62:                 * of using the following method.  But then when compilers
                     63:                 * inlined this function it caused each new task's stack
                     64:                 * to overflow on initialization, because the task::task
                     65:                 * stack frame was SIZE+100 larger.
                     66:                 */
                     67: 
                     68:                // start with next word after "sp"
                     69:                for (int i = 2; i < SIZE+100; i++) {
                     70:                        *(STACK_LAST_WORD_P(sp, i)) = UNTOUCHED;
                     71:                }
                     72:        } else {
                     73:                *(STACK_LAST_WORD_P(sp, 0)) = 0;
                     74:        }
                     75: }
                     76: 
                     77: void 
                     78: copy_stack(register* f, register c, register* t)
                     79: /*
                     80:        copy c words down from f to t
                     81:        do NOT attempt to copy "copy_stack"'s own stackframe
                     82: */
                     83: {
                     84:        COPY_STACK(f,c,t);
                     85: }
                     86: 
                     87: /* swap_stack copies contents of parent stack (starting at pa_fp)
                     88:  * to child stack.  Adjusts pointers in saved ta_fp frame of child stack 
                     89:  * (to point to places in child stack).
                     90:  * Returns distance from parent stack to child stack.
                     91:  */
                     92: int
                     93: task::swap_stack(int* ta_fp, int* pa_fp)
                     94: {
                     95:        int size = ACTIVE_STK_SZ(pa_fp, TOP());
                     96:        if (size > t_stacksize) {
                     97:                task_error(E_STACK, this);
                     98:        }
                     99:        copy_stack(pa_fp, size, t_basep);
                    100:        /* distance from old stack to new */
                    101:        register int distance = pa_fp - t_basep;
                    102:        /* now doctor the new frame */
                    103: #if defined(vax) || defined(PROC_3B)
                    104:        OLD_AP(ta_fp - distance) = int((int*)OLD_AP(ta_fp) - distance);
                    105: #endif
                    106:        OLD_FP(ta_fp - distance) = int((int*)OLD_FP(ta_fp) - distance);
                    107:        return distance;
                    108: }
                    109: inline
                    110: void
                    111: task::settrap()
                    112: {
                    113:        if (t_team->size) {     // Don't set trap for main task
                    114:                t_trap = *(STACK_LAST_WORD_P(
                    115:                                STACK_BASE(t_team->stack, t_stacksize),
                    116:                                t_team->size));
                    117:        }
                    118: }
                    119: 
                    120: inline
                    121: void
                    122: task::checktrap()
                    123: {
                    124:        if (t_team->size        // Don't test for main task
                    125:            && t_trap != *(STACK_LAST_WORD_P(
                    126:                                STACK_BASE(t_team->stack, t_stacksize),
                    127:                                t_team->size))) {
                    128:                task_error(E_STACK, this);
                    129:        }
                    130: 
                    131: }
                    132: 
                    133: extern "C" {
                    134:        /* swap and sswap are assembly language functions */
                    135: extern task* swap(task*, task*, int, int);
                    136: extern task* sswap(task*, task*, task*, int, int);
                    137: }
                    138: 
                    139: inline
                    140: void
                    141: task::restore(task* running, int is_new_child)
                    142: /*
                    143:  *     Call assembly function swap or sswap to do a task switch.
                    144:  *     Swap suspends "running" task by saving current hardware state (fp, etc)
                    145:  *     in running->t_framep, etc.,
                    146:  *     and makes "this" task run after suspension by returning from the frame
                    147:  *     denoted by "t_framep."
                    148:  *     
                    149:  *     swap does a normal return--must be the last thing called here.
                    150:  *     swap for a new child task will not return through restore,
                    151:  *     but will return from task::task().
                    152:  *
                    153:  *     sswap saves running's hw state, copies out the target stack,
                    154:  *     copies in to_run's stack from the save area before "swap"ing
                    155:  *     It is equivalent to two "copystack"s in the middle of "swap".
                    156:  *     sswap for a new child copies out the parent stack, but does not need
                    157:  *     to restore hw_state of child--it's already in place, and 
                    158:  *     WILL return through restore, unlike swap.
                    159:  */
                    160: {
                    161:        task* prevOnStack;
                    162:        // running might have been TERMINATED
                    163:        int is_terminated = 0;
                    164:        if ((running == 0) || (running->s_state == TERMINATED)) {
                    165:                is_terminated = 1;
                    166:        } else {
                    167:                running->checktrap();
                    168:        }
                    169: 
                    170:        if ((t_mode == SHARED) && this != (prevOnStack = t_team->got_stack)){
                    171:                t_team->got_stack = this;    // assuming sswap will get space.
                    172:                sswap(running, prevOnStack, this, is_new_child, is_terminated);
                    173:        }
                    174:        else  { // DEDICATED or (SHARED && this already on target stack)
                    175:                swap(running, this, is_new_child, is_terminated);
                    176:        }
                    177:        //sswap and swap for old task return here.
                    178:        // This code is not needed for a new child, because a terminated
                    179:        // parent cannot create a new child.
                    180:        if (team_to_delete) {
                    181:                delete team_to_delete;
                    182:                team_to_delete = 0;
                    183:        }
                    184:        // WARNING!  No new code here.
                    185: }
                    186: 
                    187: task::task(char* name, modetype mode, int stacksize)
                    188: /*
                    189:        executed in the task creating a new task - thistask.
                    190:        1:      put thistask at head of scheduler queue,
                    191:        2:      create new task
                    192:        3:      transfer execution to new task
                    193:        derived::derived can never return - its return link is destroyed
                    194: 
                    195:        if thistask==0 then we are executing on main()'s stack and
                    196:        should turn it into the "main" task
                    197: */
                    198: {
                    199:        register task* running;
                    200: 
                    201:        register int* ta_fp = (int*)FP();           // fp for task::task()
                    202:        register int* ta_ap = (int*)AP();           // ap for task::task()
                    203:        register int* de_fp = (int*)OLD_FP(ta_fp);  // fp for ctor of class 
                    204:                                                    // derived from class task
                    205:        register int* de_ap = (int*)OLD_AP(ta_fp);
                    206:        register int* pa_fp = (int*)OLD_FP(de_fp);  // parent fp
                    207:                                                    // (caller of derived ctor)
                    208:        t_name = name;
                    209:        t_mode = (mode) ? mode : DEFAULT_MODE;
                    210:        t_stacksize = (stacksize) ? stacksize : SIZE;
                    211:        t_alert = 0;
                    212:        s_state = RUNNING;
                    213:        t_next = txsk_chxin;
                    214:        txsk_chxin = this;
                    215:        th = this;      /* fudged return value -- "returned" from swap */
                    216: 
                    217:        switch ((int)thxstxsk) {
                    218:        case 0:
                    219:                /* initialize task system by creating "main" task */
                    220:                thxstxsk = (task*) 1;
                    221:                thxstxsk = new task("main");
                    222:                break;
                    223:        case 1:
                    224:                /*      create "main" task      */
                    225:                usemainstack();         /* ensure that store is allocated */
                    226:                //set base pointer assuming a static task (Interrupt_alerter)
                    227:                //at this point stack has 6 frames for:
                    228:                //main, _main, <static ctor>, Int::Int, task::task, task::task
                    229:                //NOTE:  This sets basep to be the fp saved in _main's stack
                    230:                //frame (fp for main).  Depending on layout, may not include
                    231:                //main's save area.  This shouldn't matter.
                    232:                t_basep = (int*)OLD_FP((int*)OLD_FP((int*)OLD_FP(pa_fp)));
                    233:                t_team = new team(this);        /* don't allocate stack */
                    234:                t_team->no_of_tasks = 2;        /* never deallocate */
                    235:                return;
                    236:        }
                    237:        // thxstxsk is parent task
                    238:        /* return pointer to "child" */
                    239:        thxstxsk->th = this;
                    240:        thxstxsk->insert(0,this);
                    241: 
                    242:        switch (t_mode) {
                    243:        case DEDICATED:
                    244:                t_team = new team(this,t_stacksize);
                    245:                t_basep = STACK_BASE(t_team->stack, t_stacksize);
                    246: 
                    247:                // initialize child's stack
                    248:                int distance = swap_stack(ta_fp, pa_fp);
                    249:                // save hardware state of this frame in "this" (child)
                    250:                t_framep = ta_fp - distance;
                    251:                t_ap = ta_ap - distance;
                    252:                settrap();
                    253: 
                    254:                // save all current and saved hw regs in New_task_regs,
                    255:                // so when child begins execution, it will have hw regs
                    256:                // as the derived constructor had them set.
                    257:                SAVE_CHILD_REGS(&New_task_regs);
                    258: 
                    259:                thxstxsk->fudge_return(ta_fp);
                    260:                running = thxstxsk;     // running = parent
                    261:                thxstxsk = this;
                    262:                restore(running, NEW_CHILD);    // no return for child; 
                    263:                                                // parent will return
                    264:                // Needed on some machines to reset sp on fudged stack
                    265:                FUDGE_SP(de_ap, de_fp);  // Can't access arguments on 3B now
                    266:                                         // (except arg1, implicit "this")
                    267:                return;         // On 68k, return through fudge_sp()
                    268:        case SHARED:
                    269:                thxstxsk->t_mode = SHARED; /* you cannot share on your own */
                    270:                t_basep = pa_fp;
                    271:                t_team = thxstxsk->t_team;
                    272:                t_team->no_of_tasks++;
                    273:                t_framep = ta_fp;
                    274:                t_ap = ta_ap;
                    275:                settrap();
                    276:                running = thxstxsk;     // running == parent
                    277:                thxstxsk = this;
                    278:                restore(running, NEW_CHILD);    // both parent & child will
                    279:                                                // return
                    280:                if (running == thxstxsk) {      // parent
                    281:                        running->fudge_return(ta_fp);
                    282:                        // Needed on some machines to reset sp on fudged stack
                    283:                        FUDGE_SP(de_ap, de_fp);  // Can't access arguments
                    284:                                                 // on 3B now (except arg1,
                    285:                                                 // implicit "this")
                    286:                        // On 68k, parent returns through fudge_sp()
                    287:                }
                    288:                return;
                    289:        default:
                    290:                task_error(E_TASKMODE, this);
                    291:        }
                    292: }
                    293: 
                    294: void
                    295: task::resume()
                    296: {
                    297:        task* running = thxstxsk;
                    298:        thxstxsk = this;
                    299:        restore(running);
                    300: }
                    301: 
                    302: void
                    303: task::cancel(int val)
                    304: /*
                    305:        TERMINATE and free stack space
                    306: */
                    307: {
                    308:        sched::cancel(val);
                    309:        if (_hwm) t_size = curr_hwm();
                    310:        if (t_team->no_of_tasks-- == 1) {
                    311:                if (this != thxstxsk) {
                    312:                        delete t_team;
                    313:                } else {        // don't delete current stack!
                    314:                        // delete will be called from task::restore
                    315:                        // immediately after task switch
                    316:                        assert(team_to_delete == 0);
                    317:                        team_to_delete = t_team;
                    318:                }
                    319:        }
                    320: }
                    321: 
                    322: task::~task()
                    323: /*
                    324:        free stack space and remove task from task chain
                    325: */
                    326: {
                    327:        if (s_state != TERMINATED) task_error(E_TASKDEL, this);
                    328:        if (this == txsk_chxin)
                    329:                txsk_chxin = t_next;
                    330:        else {
                    331:                register task* t;
                    332:                register task* tt;
                    333: 
                    334:                for (t=txsk_chxin; tt=t->t_next; t=tt)  
                    335:                        if (tt == this) {
                    336:                                t->t_next = t_next;
                    337:                                break;
                    338:                        }
                    339:        }
                    340: 
                    341:        if (this == thxstxsk) {
                    342:                delete (int*) thxstxsk; /* fudge: free(_that) */
                    343:                thxstxsk = 0;
                    344:                schedule();
                    345:        }
                    346: }
                    347: 
                    348: void
                    349: task::resultis(int val)
                    350: {
                    351:        cancel(val);
                    352:        if (this == thxstxsk) schedule();
                    353: }
                    354: 
                    355: void
                    356: task::sleep(object* t)
                    357: {
                    358:        if (t) t->remember(this);
                    359:        if (s_state == RUNNING) remove();
                    360:        if (this == thxstxsk) schedule();
                    361: }
                    362: 
                    363: void
                    364: task::delay(int d)
                    365: {
                    366:        insert(d,this);
                    367:        if (thxstxsk == this) schedule();
                    368: }
                    369: 
                    370: int
                    371: task::preempt()
                    372: {
                    373:        if (s_state == RUNNING) {
                    374:                remove();
                    375:                return s_time - get_clock();
                    376:        }
                    377:        else {
                    378:                task_error(E_TASKPRE, this);
                    379:                return 0;
                    380:        }
                    381: }
                    382: 
                    383: char*
                    384: state_string(statetype s)
                    385: {
                    386:        switch (s) {
                    387:        case IDLE:              return "IDLE";
                    388:        case TERMINATED:        return "TERMINATED";
                    389:        case RUNNING:           return "RUNNING";
                    390:        default:                return 0;
                    391:        }
                    392: }
                    393: 
                    394: char*
                    395: mode_string(modetype m)
                    396: {
                    397:        switch(m) {
                    398:        case SHARED:            return "SHARED";
                    399:        case DEDICATED:         return "DEDICATED";
                    400:        default:                return 0;
                    401:        }
                    402: }
                    403: 
                    404: void
                    405: task::print(int n, int baseClass)
                    406: /*
                    407:        "n" values:     CHAIN, VERBOSE, STACK
                    408: */
                    409: {
                    410:        if (!baseClass)
                    411:                printf("task\n");
                    412: 
                    413:        char* ss = state_string(s_state);
                    414:        char* ns = (t_name) ? t_name : "";
                    415:        
                    416:        printf("task %s ",ns);
                    417:        if (this == thxstxsk)
                    418:                printf("(is thistask, %s) ", ss);
                    419:        else if (ss)
                    420:                printf("(%s) ",ss);
                    421:        else
                    422:                printf("(state==%d CORRUPTED) ",s_state);
                    423:        printf("\tthis = %x:\n", this);
                    424: 
                    425:        if (n&VERBOSE) {
                    426:                char* ms = mode_string(t_mode);
                    427:                if (ms == 0) ms = "CORRUPTED";
                    428:                printf("\tmode=%s t_alert=%x t_next=%x",
                    429:                        ms, t_alert, t_next);
                    430:                printf((s_state==TERMINATED) ? " result=%d\n" : " s_time=%d\n", s_time);
                    431:        }
                    432: 
                    433:        if (n&STACK) {
                    434:                printf("\tstack: ");
                    435:                if (s_state == TERMINATED) {
                    436:                        printf("deleted.  ");
                    437:                        if (_hwm) {
                    438:                                printf("hwm size=%d, ", t_size);
                    439:                                printf("hwm address=%x",STACK_LAST_WORD_P(t_basep,t_size));
                    440:                        }
                    441:                        printf("\n");
                    442:                }
                    443:                else {
                    444:                        register int* b = t_basep;
                    445:                        printf("\tsizes:\t");
                    446:                        register int sz;
                    447:                        if (this==thxstxsk) { // figure out real current size
                    448:                                sz = ACTIVE_STK_SZ(b,TOP());
                    449:                        } else {        // approximate at last switch
                    450:                                sz = t_mode==DEDICATED ?
                    451:                                        ACTIVE_STK_SZ(b,t_framep) : t_size;
                    452:                        }
                    453:                        printf("max=%d, current=%d",t_stacksize, sz);
                    454:                        if (_hwm) printf(", hwm=%d",curr_hwm());
                    455:                        printf("\n\t\taddresses:\t");
                    456:                        printf("t_basep=%x, t_framep=%x\n",b,t_framep);
                    457:                        printf("\t\t\t\tmax=%x",
                    458:                                STACK_LAST_WORD_P(b,t_stacksize));
                    459:                        printf(", current=%x", STACK_LAST_WORD_P(b,sz));
                    460:                        if (_hwm) printf(", hwm=%x",
                    461:                                STACK_LAST_WORD_P(b, curr_hwm()));
                    462:                        printf("\n");
                    463:                }
                    464:        }
                    465: 
                    466:        if (n&CHAIN) {
                    467:                sched::print(n, 1);     // call sched::print here to keep
                    468:                                        // output for same object together
                    469:                // Start at beginning of task chain, and print all tasks
                    470:                task *tp = get_task_chain();
                    471:                if (tp == this) {
                    472:                        tp = tp->t_next;        // just printed, skip it
                    473:                } else {
                    474:                        printf("\nChain of all tasks:\n");
                    475:                }
                    476:                for (; tp; tp = tp->t_next) {
                    477:                        printf("Next task on chain of all tasks is:\n");
                    478:                        tp->print(n & ~CHAIN);
                    479:                }
                    480:        } else {
                    481:                sched::print(n, 1);
                    482:        }
                    483: }
                    484: 
                    485: int
                    486: task::curr_hwm()
                    487: {
                    488:        int* b = t_basep;
                    489:        int i;
                    490:        for (i=t_team->size; 0<i && *(STACK_LAST_WORD_P(b,i))==UNTOUCHED; i--) ;
                    491:        return i;
                    492: }
                    493: 
                    494: void
                    495: task::wait(object* ob)
                    496: {
                    497:        if (ob == (object*)this) task_error(E_WAIT, this);
                    498:        t_alert = ob;
                    499:        while (ob->pending())
                    500:                sleep(ob);
                    501: }
                    502: 
                    503: int
                    504: task::waitlist(object* a ...)
                    505: {
                    506:        return waitvec(&a);
                    507: }
                    508: 
                    509: int
                    510: task::waitvec(object** v)
                    511: /*
                    512:        first determine if it is necessary to sleep(),
                    513:        return hint: who caused return
                    514: */
                    515: {
                    516:        int i;
                    517:        int j;
                    518:        register object* ob;
                    519: 
                    520:        for(;;) {
                    521:                for (i = 0; ob = v[i]; i++) {
                    522:                        if (!ob->pending()) goto ex;
                    523:                        ob->remember(this);
                    524:                }
                    525:                if (i==1 && v[0]==(object*)this) task_error(E_WAIT, this);
                    526:                sleep();
                    527:        }
                    528: ex:
                    529:        t_alert = ob;
                    530:        for (j = 0; ob = v[j]; j++)
                    531:                ob->forget(this);
                    532:        return i;
                    533: } 
                    534: 
                    535: Interrupt_alerter      interrupt_alerter;

unix.superglobalmegacorp.com

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