|
|
researchv9-SUN3(old)
#include "task.h"
/* macros giving the addresses of the stack frame pointer
and the program counter of the caller of the current function
given the first local variable
TOP points to the top of the current stack frame
given the last local variable
*/
#ifdef pdp11
#define FP() (&_that+4)
#define OLD_FP(fp) (*fp)
#define TOP(var9) (&var9)
#endif
#ifdef vax
#define FP(p) ((int*)(&p+1))
#define OLD_AP(fp) (*(fp+2))
#define OLD_FP(fp) (*(fp+3))
#define TOP(p) top(&p)
extern int * top(...);
#endif
#define SETTRAP() t_trap = *(t_basep-t_stacksize+1)
#define CHECKTRAP() if (t_trap != *(t_basep-t_stacksize+1)) task_error(E_STACK,0)
int _hwm;
class team
{
friend task;
int no_of_tasks;
task* got_stack;
int* stack;
team(task*, int = 0);
~team() { delete stack; }
};
team.team(task* t, int stacksize) {
no_of_tasks = 1;
got_stack = t;
if (stacksize) {
stack = new int[stacksize];
while (stack == 0) task_error(E_STORE,0);
}
}
void usemainstack()
/* fudge to allow simple stack overflow check */
{
register v[SIZE+100];
if (_hwm)
for (register i=0;i<SIZE+100;i++) v[i] = UNTOUCHED;
else
v[0] = 0;
}
void copy_stack(register* f, register c, register* t)
/*
copy c words down from f to t
do NOT attempt to copy "copy_stack"'s own stackframe
*/
{
while (c--) { *t-- = *f--;}
}
void task.swap_stack(int* p, int* ta, int* de, int* pa, int* ap)
{
int x = pa-TOP(x)+1; /* size of active stack */
copy_stack(pa,x,p);
x = pa-p; /* distance from old stack to new */
t_framep = ta-x; /* fp on new frame */
/* now doctor the new frame */
#ifdef vax
OLD_AP(t_framep) = int(ap-x);
#endif
OLD_FP(t_framep) = int(de-x);
restore();
}
#include <stdio.h>
task::task(char* name, int mode, int stacksize) : (TASK)
/*
executed in the task creating a new task - thistask.
1: put thistask at head of scheduler queue,
2: create new task
3: transfer execution to new task
derived::derived can never return - its return link is destroyed
if thistask==0 then we are executing on main()'s stack and
should turn it into the "main" task
*/
{
int* p;
int* ta_fp = (int*)FP(p);
int* de_fp = (int*)OLD_FP(ta_fp);
#ifdef vax
int* de_ap = (int*)OLD_AP(ta_fp);
#endif
int* pa_fp = (int*)OLD_FP(de_fp);
int x;
//fprintf(stderr,"task\n");
t_name = name;
t_mode = (mode) ? mode : DEDICATED;
t_stacksize = (stacksize) ? stacksize : SIZE;
t_size = 0; /* avoid stack copy at initial restore */
t_alert = 0;
s_state = RUNNING;
t_next = task_chain;
task_chain = this;
th = this; /* fudged return value -- "returned" from swap */
//fprintf(stderr,"this %d name %s mode %d size %d\n",this,name,mode,stacksize);
switch ((int)thistask) {
case 0:
/* initialize task system by creating "main" task */
thistask = (task*) 1;
thistask = new task("main");
break;
case 1:
/* create "main" task */
usemainstack(); /* ensure that store is allocated */
t_basep = (int*)OLD_FP(pa_fp); /* fudge, what if main
is already deeply nested
*/
t_team = new team(this); /* don't allocate stack */
t_team->no_of_tasks = 2; /* never deallocate */
return;
}
thistask->th = this; /* return pointer to "child" */
thistask->t_framep = de_fp;
thistask->insert(0,this);
switch (t_mode) {
case DEDICATED:
t_team = new team(this,t_stacksize);
t_basep = t_team->stack + t_stacksize - 1;
if (_hwm) for (x=0; x<t_stacksize; x++) p[x] = UNTOUCHED;
thistask = this;
swap_stack(t_basep,ta_fp,de_fp,pa_fp,de_ap);
case SHARED:
thistask->t_mode = SHARED; /* you cannot share on your own */
t_basep = pa_fp;
t_team = thistask->t_team;
t_team->no_of_tasks++;
t_framep = ta_fp;
if (mode==0 && stacksize==0)
t_stacksize = thistask->t_stacksize - (thistask->t_basep - t_basep);
thistask = this;
return;
default:
task_error(E_TASKMODE,this);
}
}
void task::save()
/*
save task's state so that ``restore'' can resume it later
by returning from the function which called "save"
- typically the scheduler
*/
{
int* x;
register* p = (int*)FP(x);
t_framep = (int*)OLD_FP(p);
CHECKTRAP();
if (t_mode == SHARED) {
register int sz;
t_size = sz = t_basep - p + 1;
p = new int[sz];
while (p == 0) task_error(E_STORE,0);
t_savearea = &p[sz-1];
copy_stack(t_basep,sz,t_savearea);
};
}
extern int rr2,rr3,rr4;
int rr2,rr3,rr4;
swap(task*);
sswap(task*);
void task::restore()
/*
make "this" task run after suspension by returning from the frame
denoted by "t_framep"
the key function "swap" is written in assembly code,
it returns from the function which "save"d the task
- typically the scheduler
"sswap" copies the stack back from the save area before "swap"ing
arguments to "sswap" are passed in rr2,rr3,rr4 to avoid overwriting them
it is equivallent to "copystack" followed by "swap".
*/
{
register sz;
SETTRAP();
if ((t_mode == SHARED) && (sz=t_size)){
register* p = t_savearea - sz + 1;
register x = (this != t_team->got_stack);
t_team->got_stack = this;
delete p;
if (x) {
rr4 = (int) t_savearea;
rr3 = sz;
rr2 = (int) t_basep;
sswap(this);
}
else
swap(this);
}
else
swap(this);
}
void task::cancel(int val)
/*
TERMINATE and free stack space
*/
{
sched::cancel(val);
if (_hwm) t_size = curr_hwm();
if (t_team->no_of_tasks-- == 1) delete t_team;
}
task::~task()
/*
free stack space and remove task from task chain
*/
{
if (s_state != TERMINATED) task_error(E_TASKDEL,this);
if (this == task_chain)
task_chain = t_next;
else {
register task* t;
register task* tt;
for (t=task_chain; tt=t->t_next; t=tt)
if (tt == this) {
t->t_next = t_next;
break;
}
}
if (this == thistask) {
delete (int*) thistask; /* fudge: free(_that) */
thistask = 0;
schedule();
}
}
void task::resultis(int val)
{
cancel(val);
if (this == thistask) schedule();
}
void task::sleep()
{
if (s_state == RUNNING) remove();
if (this == thistask) schedule();
}
void task::delay(int d)
{
insert(d,this);
if (thistask == this) schedule();
}
int task::preempt()
{
if (s_state == RUNNING) {
remove();
return s_time-clock;
}
else {
task_error(E_TASKPRE,this);
return 0;
}
}
char* state_string(int s)
{
switch (s) {
case IDLE: return "IDLE";
case TERMINATED: return "TERMINATED";
case RUNNING: return "RUNNING";
default: return 0;
}
}
char* mode_string(int m)
{
switch(m) {
case SHARED: return "SHARED";
case DEDICATED: return "DEDICATED";
default: return 0;
}
}
void task::print(int n)
/*
``n'' values: CHAIN,VERBOSE,STACK
*/
{
char* ss = state_string(s_state);
char* ns = (t_name) ? t_name : "";
printf("task %s ",ns);
if (this == thistask)
printf("(is thistask):\n");
else if (ss)
printf("(%s):\n",ss);
else
printf("(state==%d CORRUPTED):\n",s_state);
if (n&VERBOSE) {
int res = (s_state==TERMINATED) ? (int) s_time : 0;
char* ms = mode_string(t_mode);
if (ms == 0) ms = "CORRUPTED";
printf("\tthis==%d mode=%s alert=%d next=%d result=%d\n",
this,ms,t_alert,t_next,res);
}
if (n&STACK) {
printf("\tstack: ");
if (s_state == TERMINATED) {
if (_hwm) printf("hwm=%d",t_size);
printf(" deleted\n");
}
else {
int b = (int) t_basep;
int x = ((this==thistask) || t_mode==DEDICATED) ? b-(int)t_framep : t_size;
printf("max=%d current=%d",t_stacksize,x);
if (_hwm) printf(" hwm=%d",curr_hwm());
printf(" t_base=%d, t_frame=%d, t_size=%d\n",b,t_framep,t_size);
}
}
if (n&CHAIN) {
if (t_next) t_next->print(n);
}
}
int task.curr_hwm()
{
int* b = t_basep;
int i;
for (i=t_stacksize-1; 0<=i && *(b-i)==UNTOUCHED; i--) ;
return i;
}
int task.waitlist(object* a)
{
return waitvec(&a);
}
int task.waitvec(object* * v)
/*
first determine if it is necessary to sleep(),
return hint: who caused return
*/
{
int i = 0;
int r;
object* ob;
while (ob = v[i++]) {
t_alert = ob;
switch (ob->o_type) {
case TASK:
case TIMER:
if (((sched*)ob)->s_state == TERMINATED) goto ex;
break;
case QHEAD:
if (((qhead*)ob)->rdcount()) goto ex;
break;
case QTAIL:
if (((qtail*)ob)->rdspace()) goto ex;
break;
}
ob->remember(this);
}
if (i==2 && v[0]==(object*)thistask) task_error(E_WAIT,0);
sleep();
ex:
i = 0;
while (ob = v[i++]) {
ob->forget(this);
if (ob == t_alert) r = i-1;
}
return r;
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.