|
|
1.1 ! root 1: #include "task.h" ! 2: ! 3: /* macros giving the addresses of the stack frame pointer ! 4: and the program counter of the caller of the current function ! 5: given the first local variable ! 6: The AP macro (used only by 3B) takes the first function ! 7: argument (after the implied this) which must not be a ! 8: register. ! 9: */ ! 10: ! 11: #ifdef pdp11 ! 12: /* of historical interest only */ ! 13: #define FP() (&_that+4) ! 14: #define OLD_FP(fp) (*fp) ! 15: #endif ! 16: ! 17: #ifdef vax ! 18: #define STACK_GROWS_DOWN 1 ! 19: #define FP(p) ((int*)(&p+1)) ! 20: #define AP(arg1) ((int*)0) /* unnecessary on vax */ ! 21: #define OLD_AP(fp) (*(fp+2)) ! 22: #define OLD_FP(fp) (*(fp+3)) ! 23: #define FIX_FRAME(x)\ ! 24: OLD_AP(t_framep) = int(de_ap-x);\ ! 25: OLD_FP(t_framep) = int(de_fp-x) ! 26: ! 27: #endif ! 28: ! 29: #ifdef mc68000 ! 30: /* careful -- stack frame not self-describing */ ! 31: #define STACK_GROWS_DOWN 1 ! 32: #define FP(p) ( (int*)(&p+1) ) ! 33: #define AP(arg1) ((int*)0) /* unnecessary on mc68000 */ ! 34: #define OLD_AP(fp) (int*)0 /* unnecessary on mc68000 */ ! 35: #define OLD_FP(fp) (*fp) ! 36: #define FIX_FRAME(x)\ ! 37: OLD_FP(t_framep) = int(de_fp - x) ! 38: #endif ! 39: ! 40: #if u3b | u3b5 | u3b2 | u3b15 ! 41: #define STACK_GROWS_UP 1 ! 42: #define FP(p) ( (int*)&p ) ! 43: #define AP(arg1) ((int*)&arg1-1) /* AP of current frame */ ! 44: #ifdef u3b ! 45: #define OLD_FP(fp) (*( (int*)fp - 11 ) ) ! 46: #define OLD_AP(fp) (*( (int*)fp - 12 ) ) ! 47: #else ! 48: #define OLD_FP(fp) (*( (int*)fp - 7 ) ) ! 49: #define OLD_AP(fp) (*( (int*)fp - 8 ) ) ! 50: #endif ! 51: ! 52: #define FIX_FRAME(x)\ ! 53: OLD_AP(t_framep) = int(de_ap - x);\ ! 54: OLD_FP(t_framep) = int(de_fp - x) ! 55: ! 56: #endif ! 57: ! 58: #ifdef STACK_GROWS_UP /* stack grows toward higher memory */ ! 59: #define COPY_STACK(f,c,t) while (c--) *t++ = *f++ ! 60: #define ACTIVE_STK_SZ(b,t) (t - b + 1) /* size of active stack */ ! 61: #define STACK_BASE(b,s) b ! 62: #define SAVED_AREA(b,s) b ! 63: #define STACK_TOP(b,s) (b + s + 1) ! 64: #define STACK_DIFF(s1,s2) ((int*)s2 - (int*)s1) ! 65: #define SETTRAP() t_trap = *(t_basep + t_team->size - 1) ! 66: #define CHECKTRAP()\ ! 67: if (t_team->size && t_trap != *(t_basep + t_team->size - 1))\ ! 68: task_error(E_STACK) ! 69: #else /* stack grows toward lower memory */ ! 70: #define COPY_STACK(f,c,t) while (c--) *t-- = *f-- ! 71: #define ACTIVE_STK_SZ(b,t) (b - t + 1) /* size of active stack */ ! 72: #define STACK_BASE(b,s) (b + s - 1) ! 73: #define SAVED_AREA(b,s) (b - s + 1) ! 74: #define STACK_TOP(b,s) (b - s - 1) ! 75: #define STACK_DIFF(s1,s2) ((int*)s1 - (int*)s2) ! 76: #define SETTRAP() t_trap = *(t_basep - t_team->size + 1) ! 77: #define CHECKTRAP()\ ! 78: if (t_team->size && t_trap != *(t_basep - t_team->size + 1))\ ! 79: task_error(E_STACK) ! 80: #endif ! 81: ! 82: int _hwm; ! 83: ! 84: static void copy_in(task* th, int* savearea, int sz, int* basep); ! 85: ! 86: // a team is a collection of tasks that share one stack ! 87: class team ! 88: { ! 89: friend task; ! 90: int no_of_tasks; ! 91: task* got_stack; ! 92: int* stack; ! 93: int size; // of the stack ! 94: team(task*, int =0); // stacksize == zero ==> using the main stack ! 95: ~team() { delete stack; } ! 96: }; ! 97: team::team(task* t, int stacksize) { ! 98: no_of_tasks = 1; ! 99: got_stack = t; ! 100: if (size = stacksize) { ! 101: stack = new int[stacksize]; ! 102: if (_hwm) for (int x=0; x<stacksize; x++) stack[x] = UNTOUCHED; ! 103: } ! 104: } ! 105: ! 106: ! 107: static void ! 108: usemainstack() ! 109: /* fudge to allow simple stack overflow check */ ! 110: { ! 111: register v[SIZE+100]; ! 112: ! 113: if (_hwm) ! 114: for (register i=0;i<SIZE+100;i++) v[i] = UNTOUCHED; ! 115: else ! 116: v[0] = 0; ! 117: } ! 118: ! 119: static void ! 120: copy_stack(register* f, register c, register* t) ! 121: /* ! 122: copy c words down from f to t ! 123: do NOT attempt to copy "copy_stack"'s own stackframe ! 124: */ ! 125: { ! 126: COPY_STACK(f,c,t); ! 127: } ! 128: ! 129: // copy the current task out when starting a new SHARED task ! 130: int // return offset to save area ! 131: task::copy_share() ! 132: { ! 133: int* p; ! 134: p = new int[t_size]; ! 135: t_savearea = STACK_BASE(p,t_size); ! 136: copy_stack(t_basep,t_size,t_savearea); ! 137: return t_savearea-t_basep; ! 138: } ! 139: ! 140: void ! 141: task::get_size() // save size of active stack in preparation for copy out ! 142: { ! 143: int x = ACTIVE_STK_SZ(t_basep,FP(x)); ! 144: t_size = x; ! 145: } ! 146: ! 147: int // return distance from original to new stack ! 148: task::swap_stack(int* p, int* pa) // copy parent's stack for child ! 149: { ! 150: int x = ACTIVE_STK_SZ(pa,FP(x)); // a little extra for this frame ! 151: copy_stack(pa,x,p); ! 152: return pa-p; ! 153: } ! 154: #include <stdio.h> ! 155: task::task(char* name, int mode, int stacksize) ! 156: /* ! 157: executed in the task creating a new task - thistask. ! 158: 1: put thistask at head of scheduler queue, ! 159: 2: create new task ! 160: 3: transfer execution to new task ! 161: derived::derived can never return - its return link is destroyed ! 162: ! 163: if thistask==0 then we are executing on main()'s stack and ! 164: should turn it into the "main" task ! 165: ! 166: for the mc68000 implementation, the function prologue of this function ! 167: must save all registers of interest to any function, and it must match the ! 168: prologue of sched::schedule(). The assembly language function swap() ! 169: must have an epilogue that matches the epilogue of this function exactly! ! 170: The current prologue with the -O switch is ! 171: ! 172: link a6,#-44 ! 173: moveml #15612,sp@ ! 174: ! 175: and without the -O switch ! 176: ! 177: link a6,#0 ! 178: addl #-LF195,sp ! 179: moveml #LS195,sp@ ! 180: LF195 = 44 ! 181: LS195 = 0x3cfc ! 182: ! 183: this allocates a stack frame of 11 longwords and saves registers ! 184: a5, a4, a3, a2, d7, d6, d5, d4, d3, and d2 in it. ! 185: */ ! 186: { ! 187: int* de_ap; ! 188: register int* ta_fp = (int*)FP(de_ap); // task::task() frame pointer ! 189: register int* de_fp = (int*)OLD_FP(ta_fp); // My_task::My_task() frame pointer ! 190: de_ap = (int*)OLD_AP(ta_fp); ! 191: register int* pa_fp = (int*)OLD_FP(de_fp); // parent task frame pointer ! 192: // we have to trick the compiler into thinking we really use all these registers ! 193: register int x, y, z, u, v, w; ! 194: w = 0; v = w; u = v; z = u; y = z; x = y; ! 195: //fprintf(stderr,"task\n"); ! 196: t_name = name; ! 197: t_mode = mode ? mode : DEDICATED; ! 198: t_alert = 0; ! 199: s_state = RUNNING; ! 200: t_next = txsk_chxin; ! 201: txsk_chxin = this; ! 202: th = this; /* fudged return value -- "returned" from swap */ ! 203: ! 204: //fprintf(stderr,"this %d name %s mode %d size %d\n",this,name,mode,stacksize); ! 205: switch ((int)thxstxsk) { ! 206: case 0: ! 207: /* initialize task system by creating "main" task */ ! 208: thxstxsk = (task*) 1; ! 209: thxstxsk = new task("main"); ! 210: break; ! 211: case 1: ! 212: /* create "main" task */ ! 213: usemainstack(); /* ensure that store is allocated */ ! 214: // set base pointer assuming a static task ! 215: t_basep = (int*)OLD_FP((int*)OLD_FP((int*)OLD_FP(pa_fp))); ! 216: current_stack = t_team = new team(this); /* don't allocate stack */ ! 217: t_team->no_of_tasks = 2; /* never deallocate */ ! 218: return; ! 219: } ! 220: thxstxsk->th = this; /* return pointer to "child" */ ! 221: thxstxsk->t_framep = de_fp; // prepare to return from My_task::My_task frame ! 222: thxstxsk->t_ap = de_ap; // only matters to 3B ! 223: thxstxsk->insert(0,this); ! 224: ! 225: switch (t_mode) { ! 226: case DEDICATED: ! 227: t_team = new team(this, (stacksize ? stacksize : SIZE)); ! 228: t_basep = STACK_BASE(t_team->stack, t_team->size); ! 229: t_framep = ta_fp - (x = swap_stack(t_basep, pa_fp)); ! 230: /* now doctor the new frame */ ! 231: t_ap = AP(name) - x; // only matters to 3B ! 232: FIX_FRAME(x); ! 233: if (thxstxsk->t_mode == SHARED) ! 234: thxstxsk->get_size(); ! 235: thxstxsk->fudge_return(ta_fp, 0, this); ! 236: /* NO_RETURN */ ! 237: case SHARED: ! 238: thxstxsk->t_mode = SHARED; /* you cannot share on your own */ ! 239: t_basep = pa_fp; ! 240: t_team = thxstxsk->t_team; ! 241: t_team->no_of_tasks++; ! 242: t_framep = ta_fp; ! 243: t_ap = AP(name); // only matters for 3B ! 244: SETTRAP(); ! 245: thxstxsk->get_size(); ! 246: x = thxstxsk->copy_share(); // copy out ! 247: thxstxsk->fudge_return(ta_fp, x); ! 248: t_team->got_stack = thxstxsk = this; ! 249: return; ! 250: default: ! 251: task_error(E_TASKMODE); ! 252: } ! 253: } ! 254: ! 255: void ! 256: task::save() ! 257: /* ! 258: save task's state so that ``restore'' can resume it later. ! 259: Works by saving the frame pointer to the scheduler's frame. ! 260: */ ! 261: { ! 262: int* x; ! 263: register* old_fp = (int*)OLD_FP((int*)FP(x)); // caller's frame pointer (task::resume()) ! 264: t_framep = (int*)OLD_FP(old_fp); // sched::schedule() frame pointer ! 265: t_ap = (int*)OLD_AP(old_fp); // only matters for 3B ! 266: ! 267: CHECKTRAP(); ! 268: ! 269: if (t_mode == SHARED) ! 270: t_size = ACTIVE_STK_SZ(t_basep,old_fp); // a little extra room ! 271: // don't copy out until we have to ! 272: } ! 273: ! 274: void ! 275: task::resume() ! 276: { ! 277: if (thxstxsk && thxstxsk->s_state != TERMINATED) ! 278: thxstxsk->save(); ! 279: restore(); ! 280: } ! 281: ! 282: extern "C" { ! 283: swap(task*); ! 284: } ! 285: ! 286: void ! 287: task::restore() ! 288: /* ! 289: make "this" task run after suspension by returning from the frame ! 290: denoted by "t_framep" ! 291: ! 292: the key function "swap" is written in assembly code, ! 293: it returns from the function which "save"d the task ! 294: - typically the scheduler ! 295: */ ! 296: { ! 297: register sz; ! 298: register int* p; ! 299: register task* prevOnStack; ! 300: ! 301: SETTRAP(); ! 302: ! 303: thxstxsk = this; ! 304: if (t_mode == SHARED && this != (prevOnStack = t_team->got_stack)) { ! 305: p = new int[sz = prevOnStack->t_size]; ! 306: prevOnStack->t_savearea = p = STACK_BASE(p,sz); ! 307: copy_stack(prevOnStack->t_basep, sz, p); // copy out ! 308: sz = t_size; ! 309: t_team->got_stack = this; ! 310: if (current_stack == t_team) // do we have to be careful? ! 311: copy_in(this, t_savearea, sz, t_basep); // no return ! 312: copy_stack(t_savearea, sz, t_basep); // copy in carelessly ! 313: delete SAVED_AREA(t_savearea,sz); ! 314: } ! 315: current_stack = t_team; ! 316: swap(this); ! 317: } ! 318: ! 319: int* dummy_write_but_dont_read_pointer; // defeat simple optimization ! 320: ! 321: static void // watch out for tail recursion elimination ! 322: hack_stack32(task* th, int* savearea, int sz, int* basep) ! 323: { ! 324: int dummy[32]; ! 325: dummy_write_but_dont_read_pointer = dummy; ! 326: copy_in(th, savearea, sz, basep); ! 327: } ! 328: ! 329: static void // watch out for tail recursion elimination ! 330: hack_stack64(task* th, int* savearea, int sz, int* basep) ! 331: { ! 332: int dummy[64]; ! 333: dummy_write_but_dont_read_pointer = dummy; ! 334: copy_in(th, savearea, sz, basep); ! 335: } ! 336: ! 337: static void // make sure we don't copy on top of our own stack frame ! 338: copy_in(task* th, int* savearea, int sz, int* basep) ! 339: { ! 340: int i; ! 341: if ((i = STACK_DIFF((int*)OLD_FP(FP(i)), STACK_TOP(basep,sz))) ! 342: <= 0) { ! 343: copy_stack(savearea, sz, basep); // copy in ! 344: delete SAVED_AREA(savearea,sz); ! 345: swap(th); ! 346: } else if (i < 32) ! 347: hack_stack32(th, savearea, sz, basep); ! 348: else ! 349: hack_stack64(th, savearea, sz, basep); ! 350: } ! 351: ! 352: void ! 353: task::cancel(int val) ! 354: /* ! 355: TERMINATE and free stack space ! 356: */ ! 357: { ! 358: sched::cancel(val); ! 359: if (_hwm) t_size = curr_hwm(); ! 360: if (t_team->no_of_tasks-- == 1) delete t_team; ! 361: } ! 362: ! 363: task::~task() ! 364: /* ! 365: free stack space and remove task from task chain ! 366: */ ! 367: { ! 368: if (s_state != TERMINATED) task_error(E_TASKDEL); ! 369: if (this == txsk_chxin) ! 370: txsk_chxin = t_next; ! 371: else { ! 372: register task* t; ! 373: register task* tt; ! 374: ! 375: for (t=txsk_chxin; tt=t->t_next; t=tt) ! 376: if (tt == this) { ! 377: t->t_next = t_next; ! 378: break; ! 379: } ! 380: } ! 381: ! 382: if (this == thxstxsk) { ! 383: delete (int*) thxstxsk; /* fudge: free(_that) */ ! 384: thxstxsk = 0; ! 385: schedule(); ! 386: } ! 387: } ! 388: ! 389: void ! 390: task::resultis(int val) ! 391: { ! 392: cancel(val); ! 393: if (this == thxstxsk) schedule(); ! 394: } ! 395: ! 396: void ! 397: task::sleep(object* t) ! 398: { ! 399: if (t) t->remember(this); ! 400: if (s_state == RUNNING) remove(); ! 401: if (this == thxstxsk) schedule(); ! 402: } ! 403: ! 404: void ! 405: task::delay(int d) ! 406: { ! 407: insert(d,this); ! 408: if (thxstxsk == this) schedule(); ! 409: } ! 410: ! 411: int ! 412: task::preempt() ! 413: { ! 414: if (s_state == RUNNING) { ! 415: remove(); ! 416: return s_time-clock; ! 417: } ! 418: else { ! 419: task_error(E_TASKPRE); ! 420: return 0; ! 421: } ! 422: } ! 423: ! 424: char* ! 425: state_string(int s) ! 426: { ! 427: switch (s) { ! 428: case IDLE: return "IDLE"; ! 429: case TERMINATED: return "TERMINATED"; ! 430: case RUNNING: return "RUNNING"; ! 431: default: return 0; ! 432: } ! 433: } ! 434: ! 435: char* ! 436: mode_string(int m) ! 437: { ! 438: switch(m) { ! 439: case SHARED: return "SHARED"; ! 440: case DEDICATED: return "DEDICATED"; ! 441: default: return 0; ! 442: } ! 443: } ! 444: ! 445: void ! 446: task::print(int n, int baseClass) ! 447: /* ! 448: ``n'' values: CHAIN,VERBOSE,STACK ! 449: */ ! 450: { ! 451: if (!baseClass) ! 452: printf("task "); ! 453: ! 454: char* ss = state_string(s_state); ! 455: char* ns = (t_name) ? t_name : ""; ! 456: ! 457: printf("task %s ",ns); ! 458: if (this == thxstxsk) ! 459: printf("(is thistask):\n"); ! 460: else if (ss) ! 461: printf("(%s):\n",ss); ! 462: else ! 463: printf("(state==%d CORRUPTED):\n",s_state); ! 464: ! 465: if (n&VERBOSE) { ! 466: char* ms = mode_string(t_mode); ! 467: if (ms == 0) ms = "CORRUPTED"; ! 468: printf("\tmode=%s alert=%d next=%d", ! 469: ms, t_alert, t_next); ! 470: printf((s_state==TERMINATED) ? " result=%d\n" : " s_time=%d\n", s_time); ! 471: } ! 472: ! 473: if (n&STACK) { ! 474: printf("\tstack: "); ! 475: if (s_state == TERMINATED) { ! 476: if (_hwm) printf("hwm=%d",t_size); ! 477: printf(" deleted\n"); ! 478: } ! 479: else { ! 480: int* b = t_basep; ! 481: int x = this==thxstxsk || t_mode==DEDICATED ? ! 482: b - t_framep : t_size; ! 483: printf("max=%d current=%d",t_team->size,x); ! 484: if (_hwm) printf(" hwm=%d",curr_hwm()); ! 485: printf(" t_base=%d, t_frame=%d, t_size=%d\n",b,t_framep,t_size); ! 486: } ! 487: } ! 488: ! 489: if (n&CHAIN) { ! 490: if (t_next) t_next->print(n); ! 491: } ! 492: ! 493: sched::print(n, 1); ! 494: } ! 495: ! 496: int ! 497: task::curr_hwm() ! 498: { ! 499: int* b = t_basep; ! 500: int i; ! 501: for (i=t_team->size-1; 0<=i && *(b-i)==UNTOUCHED; i--) ; ! 502: return i; ! 503: } ! 504: ! 505: void ! 506: task::wait(object* ob) ! 507: { ! 508: if (ob == (object*)this) task_error(E_WAIT); ! 509: t_alert = ob; ! 510: while (ob->pending()) ! 511: sleep(ob); ! 512: } ! 513: ! 514: int ! 515: task::waitlist(object* a ...) ! 516: { ! 517: return waitvec(&a); ! 518: } ! 519: ! 520: int ! 521: task::waitvec(object** v) ! 522: /* ! 523: first determine if it is necessary to sleep(), ! 524: return hint: who caused return ! 525: */ ! 526: { ! 527: int i; ! 528: int j; ! 529: register object* ob; ! 530: ! 531: for(;;) { ! 532: for (i = 0; ob = v[i]; i++) { ! 533: if (!ob->pending()) goto ex; ! 534: ob->remember(this); ! 535: } ! 536: if (i==1 && v[0]==(object*)this) task_error(E_WAIT); ! 537: sleep(); ! 538: } ! 539: ex: ! 540: t_alert = ob; ! 541: for (j = 0; ob = v[j]; j++) ! 542: ob->forget(this); ! 543: return i; ! 544: } ! 545: ! 546: void ! 547: task::setwho(object* t) ! 548: { ! 549: t_alert = t; ! 550: } ! 551: ! 552: int ! 553: task::o_type() ! 554: { ! 555: return TASK; ! 556: } ! 557: ! 558: Interrupt_alerter interrupt_alerter; ! 559:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.