|
|
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:
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:
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: switch ((int)thistask) {
120: case 0:
121: /* initialize task system by creating "main" task */
122: thistask = (task*) 1;
123: thistask = new task("main");
124: break;
125: case 1:
126: /* create "main" task */
127: usemainstack(); /* ensure that store is allocated */
128: t_basep = (int*)OLD_FP(pa_fp); /* fudge, what if main
129: is already deeply nested
130: */
131: t_team = new team(this); /* don't allocate stack */
132: t_team->no_of_tasks = 2; /* never deallocate */
133: return;
134: }
135: thistask->th = this; /* return pointer to "child" */
136: thistask->t_framep = de_fp;
137: thistask->insert(0,this);
138:
139: switch (t_mode) {
140: case DEDICATED:
141: t_team = new team(this,t_stacksize);
142: t_basep = t_team->stack + t_stacksize - 1;
143: if (_hwm) for (x=0; x<t_stacksize; x++) p[x] = UNTOUCHED;
144: thistask = this;
145: swap_stack(t_basep,ta_fp,de_fp,pa_fp,de_ap);
146: case SHARED:
147: thistask->t_mode = SHARED; /* you cannot share on your own */
148: t_basep = pa_fp;
149: t_team = thistask->t_team;
150: t_team->no_of_tasks++;
151: t_framep = ta_fp;
152: if (mode==0 && stacksize==0)
153: t_stacksize = thistask->t_stacksize - (thistask->t_basep - t_basep);
154: thistask = this;
155: return;
156: default:
157: task_error(E_TASKMODE,this);
158: }
159: }
160:
161: void task.save()
162: /*
163: save task's state so that ``restore'' can resume it later
164: by returning from the function which called "save"
165: - typically the scheduler
166: */
167: {
168: int* x;
169: register* p = (int*)FP(x);
170:
171: t_framep = (int*)OLD_FP(p);
172:
173: CHECKTRAP();
174:
175: if (t_mode == SHARED) {
176: register int sz;
177: t_size = sz = t_basep - p + 1;
178: p = new int[sz];
179: while (p == 0) task_error(E_STORE,0);
180: t_savearea = &p[sz-1];
181: copy_stack(t_basep,sz,t_savearea);
182: };
183: }
184:
185: extern int rr2,rr3,rr4;
186: int rr2,rr3,rr4;
187:
188: swap(task*);
189: sswap(task*);
190:
191: void task.restore()
192: /*
193: make "this" task run after suspension by returning from the frame
194: denoted by "t_framep"
195:
196: the key function "swap" is written in assembly code,
197: it returns from the function which "save"d the task
198: - typically the scheduler
199:
200: "sswap" copies the stack back from the save area before "swap"ing
201: arguments to "sswap" are passed in rr2,rr3,rr4 to avoid overwriting them
202: it is equivallent to "copystack" followed by "swap".
203: */
204: {
205: register sz;
206:
207: SETTRAP();
208:
209: if ((t_mode == SHARED) && (sz=t_size)){
210: register* p = t_savearea - sz + 1;
211: register x = (this != t_team->got_stack);
212: t_team->got_stack = this;
213: delete p;
214: if (x) {
215: rr4 = (int) t_savearea;
216: rr3 = sz;
217: rr2 = (int) t_basep;
218: sswap(this);
219: }
220: else
221: swap(this);
222: }
223: else
224: swap(this);
225: }
226:
227: void task.cancel(int val)
228: /*
229: TERMINATE and free stack space
230: */
231: {
232: sched::cancel(val);
233: if (_hwm) t_size = curr_hwm();
234: if (t_team->no_of_tasks-- == 1) delete t_team;
235: }
236:
237: task.~task()
238: /*
239: free stack space and remove task from task chain
240: */
241: {
242: if (s_state != TERMINATED) task_error(E_TASKDEL,this);
243: if (this == task_chain)
244: task_chain = t_next;
245: else {
246: register task* t;
247: register task* tt;
248:
249: for (t=task_chain; tt=t->t_next; t=tt)
250: if (tt == this) {
251: t->t_next = t_next;
252: break;
253: }
254: }
255:
256: if (this == thistask) {
257: delete (int*) thistask; /* fudge: free(_that) */
258: thistask = 0;
259: schedule();
260: }
261: }
262:
263: void task.resultis(int val)
264: {
265: cancel(val);
266: if (this == thistask) schedule();
267: }
268:
269: void task.sleep()
270: {
271: if (s_state == RUNNING) remove();
272: if (this == thistask) schedule();
273: }
274:
275: void task.delay(int d)
276: {
277: insert(d,this);
278: if (thistask == this) schedule();
279: }
280:
281: int task.preempt()
282: {
283: if (s_state == RUNNING) {
284: remove();
285: return s_time-clock;
286: }
287: else {
288: task_error(E_TASKPRE,this);
289: return 0;
290: }
291: }
292:
293: char* state_string(int s)
294: {
295: switch (s) {
296: case IDLE: return "IDLE";
297: case TERMINATED: return "TERMINATED";
298: case RUNNING: return "RUNNING";
299: default: return 0;
300: }
301: }
302:
303: char* mode_string(int m)
304: {
305: switch(m) {
306: case SHARED: return "SHARED";
307: case DEDICATED: return "DEDICATED";
308: default: return 0;
309: }
310: }
311:
312: void task.print(int n)
313: /*
314: ``n'' values: CHAIN,VERBOSE,STACK
315: */
316: {
317: char* ss = state_string(s_state);
318: char* ns = (t_name) ? t_name : "";
319:
320: printf("task %s ",ns);
321: if (this == thistask)
322: printf("(is thistask):\n");
323: else if (ss)
324: printf("(%s):\n",ss);
325: else
326: printf("(state==%d CORRUPTED):\n",s_state);
327:
328: if (n&VERBOSE) {
329: int res = (s_state==TERMINATED) ? (int) s_time : 0;
330: char* ms = mode_string(t_mode);
331: if (ms == 0) ms = "CORRUPTED";
332: printf("\tthis==%d mode=%s alert=%d next=%d result=%d\n",
333: this,ms,t_alert,t_next,res);
334: }
335:
336: if (n&STACK) {
337: printf("\tstack: ");
338: if (s_state == TERMINATED) {
339: if (_hwm) printf("hwm=%d",t_size);
340: printf(" deleted\n");
341: }
342: else {
343: int b = (int) t_basep;
344: int x = ((this==thistask) || t_mode==DEDICATED) ? b-(int)t_framep : t_size;
345: printf("max=%d current=%d",t_stacksize,x);
346: if (_hwm) printf(" hwm=%d",curr_hwm());
347: printf(" t_base=%d, t_frame=%d, t_size=%d\n",b,t_framep,t_size);
348: }
349: }
350:
351: if (n&CHAIN) {
352: if (t_next) t_next->print(n);
353: }
354: }
355:
356: int task.curr_hwm()
357: {
358: int* b = t_basep;
359: int i;
360: for (i=t_stacksize-1; 0<=i && *(b-i)==UNTOUCHED; i--) ;
361: return i;
362: }
363:
364: int task.waitlist(object* a)
365: {
366: return waitvec(&a);
367: }
368:
369: int task.waitvec(object* * v)
370: /*
371: first determine if it is necessary to sleep(),
372: return hint: who caused return
373: */
374: {
375: int i = 0;
376: int r;
377: object* ob;
378:
379: while (ob = v[i++]) {
380: t_alert = ob;
381: switch (ob->o_type) {
382: case TASK:
383: case TIMER:
384: if (((sched*)ob)->s_state == TERMINATED) goto ex;
385: break;
386: case QHEAD:
387: if (((qhead*)ob)->rdcount()) goto ex;
388: break;
389: case QTAIL:
390: if (((qtail*)ob)->rdspace()) goto ex;
391: break;
392: }
393: ob->remember(this);
394: }
395: if (i==2 && v[0]==(object*)thistask) task_error(E_WAIT,0);
396: sleep();
397: ex:
398: i = 0;
399: while (ob = v[i++]) {
400: ob->forget(this);
401: if (ob == t_alert) r = i-1;
402: }
403: return r;
404: }
405:
406:
407:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.