Personal tools
You are here: Home Projects C++ Cfront releases Release 1.0 Source cfront lib task task.c
Document Actions

task.c

by Paul McJones last modified 2007-02-02 09:33

Click here to get the file

Size 11.0 kB - File type text/x-csrc

File contents

/* @(#) task.c 1.2 1/27/86 17:48:10 */
/*ident	"@(#)cfront:lib/task/task.c	1.2"*/
/* @(#) task.c 1.3 1/17/85 14:41:14 */

#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

// STACK GROWS DOWN
#define FP(p)		( (int*)(&p+4) )
#define AP()		0	/* unnecessary on pdp11 */
#define OLD_FP(fp)	(*fp)
#define TOP(var9)	(&var9)

#define COPY_STACK(f,c,t)   while (c--) *t-- = *f--
#define ACTIVE_STK_SZ(b,t)  b - t + 1	/* size of active stack */
#define STACK_BASE(b,s)     b + s - 1
#define SAVED_AREA(b,s)     b - s + 1
#define FIX_FRAME(x)\
	OLD_FP(t_framep) = int(de_fp - x)

#define SETTRAP()	t_trap = *(t_basep-t_stacksize+1)
#define CHECKTRAP()	if (t_trap != *(t_basep-t_stacksize+1)) task_error(E_STACK,0)

#endif


#ifdef vax

// STACK GROWS DOWN
#define FP(p)		( (int*)(&p+1) )
#define AP()		0	/* unnecessary on vax */
#define OLD_AP(fp)	(*(fp+2))
#define OLD_FP(fp)	(*(fp+3))
#define TOP(p)		top(&p)
extern int * top(...);

#define COPY_STACK(f,c,t)   while (c--) *t-- = *f--
#define ACTIVE_STK_SZ(b,t)  b - t + 1	/* size of active stack */
#define STACK_BASE(b,s)     b + s - 1
#define SAVED_AREA(b,s)     b - s + 1
#define FIX_FRAME(x)\
	OLD_AP(t_framep) = int(de_ap - x);\
	OLD_FP(t_framep) = int(de_fp - x)

#define SETTRAP()	t_trap = *(t_basep-t_stacksize+1)
#define CHECKTRAP()	if (t_trap != *(t_basep-t_stacksize+1)) task_error(E_STACK,0)

#endif


#if defined(u3b) || defined(u3b5) || defined(u3b2)

// STACK GROWS UP
#define FP(p)		( (int*)&p )
extern int * AP();	/* AP of current frame */
#define TOP(x)		(int*)( (int*)&x + 1 )

#ifdef u3b
asm("	.text");
asm("	.globl	AP");
asm("	.align	4");
asm("AP:");
asm("	save &0");
asm("	movw	-48(%fp),%r0  # caller's ap");
asm("	ret &0");
#define OLD_FP(fp)	( *( (int*)fp - 11 ) )
#define OLD_AP(fp)	( *( (int*)fp - 12 ) )
#else
asm("	.text");
asm("	.globl	AP");
asm("	.align	4");
asm("AP:");
asm("	save &0");
asm("	movw	-32(%fp),%r0  # caller's ap");
asm("	ret &0");
#define OLD_FP(fp)	( *( (int*)fp - 7 ) )
#define OLD_AP(fp)	( *( (int*)fp - 8 ) )
#endif

#define COPY_STACK(f,c,t)   while (c--)  *t++ = *f++
#define ACTIVE_STK_SZ(b,t)  t - b + 1	/* size of active stack */
#define STACK_BASE(b,s)     b
#define SAVED_AREA(b,s)     b
#define FIX_FRAME(x)\
	t_ap = AP() - x;\
	OLD_AP(t_framep) = int(de_ap - x);\
	OLD_FP(t_framep) = int(de_fp - x)

#define SETTRAP()	t_trap = *(t_basep + t_stacksize - 1)
#define CHECKTRAP()	if (t_trap != *(t_basep+t_stacksize-1)) task_error(E_STACK,0)

#endif


// ---- END OF MACROS ----

int _hwm;

class team
{
friend task;
	int	no_of_tasks;
	task*	got_stack;
	int*	stack;
	team(task*, int = 0);
};

team.team(task* t, int stacksize) {
	stacksize += sizeof(team);	// alloc team and stack together
	this = (team*)new int[stacksize];
	while (this == 0) task_error(E_STORE,0);
	stack = (int*)this + sizeof(team);
	no_of_tasks = 1;
	got_stack = t;
}


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
*/
{
	DB(("   copying( %x, %x, %x )\n", f, c, t));
	COPY_STACK(f,c,t);
	DB(("   copied\n"));
}


