|
|
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.