|
|
1.1 root 1:
2: #include "task.h"
3:
4: /* macros giving the addresses of the stack frame pointer
5: and the program counter of the caller of the current function
6: given the first local variable
7:
8: TOP points to the top of the current stack frame
9: given the last local variable
10: */
11:
12: #ifdef pdp11
13:
14: #define FP() (&_that+4)
15: #define OLD_FP(fp) (*fp)
16: #define TOP(var9) (&var9)
17:
18: #endif
19: #ifdef vax
20:
21: #define FP(p) ((int*)(&p+1))
22: #define OLD_AP(fp) (*(fp+2))
23: #define OLD_FP(fp) (*(fp+3))
24: #define TOP(p) top(&p)
25: extern int * top(...);
26:
27: #endif
28:
29: #define SETTRAP() t_trap = *(t_basep-t_stacksize+1)
30: #define CHECKTRAP() if (t_trap != *(t_basep-t_stacksize+1)) task_error(E_STACK,0)
31:
32:
33: int _hwm;
34:
35: class team
36: {
37: friend task;
38: int no_of_tasks;
39: task* got_stack;
40: int* stack;
41: team(task*, int = 0);
42: ~team() { delete stack; }
43: };
44: team.team(task* t, int stacksize) {
45: no_of_tasks = 1;
46: got_stack = t;
47: if (stacksize) {
48: stack = new int[stacksize];
49: while (stack == 0) task_error(E_STORE,0);
50: }
51: }
52:
53:
54: void usemainstack()
55: /* fudge to allow simple stack overflow check */
56: {
57: register v[SIZE+100];
58:
59: if (_hwm)
60: for (register i=0;i<SIZE+100;i++) v[i] = UNTOUCHED;
61: else
62: v[0] = 0;
63: }
64:
65: void copy_stack(register* f, register c, register* t)
66: /*
67: copy c words down from f to t
68: do NOT attempt to copy "copy_stack"'s own stackframe
69: */
70: {
71: while (c--) { *t-- = *f--;}
72: }
73:
74: void task.swap_stack(int* p, int* ta, int* de, int* pa, int* ap)
75: {
76: int x = pa-TOP(x)+1; /* size of active stack */
77: copy_stack(pa,x,p);
78: x = pa-p; /* distance from old stack to new */
79: t_framep = ta-x; /* fp on new frame */
80: /* now doctor the new frame */
81: #ifdef vax
82: OLD_AP(t_framep) = int(ap-x);
83: #endif
84: OLD_FP(t_framep) = int(de-x);
85: restore();
86: }
87: #include <stdio.h>
88: task::task(char* name, int mode, int stacksize) : (TASK)
89: /*
90: executed in the task creating a new task - thistask.
91: 1: put thistask at head of scheduler queue,
92: 2: create new task
93: 3: transfer execution to new task
94: derived::derived can never return - its return link is destroyed
95:
96: if thistask==0 then we are executing on main()'s stack and
97: should turn it into the "main" task
98: */
99: {
100: int* p;
101: int* ta_fp = (int*)FP(p);
102: int* de_fp = (int*)OLD_FP(ta_fp);
103: #ifdef vax
104: int* de_ap = (int*)OLD_AP(ta_fp);
105: #endif
106: int* pa_fp = (int*)OLD_FP(de_fp);
107: int x;
108: //fprintf(stderr,"task\n");
109: t_name = name;
110: t_mode = (mode) ? mode : DEDICATED;
111: t_stacksize = (stacksize) ? stacksize : SIZE;
112: t_size = 0; /* avoid stack copy at initial restore */
113: t_alert = 0;
114: s_state = RUNNING;
115: t_next = task_chain;
116: task_chain = this;
117: th = this; /* fudged return value -- "returned" from swap */
118:
119: //fprintf(stderr,"this %d name %s mode %d size %d\n",this,name,mode,stacksize);
120: switch ((int)thistask) {
121: case 0:
122: /* initialize task system by creating "main" task */
123: thistask = (task*) 1;
124: thistask = new task("main");
125: break;
126: case 1:
127: /* create "main" task */
128: usemainstack(); /* ensure that store is allocated */
129: t_basep = (int*)OLD_FP(pa_fp); /* fudge, what if main
130: is already deeply nested
131: */
132: t_team = new team(this); /* don't allocate stack */
133: t_team->no_of_tasks = 2; /* never deallocate */
134: return;
135: }
136: thistask->th = this; /* return pointer to "child" */
137: thistask->t_framep = de_fp;
138: thistask->insert(0,this);
139:
140: switch (t_mode) {
141: case DEDICATED:
142: t_team = new team(this,t_stacksize);
143: t_basep = t_team->stack + t_stacksize - 1;
144: if (_hwm) for (x=0; x<t_stacksize; x++) p[x] = UNTOUCHED;
145: thistask = this;
146: swap_stack(t_basep,ta_fp,de_fp,pa_fp,de_ap);
147: case SHARED:
148: thistask->t_mode = SHARED; /* you cannot share on your own */
149: t_basep = pa_fp;
150: t_team = thistask->t_team;
151: t_team->no_of_tasks++;
152: t_framep = ta_fp;
153: if (mode==0 && stacksize==0)
154: t_stacksize = thistask->t_stacksize - (thistask->t_basep - t_basep);
155: thistask = this;
156: return;
157: default:
158: task_error(E_TASKMODE,this);
159: }
160: }
161:
162: void task::save()
163: /*
164: save task's state so that ``restore'' can resume it later
165: by returning from the function which called "save"
166: - typically the scheduler
167: */
168: {
169: int* x;
170: register* p = (int*)FP(x);
171:
172: t_framep = (int*)OLD_FP(p);
173:
174: CHECKTRAP();
175:
176: if (t_mode == SHARED) {
177: register int sz;
178: t_size = sz = t_basep - p + 1;
179: p = new int[sz];
180: while (p == 0) task_error(E_STORE,0);
181: t_savearea = &p[sz-1];
182: copy_stack(t_basep,sz,t_savearea);
183: };
184: }
185:
186: extern int rr2,rr3,rr4;
187: int rr2,rr3,rr4;
188:
189: swap(task*);
190: sswap(task*);
191:
192: void task::restore()
193: /*
194: make "this" task run after suspension by returning from the frame
195: denoted by "t_framep"
196:
197: the key function "swap" is written in assembly code,
198: it returns from the function which "save"d the task
199: - typically the scheduler
200:
201: "sswap" copies the stack back from the save area before "swap"ing
202: arguments to "sswap" are passed in rr2,rr3,rr4 to avoid overwriting them
203: it is equivallent to "copystack" followed by "swap".
204: */
205: {
206: register sz;
207:
208: SETTRAP();
209:
210: if ((t_mode == SHARED) && (sz=t_size)){
211: register* p = t_savearea - sz + 1;
212: register x = (this != t_team->got_stack);
213: t_team->got_stack = this;
214: delete p;
215: if (x) {
216: rr4 = (int) t_savearea;
217: rr3 = sz;
218: rr2 = (int) t_basep;
219: sswap(this);
220: }
221: else
222: swap(this);
223: }
224: else
225: swap(this);
226: }
227:
228: void task::cancel(int val)
229: /*
230: TERMINATE and free stack space
231: */
232: {
233: sched::cancel(val);
234: if (_hwm) t_size = curr_hwm();
235: if (t_team->no_of_tasks-- == 1) delete t_team;
236: }
237:
238: task::~task()
239: /*
240: free stack space and remove task from task chain
241: */
242: {
243: if (s_state != TERMINATED) task_error(E_TASKDEL,this);
244: if (this == task_chain)
245: task_chain = t_next;
246: else {
247: register task* t;
248: register task* tt;
249:
250: for (t=task_chain; tt=t->t_next; t=tt)
251: if (tt == this) {
252: t->t_next = t_next;
253: break;
254: }
255: }
256:
257: if (this == thistask) {
258: delete (int*) thistask; /* fudge: free(_that) */
259: thistask = 0;
260: schedule();
261: }
262: }
263:
264: void task::resultis(int val)
265: {
266: cancel(val);
267: if (this == thistask) schedule();
268: }
269:
270: void task::sleep()
271: {
272: if (s_state == RUNNING) remove();
273: if (this == thistask) schedule();
274: }
275:
276: void task::delay(int d)
277: {
278: insert(d,this);
279: if (thistask == this) schedule();
280: }
281:
282: int task::preempt()
283: {
284: if (s_state == RUNNING) {
285: remove();
286: return s_time-clock;
287: }
288: else {
289: task_error(E_TASKPRE,this);
290: return 0;
291: }
292: }
293:
294: char* state_string(int s)
295: {
296: switch (s) {
297: case IDLE: return "IDLE";
298: case TERMINATED: return "TERMINATED";
299: case RUNNING: return "RUNNING";
300: default: return 0;
301: }
302: }
303:
304: char* mode_string(int m)
305: {
306: switch(m) {
307: case SHARED: return "SHARED";
308: case DEDICATED: return "DEDICATED";
309: default: return 0;
310: }
311: }
312:
313: void task::print(int n)
314: /*
315: ``n'' values: CHAIN,VERBOSE,STACK
316: */
317: {
318: char* ss = state_string(s_state);
319: char* ns = (t_name) ? t_name : "";
320:
321: printf("task %s ",ns);
322: if (this == thistask)
323: printf("(is thistask):\n");
324: else if (ss)
325: printf("(%s):\n",ss);
326: else
327: printf("(state==%d CORRUPTED):\n",s_state);
328:
329: if (n&VERBOSE) {
330: int res = (s_state==TERMINATED) ? (int) s_time : 0;
331: char* ms = mode_string(t_mode);
332: if (ms == 0) ms = "CORRUPTED";
333: printf("\tthis==%d mode=%s alert=%d next=%d result=%d\n",
334: this,ms,t_alert,t_next,res);
335: }
336:
337: if (n&STACK) {
338: printf("\tstack: ");
339: if (s_state == TERMINATED) {
340: if (_hwm) printf("hwm=%d",t_size);
341: printf(" deleted\n");
342: }
343: else {
344: int b = (int) t_basep;
345: int x = ((this==thistask) || t_mode==DEDICATED) ? b-(int)t_framep : t_size;
346: printf("max=%d current=%d",t_stacksize,x);
347: if (_hwm) printf(" hwm=%d",curr_hwm());
348: printf(" t_base=%d, t_frame=%d, t_size=%d\n",b,t_framep,t_size);
349: }
350: }
351:
352: if (n&CHAIN) {
353: if (t_next) t_next->print(n);
354: }
355: }
356:
357: int task.curr_hwm()
358: {
359: int* b = t_basep;
360: int i;
361: for (i=t_stacksize-1; 0<=i && *(b-i)==UNTOUCHED; i--) ;
362: return i;
363: }
364:
365: int task.waitlist(object* a)
366: {
367: return waitvec(&a);
368: }
369:
370: int task.waitvec(object* * v)
371: /*
372: first determine if it is necessary to sleep(),
373: return hint: who caused return
374: */
375: {
376: int i = 0;
377: int r;
378: object* ob;
379:
380: while (ob = v[i++]) {
381: t_alert = ob;
382: switch (ob->o_type) {
383: case TASK:
384: case TIMER:
385: if (((sched*)ob)->s_state == TERMINATED) goto ex;
386: break;
387: case QHEAD:
388: if (((qhead*)ob)->rdcount()) goto ex;
389: break;
390: case QTAIL:
391: if (((qtail*)ob)->rdspace()) goto ex;
392: break;
393: }
394: ob->remember(this);
395: }
396: if (i==2 && v[0]==(object*)thistask) task_error(E_WAIT,0);
397: sleep();
398: ex:
399: i = 0;
400: while (ob = v[i++]) {
401: ob->forget(this);
402: if (ob == t_alert) r = i-1;
403: }
404: return r;
405: }
406:
407:
408:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.