|
|
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;
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.