Annotation of researchv10no/cmd/cfront/libC/task/task.c, revision 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.