~kris/9p

9hist

1e4e061266d9170c137dbb53793c6634d2fdfd3b — David du Colombier 24 years ago 510a483
Plan 9 from Bell Labs 2002-08-31
4 files changed, 382 insertions(+), 293 deletions(-)

M port/auth.c
M port/devrealtime.c
M port/edf.c
M port/edf.h
M port/auth.c => port/auth.c +1 -1
@@ 67,7 67,7 @@ sysfauth(ulong *arg)

	validaddr(arg[1], 1, 0);
	aname = (char*)arg[1];
	validname(aname, 0);
	validname(aname, 1);
	c = fdtochan(arg[0], ORDWR, 0, 1);
	if(waserror()){
		cclose(c);

M port/devrealtime.c => port/devrealtime.c +288 -235
@@ 22,6 22,7 @@ static QLock elock;
static Ref logopens;
static Ref debugopens;
static uvlong fasthz;	
static int taskno;

static int		timeconv(Fmt *);
static char *	parsetime(Time *, char *);


@@ 32,6 33,7 @@ enum {
	Qrealtime,
	Qclone,
	Qdebug,
	Qdump,
	Qlog,
	Qnblog,
	Qresrc,


@@ 51,6 53,7 @@ Dirtab scheddir[]={
	".",			{Qrealtime, 0, QTDIR},	0,	DMDIR|0555,
	"clone",		{Qclone},				0,	0666,
	"debug",		{Qdebug},				0,	0444,
	"dump",		{Qdump},				0,	0444,
	"log",		{Qlog},				0,	0444,	/* one open only */
	"nblog",		{Qnblog},				0,	0444,	/* nonblocking version of log */
	"resources",	{Qresrc},				0,	0444,


@@ 70,6 73,18 @@ static char *schedstatename[] = {
	[SExpel] =		"Expel",
};

Task *
findtask(int taskno)
{
	List *l;
	Task *t;

	for (l = tasks.next; l; l = l->next)
		if ((t = l->i) && t->taskno == taskno)
			return t;
	return nil;
}

static char*
dumptask(char *p, char *e, Task *t, Ticks now)
{


@@ 122,6 137,42 @@ dumpq(char *p, char *e, Taskq *q, Ticks now)
	return nil;
}

static Task *
taskinit(void)
{
	Dirtab *d;
	Task *t;

	t = malloc(sizeof(Task));
	if (t == nil)
		error("taskinit: malloc");
	d = &t->dir;
	if (up->user)
		kstrdup(&t->user, up->user);
	else
		kstrdup(&t->user, eve);
	t->state = EdfExpelled;
	t->taskno = ++taskno;
	snprint(d->name, sizeof d->name, "%d", t->taskno);
	mkqid(&d->qid, Qistask | t->taskno, 0, QTFILE);
	d->length = 0;
	d->perm = 0600;
	enlist(&tasks, t);
	incref(t);
	return t;
}

void
taskfree(Task *t)
{
	if (decref(t))
		return;
	assert(t->procs.n == 0);
	assert(t->res.n == 0);
	free(t->user);
	free(t);
}

/*
 * the zeroth element of the table MUST be the directory itself for ..
*/


@@ 133,18 184,28 @@ schedgen(Chan *c, char*, Dirtab *, int, int i, Dir *dp)
	char *owner;
	ulong taskindex;
	Qid qid;
	Task *t;
	List *l;

	if((ulong)c->qid.path & Qistask){
		qlock(&edfschedlock);
		taskindex = (ulong)c->qid.path & (Qistask-1);
		if (taskindex >= Maxtasks || tasks[taskindex].state == EdfUnused)
		if ((t = findtask(taskindex)) == nil){
			qunlock(&edfschedlock);
			return -1;
		}
	}else if((ulong)c->qid.path == Qtask){
		qlock(&edfschedlock);

		taskindex = i;
		for (i = 0; i < Maxtasks; i++)
			if (tasks[i].state != EdfUnused && taskindex-- == 0)
		SET(t);
		for (l = tasks.next; l; l = l->next)
			if ((t = l->i) && taskindex-- == 0)
				break;
		if (i == Maxtasks)
		if (l == nil){
			qunlock(&edfschedlock);
			return -1;
		}
	}else {
		if((ulong)c->qid.path == Qdir){
			tab = schedrootdir;


@@ 166,13 227,14 @@ schedgen(Chan *c, char*, Dirtab *, int, int i, Dir *dp)
	if(i == DEVDOTDOT){
		mkqid(&qid, Qtask, 0, QTDIR);
		devdir(c, qid, ".", 0, eve, 0555, dp);
		return 1;
	}else{
		owner = t->user;
		if (owner == nil)
			owner = eve;
		tab = &t->dir;
		devdir(c, tab->qid, tab->name, tab->length, owner, tab->perm, dp);
	}
	owner = tasks[i].user;
	if (owner == nil)
		owner = eve;
	tab = &tasks[i].dir;
	devdir(c, tab->qid, tab->name, tab->length, owner, tab->perm, dp);
	qunlock(&edfschedlock);
	return 1;
}



@@ 183,7 245,7 @@ _devrt(Task *t, Ticks t1, SEvent etype)
		return;

	if(edfprint)iprint("state %s\n", schedstatename[etype]);
	events[wevent].tid = t - tasks;
	events[wevent].tid = t->taskno;
	events[wevent].ts = 0;
	if (t1)
		events[wevent].ts = ticks2time(t1);


@@ 241,25 303,6 @@ devrtstat(Chan *c, uchar *db, int n)
	return devstat(c, db, n, nil, 0, schedgen);
}

static void
taskinit(Task *t)
{
	Dirtab *d;

	d = &t->dir;
	memset(t, 0, sizeof(Task));
	if (up->user)
		kstrdup(&t->user, up->user);
	else
		kstrdup(&t->user, eve);
	t->state = EdfExpelled;
	snprint(d->name, sizeof d->name, "%ld", t - tasks);
	mkqid(&d->qid, Qistask | (t - tasks), 0, QTFILE);
	d->length = 0;
	d->perm = 0600;
	ntasks++;
}

static Chan *
devrtopen(Chan *c, int mode)
{


@@ 285,22 328,19 @@ devrtopen(Chan *c, int mode)
			error("already open");
		}
		break;
	case Qdump:
		if (mode != OREAD) 
			error(Eperm);
		break;
	case Qclone:
		if (mode == OREAD) 
			error(Eperm);
		edf->edfinit();
		qlock(&edfschedlock);
		/* open a new task */
		for (t = tasks; t< tasks + Maxtasks; t++){
			qlock(t);
			if(t->state == EdfUnused){
				taskinit(t);
				c->qid.vers = t - tasks;
				break;
			}
			qunlock(t);
		}
		if (t == tasks + Maxtasks)
			error("too many tasks");
		t = taskinit();
		c->qid.vers = t->taskno;
		qunlock(&edfschedlock);
		break;
	}
//	print("open %lux, mode %o\n", (ulong)c->qid.path, mode);


@@ 337,9 377,11 @@ devrtread(Chan *c, void *v, long n, vlong offs)
	long n0;
	int navail;
	Task *t;
	int s, i, fst;
	int s, i;
	Ticks now;
	Time tim;
	List *l;
	Resource *r;

	n0 = n;
//	print("schedread 0x%lux\n", (ulong)c->qid.path);


@@ 403,32 445,45 @@ devrtread(Chan *c, void *v, long n, vlong offs)
		qunlock(&elock);
		break;
	case Qresrc:
		qlock(&edfschedlock);
		if(waserror()){
			qunlock(&edfschedlock);
			nexterror();
		}
		p = buf;
		e = p + sizeof(buf);
		for (i = 0; i < Maxresources; i++){
			if (resources[i].name == nil)
				continue;
			p = seprint(p, e, "name=%s", resources[i].name);
			if (resources[i].ntasks){
		for (l = resources.next; l; l = l->next){
			r = l->i;
			assert(r);
			p = seprint(p, e, "name=%s", r->name);
			if (r->tasks.n){
				List *l;

				p = seprint(p, e, " tasks='");
				fst = 0;
				for (s = 0; s < nelem(resources[i].tasks); s++)
					if (resources[i].tasks[s]){
						if (fst)
							p = seprint(p, e, " ");
						p = seprint(p, e, "%ld", resources[i].tasks[s] - tasks);
						fst++;
					}
				for (l = r->tasks.next; l; l = l->next) {
					if (l != r->tasks.next)
						p = seprint(p, e, " ");
					p = seprint(p, e, "%d", ((Task *)l->i)->taskno);
				}
				p = seprint(p, e, "'");
			}
			if (resources[i].Delta)
				p = seprint(p, e, " Δ=%T", ticks2time(resources[i].Delta));
			else if (resources[i].testDelta)
				p = seprint(p, e, " testΔ=%T", ticks2time(resources[i].testDelta));
			if (r->Delta)
				p = seprint(p, e, " Δ=%T", ticks2time(r->Delta));
			else if (r->testDelta)
				p = seprint(p, e, " testΔ=%T", ticks2time(r->testDelta));
			p = seprint(p, e, "\n");
		}
		qunlock(&edfschedlock);
		poperror();
		return readstr(offs, v, n, buf);
		break;
	case Qdump:
		p = buf;
		e = p + sizeof(buf);
		qlock(&edfschedlock);
		qunlock(&edfschedlock);
		p = seprint(p, e, "\n");
		return readstr(offs, v, n, buf);
	case Qdebug:
		p = buf;
		e = p + sizeof(buf);


@@ 446,7 501,6 @@ devrtread(Chan *c, void *v, long n, vlong offs)
		dumpq(p, e, &qextratime, now);
		iunlock(&edflock);
		return readstr(offs, v, n, buf);
		break;
	case Qclone:
		s = c->qid.vers;
		goto common;


@@ 455,9 509,12 @@ devrtread(Chan *c, void *v, long n, vlong offs)
			error(Enonexist);
		s = (ulong)c->qid.path & (Qistask - 1);
	common:
		if (s < 0 || s >= Maxtasks || tasks[s].state == EdfUnused)
		qlock(&edfschedlock);
		t = findtask(s);
		if (t == nil){
			qunlock(&edfschedlock);
			error(Enonexist);
		t = tasks + s;
		}
		p = buf;
		e = p + sizeof(buf);
		p = seprint(p, e, "task=%d", s);


@@ 473,28 530,26 @@ devrtread(Chan *c, void *v, long n, vlong offs)
		else if (t->testDelta)
			p = seprint(p, e, " testΔ=%T", ticks2time(t->testDelta));
		p = seprint(p, e, " yieldonblock=%d", (t->flags & Verbose) != 0);
		if (t->nres){
		if (t->res.n){
			p = seprint(p, e, " resources='");
			fst = 0;
			for (i = 0; i < nelem(t->res); i++)
				if (t->res[i]){
					if (fst)
						p = seprint(p, e, " ");
					p = seprint(p, e, "%s", t->res[i]->name);
					fst++;
				}
			for (l = t->res.next; l; l = l->next){
				r = l->i;
				assert(r);
				if (l != t->res.next)
					p = seprint(p, e, " ");
				p = seprint(p, e, "%s", r->name);
			}
			p = seprint(p, e, "'");
		}
		if (t->nproc){
		if (t->procs.n){
			p = seprint(p, e, " procs='");
			fst = 0;
			for (i = 0; i < nelem(t->procs); i++)
				if (t->procs[i]){
					if (fst)
						p = seprint(p, e, " ");
					p = seprint(p, e, "%lud", t->procs[i]->pid);
					fst++;
				}
			for (l = t->procs.next; l; l = l->next){
				Proc *pr = l->i;
				assert(pr);
				if (l != t->procs.next)
					p = seprint(p, e, " ");
				p = seprint(p, e, "%lud", pr->pid);
			}
			p = seprint(p, e, "'");
		}
		if (t->periods)


@@ 508,6 563,7 @@ devrtread(Chan *c, void *v, long n, vlong offs)
		if (t->aged)
			p = seprint(p, e, " c=%T", ticks2time(t->aged));
		seprint(p, e, "\n");
		qunlock(&edfschedlock);
		return readstr(offs, v, n, buf);
	}
	return n0 - n;


@@ 516,134 572,47 @@ devrtread(Chan *c, void *v, long n, vlong offs)
static Resource *
resource(char *name, int add)
{
	Resource *r, *i;
	Task **t;

	r = nil;
	for (i = resources; i < resources + nelem(resources); i++){
		if (i->name == nil)
			r = i;
		else if (strcmp(i->name, name) == 0)
			return i;
	}
	if (add == 0)
	Resource *r;
	List *l;

	for (l = resources.next; l; l = l->next)
		if ((r = l->i) && strcmp(r->name, name) == 0)
			return r;
	if (add < 0)
		return nil;
	r = malloc(sizeof(Resource));
	if (r == nil)
		error("too many resources");
		error("resource: malloc");
	kstrdup(&r->name, name);
	for (t = r->tasks; t < r->tasks + nelem(r->tasks); t++)
		*t = nil;
	r->ntasks = 0;
	nresources++;
	enlist(&resources, r);
	return r;
}

static char *
tasktoresource(Resource *r, Task *t, int add)
{
	Task **et, **rt, **i;

	et = nil;
	rt = nil;
	for (i = r->tasks; i < r->tasks + nelem(r->tasks ); i++){
		if (*i == nil)
			et = i;
		else if (*i == t)
			rt = i;
	}
	if (add > 0){
		if (rt)
			return nil;	/* resource already present */
		if (et == nil)
			return "too many resources";
		*et = t;
		r->ntasks++;
	}else{
		if (rt == nil)
			return nil;	/* resource not found */
		*rt = nil;
		r->ntasks--;
	}
	return nil;
}

static char *
resourcetotask(Task *t, Resource *r, int add)
void
resourcefree(Resource *r)
{
	Resource **i, **tr, **er;

	er = nil;
	tr = nil;
	for (i = t->res; i < t->res + nelem(t->res); i++){
		if (*i == nil)
			er = i;
		else if (*i == r)
			tr = i;
	}
	if (add > 0){
		if (tr)
			return nil;	/* resource already present */
		if (er == nil)
			return "too many resources";
		*er = r;
		t->nres++;
	}else{
		if (tr == nil)
			return nil;	/* resource not found */
		*tr = nil;
		t->nres--;
	}
	return nil;
}

static char *
proctotask(Task *t, Proc *p, int add)
{
	Proc **i, **tr, **er;

	er = nil;
	tr = nil;
	for (i = t->procs; i < t->procs + nelem(t->procs); i++){
		if (*i == nil)
			er = i;
		else if (*i == p)
			tr = i;
	}
	if (add > 0){
		if (tr){
			assert (p->task == t);
			return nil;	/* proc already present */
		}
		if (er == nil)
			return "too many resources";
		if (p->task != nil && p->task != t)
			error("proc belongs to another task");
		p->task = t;
		*er = p;
		t->nproc++;
	}else{
		if (tr == nil)
			return nil;	/* resource not found */
		assert(p->task == t);
		p->task = nil;
		*tr = nil;
		t->nproc--;
	}
	return nil;
	if (decref(r))
		return;
	delist(&resources, r);
	assert(r->tasks.n == 0);
	free(r->name);
	free(r);
}

static void
removetask(Task *t)
{
	int s, i;
	Proc *p, **pp;
	Proc *p;
	Resource *r;
	List *l;

	qlock(t);
	edf->edfexpel(t);
	for (pp = t->procs; pp < t->procs + nelem(t->procs); pp++)
		if (p = *pp)
			p->task = nil;
	while (l = t->procs.next){
		p = l->i;
		assert(p);
		p->task = nil;
		delist(&t->procs, p);
	}
	while (p = t->runq.head){
		/* put runnable procs on regular run queue */
		t->runq.head = p->rnext;


@@ 652,27 621,18 @@ removetask(Task *t)
	}
	t->runq.tail = nil;
	assert(t->runq.n == 0);
	for (s = 0; s < nelem(t->res); s++){
		if (t->res[s] == nil)
			continue;
		r = t->res[s];
		for (i = 0; i < nelem(r->tasks); i++)
			if (r->name && r->tasks[i] == t){
				r->tasks[i] = nil;
				if (--r->ntasks == 0){
					/* resource became unused, delete it */
					free(r->name);
					r->name = nil;
					nresources--;
				}
			}
	}
	if(t->user){
		free(t->user);
		t->user = nil;
	while (l = t->res.next){
		r = l->i;
		if (delist(&r->tasks, t))
			taskfree(t);
		if (delist(&t->res, r))
			resourcefree(r);
	}
	free(t->user);
	t->user = nil;
	t->state = EdfUnused;
	qunlock(t);
	if (delist(&tasks, t))
		taskfree(t);
}

static long


@@ 680,8 640,7 @@ devrtwrite(Chan *c, void *va, long n, vlong)
{
	char *a, *v, *e, *args[16], *rargs[16], buf[512];
	int i, j, s, nargs, nrargs, add;
	Resource **rp, *r;
	Proc **pp;
	Resource *r;
	Task *t;
	Ticks ticks;
	Time time;


@@ 700,9 659,14 @@ devrtwrite(Chan *c, void *va, long n, vlong)
			error(Enonexist);
		s = (ulong)c->qid.path & (Qistask - 1);
	common:
		if (s < 0 || s >= Maxtasks || tasks[s].state == EdfUnused)
		qlock(&edfschedlock);
		if (waserror()){
			qunlock(&edfschedlock);
			nexterror();
		}
		t = findtask(s);
		if (t == nil)
			error(Enonexist);
		t = tasks + s;
		if(n >= sizeof(buf))
			n = sizeof(buf)-1;
		strncpy(buf, a, n);


@@ 788,22 752,32 @@ devrtwrite(Chan *c, void *va, long n, vlong)
					error("resources: value missing");
				edf->edfexpel(t);
				if (add == 0){
					for (rp = t->res; rp < t->res + nelem(t->res); rp++)
						if (*rp){
							tasktoresource(*rp, t, 0);
							resourcetotask(t, *rp, 0);
						}
					assert(t->nres == 0);
					List *l;

					while (l = t->res.next) {
						r = l->i;
						assert(r);
						if (delist(&r->tasks, t))
							taskfree(t);
						if (delist(&t->res, r))
							resourcefree(r);
					}
					assert(t->res.n == 0);
					add = 1;
				}
				nrargs = tokenize(v, rargs, nelem(rargs));
				for (j = 0; j < nrargs; j++)
					if (r = resource(rargs[j], add)){
						if (e = tasktoresource(r, t, add))
							error(e);
						if (e = resourcetotask(t, r, add)){
							tasktoresource(r, t, -1);
							error(e);
						if (add > 0){
							if (enlist(&r->tasks, t))
								incref(t);
							if (enlist(&t->res, r))
								incref(r);
						}else{
							if (delist(&r->tasks, t))
								taskfree(t);
							if (delist(&t->res, r))
								resourcefree(r);
						}
					}else
						error("resource not found");


@@ 814,10 788,14 @@ devrtwrite(Chan *c, void *va, long n, vlong)
					edf->edfexpel(t);
				}
				if (add == 0){
					for (pp = t->procs; pp < t->procs + nelem(t->procs); pp++)
						if (*pp){
							proctotask(t, *pp, -1);
						}
					List *l;

					while (l = t->procs.next){
						p = l->i;
						assert(p->task == t);
						delist(&t->procs, p);
						p->task = nil;
					}
					add = 1;
				}
				nrargs = tokenize(v, rargs, nelem(rargs));


@@ 833,8 811,15 @@ devrtwrite(Chan *c, void *va, long n, vlong)
							error("no such process");
						p = proctab(s);
					}
					if (e = proctotask(t, p, add))
						error(e);
					if(p->task && p->task != t)
						error("proc belongs to another task");
					if (add > 0){
						enlist(&t->procs, p);
						p->task = t;
					}else{
						delist(&t->procs, p);
						p->task = nil;
					}
				}
			}else if (strcmp(a, "admit") == 0){
				if (e = edf->edfadmit(t))


@@ 843,6 828,8 @@ devrtwrite(Chan *c, void *va, long n, vlong)
				edf->edfexpel(t);
			}else if (strcmp(a, "remove") == 0){
				removetask(t);
				poperror();
				qunlock(&edfschedlock);
				return n;	/* Ignore any subsequent commands */
			}else if (strcmp(a, "verbose") == 0){
				if (t->flags & Verbose)


@@ 861,12 848,16 @@ devrtwrite(Chan *c, void *va, long n, vlong)
			}else if (strcmp(a, "yield") == 0){
				if (edf->isedf(up) && up->task == t){
					edf->edfdeadline(up);	/* schedule next release */
					qunlock(&edfschedlock);
					sched();
					qlock(&edfschedlock);
				}else
					error("yield outside task");
			}else
				error("unrecognized command");
		}
		poperror();
		qunlock(&edfschedlock);
	}
	return n;
}


@@ 880,10 871,17 @@ devrtremove(Chan *c)
	if ((c->qid.path & Qistask) == 0)
		error(Eperm);
	s = (ulong)c->qid.path & (Qistask - 1);
	t = tasks + s;
	if (s < 0 || s >= Maxtasks || t->state == EdfUnused)
	t = findtask(s);
	if (t == nil)
		error(Enonexist);
	qlock(&edfschedlock);
	if (waserror()){
		qunlock(&edfschedlock);
		nexterror();
	}
	removetask(t);
	poperror();
	qunlock(&edfschedlock);
}