#define ABSV(x) ( (x) > 0 ? (x) : -(x) )
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);
	int* de_ap;
	de_ap = (int*)OLD_AP(ta_fp);
	int* pa_fp = (int*)OLD_FP(de_fp);
	int x;

	DB(("%x->task::task( %s, %x, %x )\n", this,name,mode,stacksize));
	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 */

	switch ((int)thistask) {
	case 0:
		/* initialize task system by creating "main" task */
		thistask = (task*) 1;
		DB(("   thistask = new task(\"main\")\n"));
		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;  /* return to caller of derived ctor */
	thistask->t_ap = de_ap;
	thistask->insert(0,this);

	switch (t_mode) {
	case DEDICATED:
		t_team = new team(this,t_stacksize);
		t_basep = STACK_BASE(t_team->stack, t_stacksize);
		if (_hwm) for (x=0; x<t_stacksize; x++)
			t_team->stack[x] = UNTOUCHED;
		thistask = this;
		DB(("%x->task::task -- ta_fp = %x\n",this,ta_fp));
		DB(("%x->task::task -- ta_ap = %x\n",this,AP()));
		x = ACTIVE_STK_SZ(pa_fp, TOP(x));
		copy_stack(pa_fp, x, t_basep);
		x = pa_fp - t_basep;	/* distance from old stack to new */
		t_framep = ta_fp - x;	/* fp on new frame */
					/* now doctor the new frame */
		DB(("  OFP(t_framep),de_fp == %x,%x\n",OLD_FP(t_framep),de_fp));
		DB(("  OAP(t_framep),de_ap == %x,%x\n",OLD_AP(t_framep),de_ap));
		FIX_FRAME(x);
		restore();
	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;
		t_ap = AP();
		if (mode==0 && stacksize==0)
			t_stacksize = thistask->t_stacksize
					- ABSV(thistask->t_basep - t_basep);
		thistask = this;
		SETTRAP();	// normally done in restore()
		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* p = (int*)FP(p);

	DB(("%x->task::save()\n",this));
	t_framep = (int*)OLD_FP(p);
	t_ap = (int*)OLD_AP(p);

	CHECKTRAP();

	if (t_mode == SHARED) {
		register int sz;
		t_size = sz = ACTIVE_STK_SZ(t_basep, TOP(p));
		p = new int[sz];
		while (p == 0) task_error(E_STORE,0);
		t_savearea = STACK_BASE(p, sz);
		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();

	DB(("%x->task::restore()\n",this));
	if ((t_mode == SHARED) && (sz=t_size)){
		register* p = SAVED_AREA(t_savearea, sz); // get ptr for delete
		register x = (this != t_team->got_stack);
		t_team->got_stack = this;
		if (x) {
			DB(("	p		= x%x\n", p));
			DB(("	t_savearea	= x%x\n", t_savearea));
			DB(("	sz		= x%x\n", sz));
			DB(("	t_basep		= x%x\n", t_basep));
			delete p;
			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
*/
{
	DB(("%x->task::cancel( %x )\n",this,val));
	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
*/
{
	DB(("%x->task::~task()\n",this));
	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)
{
	DB(("%x->task::resultis( %x )\n",this,val));
	cancel(val);
	if (this == thistask) schedule();
}

void task.sleep()
{
	DB(("%x->task::sleep()\n",this));
	if (s_state == RUNNING) remove();
	if (this == thistask) schedule();
}

void task.delay(int d)
{
	DB(("%x->task::delay( %x )\n",this,d));
	insert(d,this);
	if (thistask == this) schedule();
}

int task.preempt()
{
	DB(("%x->task::preempt()\n",this));
	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==x%x mode=%s alert=x%x next=x%x result=%d\n",
			this,ms,t_alert,t_next,res);
	}

	if (n&STACK) {
		printf("\tstack: ");
		if (s_state == TERMINATED) {
			if (_hwm) printf("hwm=x%x",t_size);
			printf(" deleted\n");
		}
		else {
			int b = (int) t_basep;
			int x = ((this==thistask) || t_mode==DEDICATED)
				? ACTIVE_STK_SZ( b, (int)t_framep ) : t_size;
			printf("max=%d current=%d",t_stacksize,x);
			if (_hwm) printf(" hwm=x%x",curr_hwm());
			printf(" t_basep=x%x, t_framep=x%x, t_size=x%x\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;
} 
« March 2024 »
Su Mo Tu We Th Fr Sa
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
 

Powered by Plone CMS, the Open Source Content Management System

This site conforms to the following standards: