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