Dev realtimedevtab = {


@@ 977,3 975,58 @@ parsetime(Time *rt, char *s)
	*rt = ticks;
	return nil;
}

int
putlist(Head *h, List *l)
{
	l->next = h->next;
	h->next = l;
	h->n++;
	return 1;
}

int
enlist(Head *h, void *i)
{
	List *l;

	for (l = h->next; l; l = l->next)
		if (l->i == i){
			/* already on the list */
			return 0;
		}
	l = malloc(sizeof(List));
	if (l == nil)
		panic("malloc in enlist");
	l->i = i;
	l->next = h->next;
	h->next = l;
	h->n++;
	return 1;
}

int
delist(Head *h, void *i)
{
	List *l, **p;

	for (p = &h->next; l = *p; p = &l->next)
		if (l->i == i){
			*p = l->next;
			free(l);
			h->n--;
			return 1;
		}
	return 0;
}

void *
findlist(Head *h, void *i)
{
	List *l;

	for (l = h->next; l; l = l->next)
		if (l->i == i)
			return i;
	return nil;
}

M port/edf.c => port/edf.c +63 -47
@@ 32,13 32,12 @@ static Timer	releasetimer[MAXMACH];		/* Time of next release */
static int		initialized;
static uvlong	fasthz;	
static Ticks	now;
/* Edfschedlock protects modification of sched params, including resources */
QLock		edfschedlock;
Lock			edflock;

Task			tasks[Maxtasks];
int			ntasks;
Resource		resources[Maxresources];
int			nresources;
Head		tasks;
Head		resources;
int			edfstateupdate;
int			misseddeadlines;



@@ 301,6 300,7 @@ edfadmit(Task *t)
{
	char *err;

	/* Called with edfschedlock held */
	if (t->state != EdfExpelled)
		return "task state";	/* should never happen */



@@ 316,12 316,11 @@ edfadmit(Task *t)
	if (t->C > t->D)
		return "C > D";

	qlock(&edfschedlock);
	if (err = edftestschedulability(t)){
		qunlock(&edfschedlock);
		return err;
	}
	ilock(&edflock);
	qunlock(&edfschedlock);
	DPRINT("%d edfadmit, %s, %d\n", m->machno, edfstatename[t->state], t->runq.n);
	now = fastticks(nil);



@@ 358,7 357,7 @@ edfadmit(Task *t)
		}
	}
	iunlock(&edflock);
	qunlock(&edfschedlock);
	qlock(&edfschedlock);
	return nil;
}



@@ 367,7 366,7 @@ edfexpel(Task *t)
{
	Task *tt;

	qlock(&edfschedlock);
	/* Called with edfschedlock held */
	ilock(&edflock);
	DPRINT("%d edfexpel, %s, %d\n", m->machno, edfstatename[t->state], t->runq.n);
	now = fastticks(nil);


@@ 376,7 375,6 @@ edfexpel(Task *t)
	case EdfExpelled:
		/* That was easy */
		iunlock(&edflock);
		qunlock(&edfschedlock);
		return;
	case EdfAdmitted:
	case EdfIdle:


@@ 408,7 406,6 @@ edfexpel(Task *t)
	if(devrt) devrt(t, now, SExpel);
	setdelta();
	iunlock(&edflock);
	qunlock(&edfschedlock);
	return;
}



@@ 497,7 494,6 @@ static void
edfbury(Proc *p)
{
	Task *t;
	Proc **pp;

	DPRINT("%d edfbury\n", m->machno);
	ilock(&edflock);


@@ 509,16 505,12 @@ edfbury(Proc *p)
		return;
	}
	assert(edfstack[m->machno].head == t);
	for (pp = t->procs; pp < t->procs + nelem(t->procs); pp++)
		if (*pp == p){
			t->nproc--;
			*pp = nil;
		}
	delist(&t->procs, p);
	if (t->runq.head == nil){
		edfpop();
		t->state = EdfBlocked;
	}
	if (t->nproc == 0){
	if (t->procs.n == 0){
		assert(t->runq.head == nil);
		t->state = EdfIdle;
	}


@@ 564,7 556,7 @@ edfresched(Task *t)
	Task *xt;

	DPRINT("%d edfresched, %s, %d\n", m->machno, edfstatename[t->state], t->runq.n);
	if (t->nproc == 0){
	if (t->procs.n == 0){
		/* No member processes */
		if (t->state > EdfIdle){
			t->state = EdfIdle;


@@ 788,48 780,66 @@ runt:
static void
setdelta(void)
{
	Resource *r, **rr;
	Task **tt, *t;
	Resource *r;
	Task *t;
	List *lr, *lt;

	for (r = resources; r < resources + nelem(resources); r++){
		if (r->name == nil)
			continue;
	for (lr = resources.next; lr; lr = lr->next){
		r = lr->i;
		assert(r);
		r->Delta = ~0LL;
		for (tt = r->tasks; tt < r->tasks + nelem(r->tasks); tt++)
			if (*tt && (*tt)->D < r->Delta)
				r->Delta = (*tt)->D;
		for (lt = r->tasks.next; lt; lt = lt->next){
			t = lt->i;
			assert(t);
			if (t->D < r->Delta)
				r->Delta = t->D;
		}
	}
	for (t = tasks; t < tasks + nelem(tasks); t++){
	for (lt = tasks.next; lt ; lt = lt->next){
		t = lt->i;
		assert(t);
		if (t->state < EdfIdle)
			continue;
		t->Delta = t->D;
		for (rr = t->res; rr < t->res + nelem(t->res); rr++)
			if (*rr && (*rr)->Delta < t->Delta)
				t->Delta = (*rr)->Delta;
		for (lr = t->res.next; lr; lr = lr->next){
			r = lr->i;
			assert(r);
			if (r->Delta < t->Delta)
				t->Delta = r->Delta;
		}
	}
}

static void
testdelta(Task *thetask)
{
	Resource *r, **rr;
	Task **tt, *t;
	Resource *r;
	Task *t;
	List *lr, *lt;

	for (r = resources; r < resources + nelem(resources); r++){
		if (r->name == nil)
			continue;
	for (lr = resources.next; lr; lr = lr->next){
		r = lr->i;
		assert(r);
		r->testDelta = ~0ULL;
		for (tt = r->tasks; tt < r->tasks + nelem(r->tasks); tt++)
			if (*tt && (*tt)->D < r->testDelta)
				r->testDelta = (*tt)->D;
		for (lt = r->tasks.next; lt; lt = lt->next){
			t = lt->i;
			assert(t);
			if (t->D < r->testDelta)
				r->testDelta = t->D;
		}
	}
	for (t = tasks; t < tasks + nelem(tasks); t++){
	for (lt = tasks.next; lt ; lt = lt->next){
		t = lt->i;
		assert(t);
		if (t->state <= EdfExpelled && t != thetask)
			continue;
		t->testDelta = t->D;
		for (rr = t->res; rr < t->res + nelem(t->res); rr++)
			if (*rr && (*rr)->testDelta < t->testDelta)
				t->testDelta = (*rr)->testDelta;
		for (lr = t->res.next; lr; lr = lr->next){
			r = lr->i;
			assert(r);
			if (r->testDelta < t->testDelta)
				t->testDelta = r->testDelta;
		}
	}
}



@@ 838,9 848,12 @@ blockcost(Ticks ticks, Task *thetask)
{
	Task *t;
	Ticks Cb;
	List *lt;

	Cb = 0;
	for (t = tasks; t < tasks + Maxtasks; t++){
	for (lt = tasks.next; lt ; lt = lt->next){
		t = lt->i;
		assert(t);
		if (t->state <= EdfExpelled && t != thetask)
			continue;
		if (t->testDelta <= ticks && ticks < t->D && Cb < t->C)


@@ 881,19 894,22 @@ edftestschedulability(Task *thetask)
	Task *t;
	Ticks H, G, Cb, ticks;
	int steps;
	List *l;

	/* initialize */
	testdelta(thetask);
	if (thetask && (thetask->flags & Verbose))
		pprint("schedulability test\n");
	qschedulability = nil;
	for (t = tasks; t < tasks + Maxtasks; t++){
	for (l = tasks.next; l; l = l->next){
		t = l->i;
		assert(t);
		if (t->state <= EdfExpelled && t != thetask)
			continue;
		t->testtype = Release;
		t->testtime = 0;
		if (thetask && (thetask->flags & Verbose))
			pprint("\tInit: enqueue task %lud\n", t - tasks);
			pprint("\tInit: enqueue task %lud\n", t->taskno);
		testenq(t);
	}
	H=0;


@@ 908,7 924,7 @@ edftestschedulability(Task *thetask)
			Cb = blockcost(ticks, thetask);
			if (thetask && (thetask->flags & Verbose))
				pprint("\tStep %3d, Ticks %T, task %lud, deadline, H += %T → %T, Cb = %T\n",
					steps, ticks2time(ticks), t - tasks,
					steps, ticks2time(ticks), t->taskno,
					ticks2time(t->C), ticks2time(H), ticks2time(Cb));
			if (H+Cb>ticks)
				return "not schedulable";


@@ 919,7 935,7 @@ edftestschedulability(Task *thetask)
		case Release:
			if (thetask && (thetask->flags & Verbose))
				pprint("\tStep %3d, Ticks %T, task %lud, release, G  %T, C%T\n",
					steps, ticks2time(ticks), t - tasks,
					steps, ticks2time(ticks), t->taskno,
					ticks2time(t->C), ticks2time(G));
			if(ticks && G <= ticks)
				return nil;

M port/edf.h => port/edf.h +30 -10
@@ 18,6 18,8 @@ typedef struct Task			Task;
typedef struct Resource		Resource;
typedef struct Edf			Edf;
typedef struct Taskq			Taskq;
typedef struct List			List;
typedef struct Head			Head;

enum Edfstate {
	EdfUnused,		/* task structure not in use */


@@ 35,6 37,16 @@ enum Edfstate {
};
typedef enum Edfstate	Edfstate;

struct List {
	List	*	next;	/* next in list */
	void	*	i;		/* item in list */
};

struct Head {
	List	*next;	/* First item in list */
	int	n;		/* number of items in list */
};

struct Edf {
	/* time intervals */
	Ticks	D;		/* Deadline */


@@ 63,13 75,13 @@ struct Edf {

struct Task {
	QLock;
	Ref;					/* ref count for farbage collection */
	int		taskno;		/* task number in Qid  */
	Edf;
	Ticks	scheduled;
	Schedq	runq;		/* Queue of runnable member procs */
	Proc *	procs[Nproc];	/* List of member procs; may contain holes */
	int		nproc;		/* number of them */
	Resource*	res[Nres];		/* List of resources; may contain holes */
	int		nres;			/* number of them */
	Head	procs;		/* List of member procs */
	Head	res;			/* List of resources */
	char		*user;		/* mallocated */
	Dirtab	dir;
	int		flags;		/* e.g., Verbose */


@@ 85,18 97,23 @@ struct Taskq

struct Resource
{
	Ref;
	char	*	name;
	Task *	tasks[Ntask];	/* may contain holes */
	int		ntasks;
	Head	tasks;
	Ticks	Delta;
	/* for schedulability testing */
	Ticks	testDelta;
};

extern Lock		edftestlock;	/* for atomic admitting/expelling */
extern Task		tasks[Maxtasks];	/* may contain holes */
extern int			ntasks;
extern Resource	resources[Maxresources];	/* may contain holes */
struct ResourceItem {
	List;			/* links and identifies the resource (must be first) */
	Ticks	C;	/* cost */
	Head	h;	/* sub resource items */
};

extern QLock		edfschedlock;
extern Head		tasks;
extern Head		resources;
extern int			nresources;
extern Lock		edflock;
extern Taskq		qwaitrelease;


@@ 112,3 129,6 @@ extern char *		edfstatename[];

Time		ticks2time(Ticks);
Ticks	time2ticks(Time);
int		putlist(Head*, List*);
int		enlist(Head*, void*);
int		delist(Head*, void*);