~kris/9p

9hist

d61471a38e31bc1bfcacf62059a52bbdf5ae5fec — David du Colombier 24 years ago 164113f
Plan 9 from Bell Labs 2002-03-16
5 files changed, 1086 insertions(+), 159 deletions(-)

A port/devrealtime.c
A port/devrealtime.h
M port/devsd.c
M port/edf.c
M port/edf.h
A port/devrealtime.c => port/devrealtime.c +880 -0
@@ 0,0 1,880 @@
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#include "ureg.h"
#include "../port/error.h"
#include	"../port/devrealtime.h"
#include "../port/edf.h"

#pragma	varargck	type	"T"		vlong

/* debugging */
extern int			edfprint;
extern char		tabs[16];
extern int			ind;

static Schedevent *events;
static int nevents, revent, wevent;
static Rendez eventr;
static QLock elock;
static Ref logopens;
static Ref debugopens;
static uvlong fasthz;	

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

enum {
	Qistask = 0x10000,
	Qdir = 0,
	Qrealtime,
	Qclone,
	Qdebug,
	Qlog,
	Qnblog,
	Qresrc,
	Qtask,
	Qtime,

	Nevents = 10000,
	Clockshift = 17,		// Good to about 10GHz clock and max. 5(s)
};

Dirtab schedrootdir[]={
	".",			{Qdir, 0, QTDIR},		0,	DMDIR|0555,
	"realtime",	{Qrealtime, 0, QTDIR},	0,	DMDIR|0555,
};

Dirtab scheddir[]={
	".",			{Qrealtime, 0, QTDIR},	0,	DMDIR|0555,
	"clone",		{Qclone},				0,	0666,
	"debug",		{Qdebug},				0,	0444,
	"log",		{Qlog},				0,	0444,	/* one open only */
	"nblog",		{Qnblog},				0,	0444,	/* nonblocking version of log */
	"resources",	{Qresrc},				0,	0444,
	"task",		{Qtask, 0, QTDIR},		0,	DMDIR|0555,
	"time",		{Qtime},				0,	0444,
};

static char*
dumptask(char *p, char *e, Task *t, Ticks now)
{
	vlong n;
	char c;

	p = seprint(p, e, "{%s, D%U, Δ%U,T%U, C%U, S%U",
		edf_statename[t->state], t->D, t->Δ, t->T, t->C, t->S);
	n = t->r - now;
	if (n >= 0)
		c = ' ';
	else {
		n = -n;
		c = '-';
	}
	p = seprint(p, e, ", r%c%U", c, (uvlong)n);
	n = t->d - now;
	if (n >= 0)
		c = ' ';
	else {
		n = -n;
		c = '-';
	}
	p = seprint(p, e, ", d%c%U", c, (uvlong)n);
	n = t->t - now;
	if (n >= 0)
		c = ' ';
	else {
		n = -n;
		c = '-';
	}
	p = seprint(p, e, ", t%c%U}", c, (uvlong)n);
	return p;
}

static char*
dumpq(char *p, char *e, Taskq *q, Ticks now)
{
	Task *t;

	t = q->head;
	for(;;){
		if (t == nil)
			return seprint(p, e, "\n");
		p = dumptask(p, e, t, now);
		t = t->rnext;
		if (t)
			seprint(p, e, ", ");
	}
	return nil;
}

/*
 * the zeroth element of the table MUST be the directory itself for ..
*/
int
schedgen(Chan *c, char*, Dirtab *, int, int i, Dir *dp)
{
	Dirtab *tab;
	int ntab;
	char *owner;
	ulong taskindex;
	Qid qid;

	if((ulong)c->qid.path & Qistask){
		taskindex = (ulong)c->qid.path & (Qistask-1);
		if (taskindex >= Maxtasks || tasks[taskindex].state == EdfUnused)
			return -1;
	}else if((ulong)c->qid.path == Qtask){
		taskindex = i;
		for (i = 0; i < Maxtasks; i++)
			if (tasks[i].state != EdfUnused && taskindex-- == 0)
				break;
		if (i == Maxtasks)
			return -1;
	}else {
		if((ulong)c->qid.path == Qdir){
			tab = schedrootdir;
			ntab = nelem(schedrootdir);
		}else{
			tab = scheddir;
			ntab = nelem(scheddir);
		}
		if(i != DEVDOTDOT){
			/* skip over the first element, that for . itself */
			i++;
			if(i >= ntab)
				return -1;
			tab += i;
		}
		devdir(c, tab->qid, tab->name, tab->length, eve, tab->perm, dp);
		return 1;
	}
	if(i == DEVDOTDOT){
		mkqid(&qid, Qtask, 0, QTDIR);
		devdir(c, qid, ".", 0, eve, 0555, dp);
		return 1;
	}
	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);
	return 1;
}

static void
_devrt(Task *t, Ticks t1, SEvent etype)
{
	if (logopens.ref == 0 || nevents == Nevents)
		return;

	if(edfprint)iprint("%.*sstate %s\n", ind, tabs, edf_statename[etype]);
	events[wevent].tid = t - tasks;
	events[wevent].ts = 0;
	if (t1)
		events[wevent].ts = ticks2time(t1);
	else
		events[wevent].ts = 0;
	events[wevent].etype = etype;

	if (!canqlock(&elock)) 
		return;

	wevent = (wevent + 1) % Nevents;
	if (nevents < Nevents)
		nevents++;
	else
		revent = (revent + 1) % Nevents;

	if(edfprint)iprint("%.*swakesched\n", ind, tabs);
	/* To avoid circular wakeup when used in combination with 
	 * EDF scheduling.
	 */
	if (eventr.p && eventr.p->state == Wakeme)
		wakeup(&eventr);

	qunlock(&elock);
}

static void
devrtinit(void)
{
	fmtinstall('T', timeconv);
	fmtinstall('U', timeconv);
	fastticks(&fasthz);
	devrt = _devrt;
	events = (Schedevent *)malloc(sizeof(Schedevent) * Nevents);
	assert(events);
	nevents = revent = wevent = 0;
}

static Chan *
devrtattach(char *param)
{
	return devattach(L'⌛', param);
}

static Walkqid *
devrtwalk(Chan *c, Chan *nc, char **name, int nname)
{
	return devwalk(c, nc, name, nname, nil, 0, schedgen);
}

static int
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)
{
	Task *t;

	switch ((ulong)c->qid.path){
	case Qlog:
	case Qnblog:
		if (mode != OREAD) 
			error(Eperm);
		incref(&logopens);
		if (logopens.ref > 1){
			decref(&logopens);
			error("already open");
		}
		break;
	case Qdebug:
		if (mode != OREAD) 
			error(Eperm);
		incref(&debugopens);
		if (debugopens.ref > 1){
			decref(&debugopens);
			error("already open");
		}
		break;
	case Qclone:
		if (mode == OREAD) 
			error(Eperm);
		edf_init();
		/* 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");
		break;
	}
//	print("open %lux, mode %o\n", (ulong)c->qid.path, mode);
	return devopen(c, mode, nil, 0, schedgen);
}

static void
devrtclose(Chan *c)
{
	switch ((ulong)c->qid.path){
	case Qlog:
	case Qnblog:
		nevents = revent = wevent = 0;
		decref(&logopens);
		break;
	case Qdebug:
		nevents = revent = wevent = 0;
		decref(&debugopens);
		break;
	}
}

static int
eventsavailable(void *)
{
	return nevents > 0;
}

static long
devrtread(Chan *c, void *v, long n, vlong offs)
{
	char *p, *e;
	char buf[1024];
	long n0;
	int navail;
	Task *t;
	int s, i, fst;
	Ticks now;

	n0 = n;
//	print("schedread 0x%lux\n", (ulong)c->qid.path);
	buf[0] = '\0';
	switch((ulong)c->qid.path){
	case Qdir:
		return devdirread(c, v, n, schedrootdir, nelem(schedrootdir), devgen);

	case Qrealtime:
		return devdirread(c, v, n, scheddir, nelem(scheddir), devgen);

	case Qtask:
		return devdirread(c, v, n, nil, 0, schedgen);

	case Qtime:
		if (n < sizeof(Ticks))
			error(Ebadarg);
		now = fastticks(nil);
 		memmove(v, &now, sizeof(Ticks));
		n -= sizeof(Ticks);
		if (n >= sizeof(Ticks)){
			memmove((char*)v + sizeof(Time), &fasthz, sizeof(Ticks));
			n -= sizeof(Ticks);
		}
		break;

	case Qnblog:
		if (eventsavailable(nil))
			goto getevnt;
		break;

	case Qlog:

		while (!eventsavailable(nil))
			sleep(&eventr, eventsavailable, nil);
	getevnt:

		p = (char *)v;

		navail = nevents;
		if (navail > n / sizeof(Schedevent))
			navail = n / sizeof(Schedevent);
		n -= navail * sizeof(Schedevent);

		qlock(&elock);
		while (navail > 0) {
			int ncopy;

			ncopy = (revent + navail > Nevents)? Nevents - revent: navail;
			memmove(p, &events[revent], ncopy * sizeof(Schedevent));
			revent = (revent+ ncopy) % Nevents;
			p += ncopy * sizeof(Schedevent);
			navail -= ncopy;
			nevents -= ncopy;
		}
		qunlock(&elock);
		break;
	case Qresrc:
		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){
				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++;
					}
				p = seprint(p, e, "'");
			}
			if (resources[i].Δ)
				p = seprint(p, e, " Δ=%T", ticks2time(resources[i].Δ));
			else if (resources[i].testΔ)
				p = seprint(p, e, " testΔ=%T", ticks2time(resources[i].testΔ));
			p = seprint(p, e, "\n");
		}
		return readstr(offs, v, n, buf);
		break;
	case Qdebug:
		p = buf;
		e = p + sizeof(buf);
		ilock(&edflock);
		now = fastticks(nil);
		for (i = 0; i < conf.nmach; i++){
			p = seprint(p, e, "edfstack[%d]\n", i);
			p = dumpq(p, e, edfstack + i, now);
		}
		p = seprint(p, e, "qreleased\n");
		p = dumpq(p, e, &qreleased, now);
		p = seprint(p, e, "qwaitrelease\n");
		p = dumpq(p, e, &qwaitrelease, now);
		p = seprint(p, e, "qextratime\n");
		dumpq(p, e, &qextratime, now);
		iunlock(&edflock);
		return readstr(offs, v, n, buf);
		break;
	case Qclone:
		s = c->qid.vers;
		goto common;
	default:
		if ((c->qid.path & Qistask) == 0)
			error(Enonexist);
		s = (ulong)c->qid.path & (Qistask - 1);
	common:
		if (s < 0 || s >= Maxtasks || tasks[s].state == EdfUnused)
			error(Enonexist);
		t = tasks + s;
		p = buf;
		e = p + sizeof(buf);
		p = seprint(p, e, "task=%d", s);
		p = seprint(p, e, " state=%s", edf_statename[t->state]);
		if (t->T)
			p = seprint(p, e, " T=%T", ticks2time(t->T));
		if (t->D)
			p = seprint(p, e, " D=%T", ticks2time(t->D));
		if (t->C)
			p = seprint(p, e, " C=%T", ticks2time(t->C));
		if (t->Δ)
			p = seprint(p, e, " Δ=%T", ticks2time(t->Δ));
		else if (t->testΔ)
			p = seprint(p, e, " testΔ=%T", ticks2time(t->testΔ));
		if (t->nres){
			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++;
				}
			p = seprint(p, e, "'");
		}
		if (t->nproc){
			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++;
				}
			p = seprint(p, e, "'");
		}
		seprint(p, e, "\n");
		return readstr(offs, v, n, buf);
	}
	return n0 - n;
}

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)
		return nil;
	if (r == nil)
		error("too many resources");
	kstrdup(&r->name, name);
	for (t = r->tasks; t < r->tasks + nelem(r->tasks); t++)
		*t = nil;
	r->ntasks = 0;
	nresources++;
	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)
{
	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;
}

static long
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;
	Task *t;
	Time time;
	long pid;
	Proc *p;

	a = va;
	if (c->mode == OREAD)
		error(Eperm);
	switch((ulong)c->qid.path){
	case Qclone:
		s = c->qid.vers;
		goto common;
	default:
		if ((c->qid.path & Qistask) == 0)
			error(Enonexist);
		s = (ulong)c->qid.path & (Qistask - 1);
	common:
		if (s < 0 || s >= Maxtasks || tasks[s].state == EdfUnused)
			error(Enonexist);
		t = tasks + s;
		if(n >= sizeof(buf))
			n = sizeof(buf)-1;
		strncpy(buf, a, n);
		buf[n] = 0;
		nargs = tokenize(buf, args, nelem(args));
		for (i = 0; i < nargs; i++){
			a = args[i];
			add  = 0;
			if (v = strchr(a, '=')){
				if (v != a && v[-1] == '+'){
					add = 1;
					v[-1] = '\0';
				} else if (v != a && v[-1] == '-'){
					add = -1;
					v[-1] = '\0';
				}
				*v++ = '\0';
			}
			if (strcmp(a, "T") == 0){
				if (e=parsetime(&time, v))
					error(e);
				edf_expel(t);
				t->T = time2ticks(time);
			}else if (strcmp(a, "D") == 0){
				if (e=parsetime(&time, v))
					error(e);
				edf_expel(t);
				t->D = time2ticks(time);
			}else if (strcmp(a, "C") == 0){
				if (e=parsetime(&time, v))
					error(e);
				edf_expel(t);
				t->C = time2ticks(time);
			}else if (strcmp(a, "resources") == 0){
				if (v == nil)
					error("resources: value missing");
				edf_expel(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);
					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);
						}
					}else
						error("resource not found");
			}else if (strcmp(a, "procs") == 0){
				if (v == nil)
					error("procs: value missing");
				if (add <= 0)
					edf_expel(t);
				if (add == 0){
					for (pp = t->procs; pp < t->procs + nelem(t->procs); pp++)
						if (*pp)
							proctotask(t, *pp, -1);
					add = 1;
				}
				nrargs = tokenize(v, rargs, nelem(rargs));
				for (j = 0; j < nrargs; j++){
					pid = atoi(rargs[j]);
					if (pid <= 0)
						error("bad process number");
					s = procindex(pid);
					if(s < 0)
						error("no such process");
					p = proctab(s);
					if (e = proctotask(t, p, add))
						error(e);
				}
			}else if (strcmp(a, "admit") == 0){
				/* Do the admission test */
				if (e = edf_admit(t))
					error(e);
			}else if (strcmp(a, "verbose") == 0){
				/* Do the admission test */
				if (t->flags & Verbose)
					t->flags &= ~Verbose;
				else
					t->flags |= Verbose;
			}else if (strcmp(a, "useblocking") == 0){
				/* Do the admission test */
				if (t->flags & Useblocking)
					t->flags &= ~Useblocking;
				else
					t->flags |= Useblocking;
			}else if (strcmp(a, "yield") == 0){
				if (isedf(up) && up->task == t){
					edf_deadline(up);	/* schedule next release */
					sched();
				}else
					error("yield outside task");
			}else
				error("unrecognized command");
		}
	}
	return n;
}

static void
devrtremove(Chan *c)
{
	int s, i;
	Task *t;
	Proc *p, **pp;
	Resource *r;

	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)
		error(Enonexist);
	qlock(t);
	edf_expel(t);
	for (pp = t->procs; pp < t->procs + nelem(t->procs); pp++)
		if (p = *pp)
			p->task = nil;
	while (p = t->runq.head){
		/* put runnable procs on regular run queue */
		t->runq.head = p->rnext;
		ready(p);
		t->runq.n--;
	}
	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;
	}
	t->state = EdfUnused;
	qunlock(t);
}

Dev realtimedevtab = {
	L'⌛',
	"scheduler",

	devreset,
	devrtinit,
	devshutdown,
	devrtattach,
	devrtwalk,
	devrtstat,
	devrtopen,
	devcreate,
	devrtclose,
	devrtread,
	devbread,
	devrtwrite,
	devbwrite,
	devrtremove,
	devwstat,
};

static int
timeconv(Fmt *f)
{
	char buf[128], *sign;
	Time t;
	Ticks ticks;

	buf[0] = 0;
	switch(f->r) {
	case 'U':
		ticks = va_arg(f->args, Ticks);
		t = ticks2time(ticks);
		break;
	case 'T':		// Time in nanoseconds
		t = va_arg(f->args, Time);
		break;
	default:
		return fmtstrcpy(f, "(timeconv)");
	}
	if (t < 0) {
		sign = "-";
		t = -t;
	}
	else
		sign = "";
	if (t > Onesecond)
		sprint(buf, "%s%d.%.3ds", sign, (int)(t / Onesecond), (int)(t % Onesecond)/1000000);
	else if (t > Onemillisecond)
		sprint(buf, "%s%d.%.3dms", sign, (int)(t / Onemillisecond), (int)(t % Onemillisecond)/1000);
	else if (t > Onemicrosecond)
		sprint(buf, "%s%d.%.3dµs", sign, (int)(t / Onemicrosecond), (int)(t % Onemicrosecond));
	else
		sprint(buf, "%s%dns", sign, (int)t);
	return fmtstrcpy(f, buf);
}

static char *
parsetime(Time *rt, char *s)
{
	uvlong ticks;
	ulong l;
	char *e, *p;
	static int p10[] = {100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1};

	if (s == nil)
		return("missing value");
	ticks=strtoul(s, &e, 10);
	if (*e == '.'){
		p = e+1;
		l = strtoul(p, &e, 10);
		if(e-p > nelem(p10))
			return "too many digits after decimal point";
		if(e-p == 0)
			return "ill-formed number";
		l *= p10[e-p-1];
	}else
		l = 0;
	if (*e == '\0' || strcmp(e, "s") == 0){
		ticks = 1000000000 * ticks + l;
	}else if (strcmp(e, "ms") == 0){
		ticks = 1000000 * ticks + l/1000;
	}else if (strcmp(e, "µs") == 0 || strcmp(e, "us") == 0){
		ticks = 1000 * ticks + l/1000000;
	}else if (strcmp(e, "ns") != 0)
		return "unrecognized unit";
	*rt = ticks;
	return nil;
}

A port/devrealtime.h => port/devrealtime.h +27 -0
@@ 0,0 1,27 @@
#define Onemicrosecond			((Time)1000ULL)
#define Onemillisecond			((Time)1000*Onemicrosecond)
#define Onesecond				((Time)1000*Onemillisecond)

typedef vlong	Time;
typedef struct Schedevent Schedevent;

enum SEvent {
	SAdmit,		/* new proc arrives*/
	SRelease,		/* released, but not yet scheduled (on qreleased) */
	SRun,		/* one of this task's procs started running */
	SPreempt,		/* the running proc was preempted */
	SBlock,		/* none of the procs are runnable as a result of sleeping */
	SResume,		/* one or more procs became runnable */
	SDeadline,	/* proc's deadline */
	SYield,		/* proc reached voluntary early deadline */
	SSlice,		/* slice exhausted */
	SExpel,		/* proc is gone */
};
typedef enum SEvent	SEvent;

struct Schedevent {
	ulong	tid;		// Task ID
	Time		ts;		// Event time
	SEvent	etype;	// Event type
};


M port/devsd.c => port/devsd.c +113 -108
@@ 16,13 16,13 @@ extern Dev sddevtab;
extern SDifc* sdifc[];

typedef struct {
	SDev 	*dt_dev;
	int		dt_nunits;		/* num units in dev */
	SDev*	dt_dev;
	int	dt_nunits;		/* num units in dev */
} dev_t;

static dev_t 	*devs;		/* all devices */
static QLock	devslock;		/* insertion and removal of devices */
static int		ndevs;		/* total number of devices in the system */
static dev_t* devs;			/* all devices */
static QLock devslock;			/* insertion and removal of devices */
static int ndevs;			/* total number of devices in the system */

enum {
	Rawcmd,


@@ 68,7 68,7 @@ enum {
#define TYPE(q)		((((ulong)(q).path)>>TypeSHIFT) & TypeMASK)
#define PART(q)		((((ulong)(q).path)>>PartSHIFT) & PartMASK)
#define UNIT(q)		((((ulong)(q).path)>>UnitSHIFT) & UnitMASK)
#define DEV(q)			((((ulong)(q).path)>>DevSHIFT) & DevMASK)
#define DEV(q)		((((ulong)(q).path)>>DevSHIFT) & DevMASK)
#define QID(d,u, p, t)	(((d)<<DevSHIFT)|((u)<<UnitSHIFT)|\
					 ((p)<<PartSHIFT)|((t)<<TypeSHIFT))



@@ 221,20 221,20 @@ sdinitpart(SDunit* unit)
	return 1;
}

static SDev *
static SDev*
sdgetdev(int idno)
{
	SDev *sdev;
	int i;

	qlock(&devslock);
	for (i = 0; i != ndevs; i++)
	for(i = 0; i != ndevs; i++)
		if (devs[i].dt_dev->idno == idno)
			break;
	
	if (i == ndevs)
	if(i == ndevs)
		sdev = nil;
	else {
	else{
		sdev = devs[i].dt_dev;
		incref(&sdev->r);
	}


@@ 255,7 255,7 @@ sdgetunit(SDev* sdev, int subno)
	 * successfully accessed.
	 */
	qlock(&sdev->unitlock);
	if (subno > sdev->nunit) {
	if(subno > sdev->nunit){
		qunlock(&sdev->unitlock);
		return nil;
	}


@@ 323,14 323,14 @@ sdreset(void)
			tail->next = sdev;
		else
			sdlist = sdev;
		for(tail = sdev; tail->next != nil; tail = tail->next) {
			tail->unit = (SDunit **)malloc(tail->nunit * sizeof(SDunit *));
			tail->unitflg = (int *)malloc(tail->nunit * sizeof(int));
		for(tail = sdev; tail->next != nil; tail = tail->next){
			tail->unit = (SDunit**)malloc(tail->nunit * sizeof(SDunit*));
			tail->unitflg = (int*)malloc(tail->nunit * sizeof(int));
			assert(tail->unit && tail->unitflg);
			ndevs++;
		}
		tail->unit = (SDunit **)malloc(tail->nunit * sizeof(SDunit *));
		tail->unitflg = (int *)malloc(tail->nunit * sizeof(int));
		tail->unit = (SDunit**)malloc(tail->nunit * sizeof(SDunit*));
		tail->unitflg = (int*)malloc(tail->nunit * sizeof(int));
		ndevs++;
	}
	


@@ 359,10 359,10 @@ sdreset(void)
	  * The IDs have been set, unlink the sdlist and copy the spec to
	  * the devtab.
	  */
	devs = (dev_t *)malloc(ndevs * sizeof(dev_t));
	devs = (dev_t*)malloc(ndevs * sizeof(dev_t));
	memset(devs, 0, ndevs * sizeof(dev_t));
	i = 0;
	while (sdlist != nil) {
	while(sdlist != nil){
		devs[i].dt_dev = sdlist;
		devs[i].dt_nunits = sdlist->nunit;
		sdlist = sdlist->next;


@@ 457,7 457,7 @@ sdgen(Chan* c, char*, Dirtab*, int, int s, Dir* dp)
	SDev *sdev;

	switch(TYPE(c->qid)){
	case Qtopdir: {
	case Qtopdir:
		if(s == DEVDOTDOT){
			mkqid(&q, QID(0, s, 0, Qtopdir), 0, QTDIR);
			sprint(up->genbuf, "#%C", sddevtab.dc);


@@ 465,24 465,24 @@ sdgen(Chan* c, char*, Dirtab*, int, int s, Dir* dp)
			return 1;
		}

		if (s == 0 || s == 1)
		if(s == 0 || s == 1)
			return sd1gen(c, s + Qtopbase, dp);
		s -= 2;

		qlock(&devslock);
		for (i = 0; i != ndevs; i++) {
		for(i = 0; i != ndevs; i++){
			if (s < devs[i].dt_nunits)
				break;
			s -= devs[i].dt_nunits;
		}
		
		if (i == ndevs) {
		if(i == ndevs){
			/* Run of the end of the list */
			qunlock(&devslock);
			return -1;
		}

		if ((sdev = devs[i].dt_dev) == nil) {
		if ((sdev = devs[i].dt_dev) == nil){
			qunlock(&devslock);
			return 0;
		}


@@ 491,7 491,7 @@ sdgen(Chan* c, char*, Dirtab*, int, int s, Dir* dp)
		qunlock(&devslock);

		if((unit = sdev->unit[s]) == nil)
			if((unit = sdgetunit(sdev, s)) == nil) {
			if((unit = sdgetunit(sdev, s)) == nil){
				decref(&sdev->r);
				return 0;
			}


@@ 502,7 502,6 @@ sdgen(Chan* c, char*, Dirtab*, int, int s, Dir* dp)
		devdir(c, q, unit->name, 0, unit->user, unit->perm, dp);
		decref(&sdev->r);
		return 1;
	}

	case Qunitdir:
		if(s == DEVDOTDOT){


@@ 512,7 511,7 @@ sdgen(Chan* c, char*, Dirtab*, int, int s, Dir* dp)
			return 1;
		}
		
		if ((sdev = sdgetdev(DEV(c->qid))) == nil) {
		if((sdev = sdgetdev(DEV(c->qid))) == nil){
			devdir(c, q, "unavailable", 0, eve, 0, dp);
			return 1;
		}


@@ 562,7 561,7 @@ sdgen(Chan* c, char*, Dirtab*, int, int s, Dir* dp)
	case Qraw:
	case Qctl:
	case Qpart:
		if ((sdev = sdgetdev(DEV(c->qid))) == nil) {
		if((sdev = sdgetdev(DEV(c->qid))) == nil){
			devdir(c, q, "unavailable", 0, eve, 0, dp);
			return 1;
		}


@@ 608,7 607,7 @@ sdattach(char* spec)
		if ((sdev = devs[i].dt_dev) != nil && sdev->idno == idno)
			break;

	if (i == ndevs || subno >= sdev->nunit || sdgetunit(sdev, subno) == nil) {
	if(i == ndevs || subno >= sdev->nunit || sdgetunit(sdev, subno) == nil){
		qunlock(&devslock);
		error(Enonexist);
	}


@@ 643,11 642,11 @@ sdopen(Chan* c, int omode)
	uchar tp;

	c = devopen(c, omode, 0, 0, sdgen);
	if ((tp = TYPE(c->qid)) != Qctl && tp != Qraw && tp != Qpart)
	if((tp = TYPE(c->qid)) != Qctl && tp != Qraw && tp != Qpart)
		return c;

	sdev = sdgetdev(DEV(c->qid));
	if (sdev == nil)
	if(sdev == nil)
		error(Enonexist);
	unit = sdev->unit[UNIT(c->qid)];



@@ 717,10 716,10 @@ sdbio(Chan* c, int write, char* a, long len, vlong off)
	ulong bno, max, nb, offset;

	sdev = sdgetdev(DEV(c->qid));
	if (sdev == nil)
	if(sdev == nil)
		error(Enonexist);
	unit = sdev->unit[UNIT(c->qid)];
	if (unit == nil)
	if(unit == nil)
		error(Enonexist);

	nchange = 0;


@@ 804,7 803,7 @@ sdbio(Chan* c, int write, char* a, long len, vlong off)
		else if(len > l - offset)
			len = l - offset;
	}
	else {
	else{
		l = unit->dev->ifc->bio(unit, 0, 0, b, nb, bno);
		if(l < 0)
			error(Eio);


@@ 885,10 884,10 @@ sdread(Chan *c, void *a, long n, vlong off)
		assert(p);
		e = p + READSTR;
		qlock(&devslock);
		for (i = 0; i != ndevs; i++) {
		for(i = 0; i != ndevs; i++){
			SDev *sdev = devs[i].dt_dev;

			if (sdev->ifc->stat)
			if(sdev->ifc->stat)
				p = sdev->ifc->stat(sdev, p, e);
			else
				p = seprint(e, "%s; no statistics available\n", sdev->name);


@@ 978,37 977,37 @@ sdread(Chan *c, void *a, long n, vlong off)
}

typedef struct {
	int		o_on;
	char		*o_spec;
	int	o_on;
	char*	o_spec;
	DevConf	o_cf;
} confdata_t;

static void
parse_switch(confdata_t *cd, char *option)
parse_switch(confdata_t* cd, char* option)
{
	if (!strcmp("on", option))
	if(!strcmp("on", option))
		cd->o_on = 1;
	else if (!strcmp("off", option))
	else if(!strcmp("off", option))
		cd->o_on = 0;
	else
		error(Ebadarg);
}

static void
parse_spec(confdata_t *cd, char *option)
parse_spec(confdata_t* cd, char* option)
{
	if (strlen(option) > 1) 
	if(strlen(option) > 1) 
		error(Ebadarg);
	cd->o_spec = option;
}

static port_t *
getnewport(DevConf *dc)
static port_t*
getnewport(DevConf* dc)
{
	port_t *p;

	p = (port_t *)malloc((dc->nports + 1) * sizeof(port_t));
	if (dc->nports > 0) {
	if(dc->nports > 0){
		memmove(p, dc->ports, dc->nports * sizeof(port_t));
		free(dc->ports);
	}


@@ 1020,62 1019,65 @@ getnewport(DevConf *dc)
}

static void
parse_port(confdata_t *cd, char *option)
parse_port(confdata_t* cd, char* option)
{
	char *e;
	port_t *p;
	
	p = (cd->o_cf.nports == 0 || 
	        cd->o_cf.ports[cd->o_cf.nports -1].port != (ulong)-1)?
			getnewport(&cd->o_cf): &cd->o_cf.ports[cd->o_cf.nports - 1];

	if(cd->o_cf.nports == 0 || cd->o_cf.ports[cd->o_cf.nports-1].port != (ulong)-1)
		p = getnewport(&cd->o_cf);
	else
		p = &cd->o_cf.ports[cd->o_cf.nports-1];
	p->port = strtol(option, &e, 0);
	if (e == nil || *e != '\0')
	if(e == nil || *e != '\0')
		error(Ebadarg);
}

static void
parse_size(confdata_t *cd, char *option)
parse_size(confdata_t* cd, char* option)
{
	char *e;
	port_t *p;

	p = (cd->o_cf.nports == 0 || cd->o_cf.ports[cd->o_cf.nports -1].size != -1)?
			getnewport(&cd->o_cf): &cd->o_cf.ports[cd->o_cf.nports - 1];
	p->size = 	(int)strtol(option, &e, 0);
	if (e == nil || *e != '\0')
	if(cd->o_cf.nports == 0 || cd->o_cf.ports[cd->o_cf.nports-1].size != -1)
		p = getnewport(&cd->o_cf);
	else
		p = &cd->o_cf.ports[cd->o_cf.nports-1];
	p->size = (int)strtol(option, &e, 0);
	if(e == nil || *e != '\0')
		error(Ebadarg);
}

static void
parse_irq(confdata_t *cd, char *option)
parse_irq(confdata_t* cd, char* option)
{
	char *e;

	cd->o_cf.interrupt = strtoul(option, &e, 0);
	if (e == nil || *e != '\0')
	if(e == nil || *e != '\0')
		error(Ebadarg);
}

static void
parse_type(confdata_t *cd, char *option)
parse_type(confdata_t* cd, char* option)
{
	cd->o_cf.type = option;
}

static struct {
	char *option;
	void	(*parse)(confdata_t *, char *);
	char	*option;
	void	(*parse)(confdata_t*, char*);
} options[] = {
	{ 	"switch",		parse_switch,	},
	{ 	"switch",	parse_switch,	},
	{	"spec",		parse_spec,	},
	{	"port",		parse_port,	},
	{	"size",		parse_size,	},
	{	"irq",			parse_irq,		},
	{	"irq",		parse_irq,	},
	{	"type",		parse_type,	},
};

static long
sdwrite(Chan *c, void *a, long n, vlong off)
sdwrite(Chan* c, void* a, long n, vlong off)
{
	Cmdbuf *cb;
	SDreq *req;


@@ 1101,33 1103,33 @@ sdwrite(Chan *c, void *a, long n, vlong off)
		memset(&cd.o_cf, 0, sizeof(DevConf));

		nf = tokenize(buf, field, Ncmd);
		for (i = 0; i < nf; i++) {
		for(i = 0; i < nf; i++){
			char *opt = field[i++];
			if (i >= nf)
			if(i >= nf)
				error(Ebadarg);
			for (j = 0; j != nelem(options); j++)
				if (!strcmp(opt, options[j].option))
			for(j = 0; j != nelem(options); j++)
				if(!strcmp(opt, options[j].option))
					break;
					
			if (j == nelem(options))
			if(j == nelem(options))
				error(Ebadarg);
			options[j].parse(&cd, field[i]);
		}

		if (cd.o_on < 0) 
		if(cd.o_on < 0) 
			error(Ebadarg);

		if (cd.o_on) {
			if (cd.o_spec == '\0' || cd.o_cf.nports == 0 || 
		if(cd.o_on){
			if(cd.o_spec == '\0' || cd.o_cf.nports == 0 || 
			     cd.o_cf.interrupt == 0 || cd.o_cf.type == nil)
				error(Ebadarg);
		}
		else {
			if (cd.o_spec == '\0')
		else{
			if(cd.o_spec == '\0')
				error(Ebadarg);
		}

		if (sddevtab.config == nil)
		if(sddevtab.config == nil)
			error("No configuration function");
		sddevtab.config(cd.o_on, cd.o_spec, &cd.o_cf);
		break;


@@ 1177,7 1179,7 @@ sdwrite(Chan *c, void *a, long n, vlong off)

	case Qraw:
		sdev = sdgetdev(DEV(c->qid));
		if (sdev == nil)
		if(sdev == nil)
			error(Enonexist);
		unit = sdev->unit[UNIT(c->qid)];
		qlock(&unit->raw);


@@ 1291,15 1293,15 @@ sdwstat(Chan* c, uchar* dp, int n)
static char
getspec(char base)
{
	while (1) {
	while(1){
		int i;
		SDev *sdev;

		for (i = 0; i != ndevs; i++)
			if ((sdev = devs[i].dt_dev) != nil && (char)sdev->idno == base)
		for(i = 0; i != ndevs; i++)
			if((sdev = devs[i].dt_dev) != nil && (char)sdev->idno == base)
				break;

		if (i == ndevs)
		if(i == ndevs)
			return base;
		base++;
	}


@@ 1307,73 1309,73 @@ getspec(char base)
}

static int
configure(char *spec, DevConf *cf)
configure(char* spec, DevConf* cf)
{
	ISAConf isa;
	dev_t *_devs;
	SDev *tail, *sdev, *(*probe)(DevConf *);
	SDev *tail, *sdev, *(*probe)(DevConf*);
	char *p, name[32];
	int i, added_devs;

	if ((p = strchr(cf->type, '/')) != nil)
	if((p = strchr(cf->type, '/')) != nil)
		*p++ = '\0';

	for(i = 0; sdifc[i] != nil; i++)
		if(!strcmp(sdifc[i]->name, cf->type))
			break;

	if (sdifc[i] == nil)
	if(sdifc[i] == nil)
		error("type not found");
	
	if ((probe = sdifc[i]->probe) == nil)
	if((probe = sdifc[i]->probe) == nil)
		error("No probe function");

	if (p) {
	if(p){
		/* Try to find the card on the ISA bus.  This code really belongs
		     in sdata and I'll move it later.  Really! */
		memset(&isa, 0, sizeof(isa));
		isa.port = cf->ports[0].port;
		isa.irq = cf->interrupt;

		if (pcmspecial(p, &isa) < 0)
		if(pcmspecial(p, &isa) < 0)
			error("Cannot find controller");
	}

	qlock(&devslock);
	if (waserror()) {
	if(waserror()){
		qunlock(&devslock);
		nexterror();
	}
	
	for (i = 0; i != ndevs; i++)
		if ((sdev = devs[i].dt_dev) != nil && sdev->idno == *spec)
	for(i = 0; i != ndevs; i++)
		if((sdev = devs[i].dt_dev) != nil && sdev->idno == *spec)
			break;
	if (i != ndevs)
	if(i != ndevs)
		error(Eexist);

	if ((sdev = (*probe)(cf)) == nil)
	if((sdev = (*probe)(cf)) == nil)
		error("Cannot probe controller");
	poperror();

	added_devs = 0;
	tail = sdev;
	while (tail) {
	while(tail){
		added_devs++;
		tail = tail->next;
	}
	
	_devs = (dev_t *)malloc((ndevs + added_devs) * sizeof(dev_t));
	_devs = (dev_t*)malloc((ndevs + added_devs) * sizeof(dev_t));
	memmove(_devs, devs, ndevs * sizeof(dev_t));
	free(devs);
	devs = _devs;

	while (sdev) {
	while(sdev){
		/* Assign `spec' to the device */
		*spec = getspec(*spec);
		snprint(name, sizeof(name), "sd%c", *spec);
		kstrdup(&sdev->name, name);
		sdev->idno = *spec;
		sdev->unit = (SDunit **)malloc(sdev->nunit * sizeof(SDunit *));
		sdev->unit = (SDunit **)malloc(sdev->nunit * sizeof(SDunit*));
		sdev->unitflg = (int *)malloc(sdev->nunit * sizeof(int));
		assert(sdev->unit && sdev->unitflg);



@@ 1389,29 1391,30 @@ configure(char *spec, DevConf *cf)
}

static int
unconfigure(char *spec)
unconfigure(char* spec)
{
	int i;	
	SDev *sdev;

	qlock(&devslock);
	if (waserror()) {
	if(waserror()){
		qunlock(&devslock);
		nexterror();
	}

	for (sdev = nil, i = 0; i != ndevs; i++)
		if ((sdev = devs[i].dt_dev) != nil && sdev->idno == *spec)
	sdev = nil;
	for(i = 0; i != ndevs; i++)
		if((sdev = devs[i].dt_dev) != nil && sdev->idno == *spec)
			break;

	if (i == ndevs)
	if(i == ndevs)
		error(Enonexist);

	if (sdev->r.ref)
	if(sdev->r.ref)
		error(Einuse);

	/* make sure no interrupts arrive anymore before removing resources */
	if (sdev->enabled && sdev->ifc->disable)
	if(sdev->enabled && sdev->ifc->disable)
		sdev->ifc->disable(sdev);

	/* we're alone and the device tab is locked; make the device unavailable */


@@ 1422,8 1425,8 @@ unconfigure(char *spec)
	qunlock(&devslock);
	poperror();

	for (i = 0; i != sdev->nunit; i++)
		if (sdev->unit[i]) {
	for(i = 0; i != sdev->nunit; i++)
		if(sdev->unit[i]){
			SDunit *unit = sdev->unit[i];

			free(unit->name);


@@ 1431,15 1434,17 @@ unconfigure(char *spec)
			free(unit);
		}

	if (sdev->ifc->clear)
	if(sdev->ifc->clear)
		sdev->ifc->clear(sdev);
	return 0;
}

static int
sdconfig(int on, char *spec, DevConf *cf)
sdconfig(int on, char* spec, DevConf* cf)
{
	return on? configure(spec, cf): unconfigure(spec);
	if(on)
		return configure(spec, cf);
	return unconfigure(spec);
}

Dev sddevtab = {

M port/edf.c => port/edf.c +64 -50
@@ 5,7 5,7 @@
#include	"dat.h"
#include	"fns.h"
#include	"../port/error.h"
#include	"../port/devsched.h"
#include	"../port/devrealtime.h"
#include	"../port/edf.h"

/* debugging */


@@ 68,7 68,7 @@ Taskq		qadmit;
/* Running/Preempted EDF tasks, head running, one stack per processor */
Taskq		edfstack[MAXMACH];

void (*devsched)(Task*, Ticks, int);
void (*devrt)(Task*, Ticks, int);

static void		edf_intr(Ureg*, Cycintr*);
static void		edf_resched(Task *t);


@@ 115,16 115,16 @@ edfpush(Task *t)
{
	Taskq *q;

	DENTER("%.*sedfpush, %s, %d\n", ind, tabs, edf_statename[t->state], t->runq.n);
	DENTER("%.*s%d edfpush, %s, %d\n", ind, tabs, m->machno, edf_statename[t->state], t->runq.n);
	q = edfstack + m->machno;
	assert(t->runq.n || (up && up->task == t));
	if (q->head){
		assert(q->head->state == EdfRunning);
		q->head->state = EdfPreempted;
		if(devsched) devsched(q->head, now, SPreempt);
		if(devrt) devrt(q->head, now, SPreempt);
	}
	t->rnext = q->head;
	if(devsched) devsched(t, now, SRun);
	if(devrt) devrt(t, now, SRun);
	q->head = t;
	DLEAVE;
}


@@ 135,7 135,7 @@ edfpop(void)
	Task *t;
	Taskq *q;

	DENTER("%.*sedfpop\n", ind, tabs);
	DENTER("%.*s%d edfpop\n", ind, tabs, m->machno);
	q = edfstack + m->machno;
	if (t = q->head){
		assert(t->state == EdfRunning);


@@ 144,7 144,7 @@ edfpop(void)
		if (q->head){
			assert(q->head->state == EdfPreempted);
			q->head->state = EdfRunning;
			if(devsched) devsched(q->head, now, SRun);
			if(devrt) devrt(q->head, now, SRun);
		}
	}
	DLEAVE;


@@ 157,7 157,7 @@ edfenqueue(Taskq *q, Task *t)
	Task *tt, **ttp;

	ilock(q);
	DENTER("%.*sedfenqueue, %s, %d\n", ind, tabs, edf_statename[t->state], t->runq.n);
	DENTER("%.*s%d edfenqueue, %s, %d\n", ind, tabs, m->machno, edf_statename[t->state], t->runq.n);
	t->rnext = nil;
	if (q->head == nil) {
		q->head = t;


@@ 188,7 188,7 @@ edfdequeue(Taskq *q)
{
	Task *t;

	DENTER("%.*sedfdequeue\n", ind, tabs);
	DENTER("%.*s%d edfdequeue\n", ind, tabs, m->machno);
	ilock(q);
	if (t = q->head){
		q->head = t->rnext;


@@ 205,7 205,7 @@ edfqremove(Taskq *q, Task *t)
	Task **tp;

	ilock(q);
	DENTER("%.*sedfqremove, %s, %d\n", ind, tabs, edf_statename[t->state], t->runq.n);
	DENTER("%.*s%d edfqremove, %s, %d\n", ind, tabs, m->machno, edf_statename[t->state], t->runq.n);
	for (tp = &q->head; *tp; tp = &(*tp)->rnext){
		if (*tp == t){
			*tp = t->rnext;


@@ 226,7 226,7 @@ edf_block(Proc *p)
	/* The current proc has blocked */
	ilock(&edflock);
	t = p->task;
	DENTER("%.*sedf_block, %s, %d\n", ind, tabs, edf_statename[t->state], t->runq.n);
	DENTER("%.*s%d edf_block, %s, %d\n", ind, tabs, m->machno, edf_statename[t->state], t->runq.n);

	assert(t);
	assert(t->state == EdfRunning);


@@ 239,7 239,7 @@ edf_block(Proc *p)
	pt = edfpop();
	assert(pt == t);
	t->state = EdfBlocked;
	if(devsched) devsched(t, now, SBlock);
	if(devrt) devrt(t, now, SBlock);
	DLEAVE;
	iunlock(&edflock);
}


@@ 250,7 250,7 @@ edfdeadline(Proc *p, SEvent why)
	Task *t, *nt;

	/* Task has reached its deadline, lock must be held */
	DENTER("%.*sedfdeadline, %s, %d\n", ind, tabs, edf_statename[p->task->state], p->task->runq.n);
	DENTER("%.*s%d edfdeadline, %s, %d\n", ind, tabs, m->machno, edf_statename[p->task->state], p->task->runq.n);
	SET(nt);
	if (p){
		nt = p->task;


@@ 260,14 260,14 @@ edfdeadline(Proc *p, SEvent why)
	t = edfpop();

	if(p != nil && nt != t){
		DPRINT("%.*sedfdeadline, %s, %d\n", ind, tabs, edf_statename[p->task->state], p->task->runq.n);
		DPRINT("%.*s%d edfdeadline, %s, %d\n", ind, tabs, m->machno, edf_statename[p->task->state], p->task->runq.n);
		iunlock(&edflock);
		assert(0 && p == nil || nt == t);
	}

	t->d = now;
	t->state = EdfDeadline;
	if(devsched) devsched(t, now, why);
	if(devrt) devrt(t, now, why);
	edf_resched(t);
	DLEAVE;
}


@@ 275,7 275,7 @@ edfdeadline(Proc *p, SEvent why)
void
edf_deadline(Proc *p)
{
	DENTER("%.*sedf_deadline\n", ind, tabs);
	DENTER("%.*s%d edf_deadline\n", ind, tabs, m->machno);
	/* Task has reached its deadline */
	ilock(&edflock);
	now = fastticks(nil);


@@ 291,27 291,41 @@ edf_admit(Task *t)

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

	/* simple sanity checks */
	if (t->T == 0)
		return "T not set";
	if (t->C == 0)
		return "C not set";
	if (t->D > t->T)
		return "D > T";
	if (t->D == 0)	/* if D is not set, set it to T */
		t->D = t->T;
	if (t->C > t->D)
		return "C > D";

	qlock(&edfschedlock);
	if (err = edf_testschedulability(t)){
		qunlock(&edfschedlock);
		return err;
	}
	ilock(&edflock);
	DENTER("%.*sedf_admit, %s, %d\n", ind, tabs, edf_statename[t->state], t->runq.n);
	DENTER("%.*s%d edf_admit, %s, %d\n", ind, tabs, m->machno, edf_statename[t->state], t->runq.n);
	now = fastticks(nil);

	t->state = EdfAdmitted;
	if(devrt) devrt(t, t->d, SAdmit);
	if (up->task == t){
		DPRINT("%.*sedf_admitting self\n", ind, tabs);
		DPRINT("%.*s%d edf_admitting self\n", ind, tabs, m->machno);
		/* Admitting self, fake reaching deadline */
		t->r = now;
		t->t = now + t->T;
		t->d = now + t->D;
		if(devsched) devsched(t, t->d, SDeadline);
		if(devrt) devrt(t, t->d, SDeadline);
		t->S = t->C;
		t->scheduled = now;
		t->state = EdfRunning;
		if(devsched) devsched(t, now, SRun);
		if(devrt) devrt(t, now, SRun);
		setΔ();
		assert(t->runq.n > 0 || (up && up->task == t));
		edfpush(t);


@@ 342,7 356,7 @@ edf_expel(Task *t)

	qlock(&edfschedlock);
	ilock(&edflock);
	DENTER("%.*sedf_expel, %s, %d\n", ind, tabs, edf_statename[t->state], t->runq.n);
	DENTER("%.*s%d edf_expel, %s, %d\n", ind, tabs, m->machno, edf_statename[t->state], t->runq.n);
	now = fastticks(nil);
	switch(t->state){
	case EdfUnused:


@@ 378,7 392,7 @@ edf_expel(Task *t)
		break;
	}
	t->state = EdfExpelled;
	if(devsched) devsched(t, now, SExpel);
	if(devrt) devrt(t, now, SExpel);
	setΔ();
	DLEAVE;
	iunlock(&edflock);


@@ 432,7 446,7 @@ edf_setclock(void)
	Ticks ticks;
	Task *t;

	DENTER("%.*sedf_setclock\n", ind, tabs);
	DENTER("%.*s%d edf_setclock\n", ind, tabs, m->machno);
	ticks = ~0ULL;
	if ((t = qwaitrelease.head) && t->r < ticks)
		ticks = t->r;


@@ 447,19 461,19 @@ edf_setclock(void)
		return;
	}
	if (schedpoint.when){
		DPRINT("%.*scycintrdel %T\n", ind, tabs, ticks2time(schedpoint.when));
		DPRINT("%.*s%d cycintrdel %T\n", ind, tabs, m->machno, ticks2time(schedpoint.when));
		cycintrdel(&schedpoint);
		schedpoint.when = 0;
	}
	if (ticks <= now){
		DPRINT("%.*sedf_timer: %T too late\n", ind, tabs, ticks2time(now-ticks));
		DPRINT("%.*s%d edf_timer: %T too late\n", ind, tabs, m->machno, ticks2time(now-ticks));
		ticks = now;
	}
	if (ticks != ~0ULL) {
		DPRINT("%.*sprogram timer in %T\n", ind, tabs, ticks2time(ticks-now));
		DPRINT("%.*s%d program timer in %T\n", ind, tabs, m->machno, ticks2time(ticks-now));
		schedpoint.when = ticks;
		cycintradd(&schedpoint);
		DPRINT("%.*scycintradd %T\n", ind, tabs, ticks2time(schedpoint.when-now));
		DPRINT("%.*s%d cycintradd %T\n", ind, tabs, m->machno, ticks2time(schedpoint.when-now));
	}
	clockintrsched();
	DLEAVE;


@@ 469,7 483,7 @@ static void
edf_intr(Ureg *, Cycintr *cy)
{

	DENTER("%.*sedf_intr\n", ind, tabs);
	DENTER("%.*s%d edf_intr\n", ind, tabs, m->machno);
	/* Timer interrupt
	 * Timed events are:
	 * 1. release a task (look in qwaitrelease)


@@ 497,13 511,13 @@ edf_bury(Proc *p)
	Task *t;
	Proc **pp;

	DPRINT("%.*sedf_bury\n", ind, tabs);
	DPRINT("%.*s%d edf_bury\n", ind, tabs, m->machno);
	ilock(&edflock);
	now = fastticks(nil);
	if ((t = p->task) == nil){
		/* race condition? */
		iunlock(&edflock);
		DPRINT("%.*sedf bury race, pid %lud\n", ind, tabs, p->pid);
		DPRINT("%.*s%d edf bury race, pid %lud\n", ind, tabs, m->machno, p->pid);
		return;
	}
	assert(edfstack[m->machno].head == t);


@@ 520,7 534,7 @@ edf_bury(Proc *p)
		assert(t->runq.head == nil);
		t->state = EdfIdle;
	}
	if(devsched) devsched(t, now, SBlock);
	if(devrt) devrt(t, now, SBlock);
	p->task = nil;
	iunlock(&edflock);
}


@@ 531,11 545,11 @@ edf_ready(Proc *p)
	Task *t;

	ilock(&edflock);
	DENTER("%.*sedf_ready, %s, %d\n", ind, tabs, edf_statename[p->task->state], p->task->runq.n);
	DENTER("%.*s%d edf_ready, %s, %d\n", ind, tabs, m->machno, edf_statename[p->task->state], p->task->runq.n);
	if ((t = p->task) == nil){
		/* Must be a race */
		iunlock(&edflock);
		DPRINT("%.*sedf ready race, pid %lud\n", ind, tabs, p->pid);
		DPRINT("%.*s%d edf ready race, pid %lud\n", ind, tabs, m->machno, p->pid);
		return;
	}
	p->rnext = 0;


@@ 562,25 576,25 @@ edf_resched(Task *t)
{
	Task *xt;

	DENTER("%.*sedf_resched, %s, %d\n", ind, tabs, edf_statename[t->state], t->runq.n);
	DENTER("%.*s%d edf_resched, %s, %d\n", ind, tabs, m->machno, edf_statename[t->state], t->runq.n);
	if (t->nproc == 0){
		/* No member processes */
		if (t->state > EdfIdle){
			t->state = EdfIdle;
			if(devsched) devsched(t, now, SBlock);
			if(devrt) devrt(t, now, SBlock);
		}
		DLEAVE;
		return;
	}
	if (t->runq.n == 0 && (up == nil || up->task != t)){
		/* Member processes but none runnable */
		DPRINT("%.*sedf_resched, nothing runnable\n", ind, tabs);
		DPRINT("%.*s%d edf_resched, nothing runnable\n", ind, tabs, m->machno);
		if (t->state == EdfRunning)
			edfpop();

		if (t->state >= EdfIdle && t->state != EdfBlocked){
			t->state = EdfBlocked;
			if(devsched) devsched(t, now, SBlock);
			if(devrt) devrt(t, now, SBlock);
		}
		DLEAVE;
		return;


@@ 590,7 604,7 @@ edf_resched(Task *t)

	switch (t->state){
	case EdfUnused:
		iprint("%.*sattempt to schedule unused task\n", ind, tabs);
		iprint("%.*s%d attempt to schedule unused task\n", ind, tabs, m->machno);
	case EdfExpelled:
		DLEAVE;
		return;	/* Not admitted */


@@ 619,7 633,7 @@ edf_resched(Task *t)
	case EdfRunning:
		if (t->r <= now){
			if (t->t < now){
				DPRINT("%.*sedf_resched, rerelease\n", ind, tabs);
				DPRINT("%.*s%d edf_resched, rerelease\n", ind, tabs, m->machno);
				/* Period passed, rerelease */
				t->r = now;
				xt = edfpop();


@@ 630,7 644,7 @@ edf_resched(Task *t)
			}
			if (now < t->d){
				if (t->S > 0){
					DPRINT("%.*sedf_resched, resume\n", ind, tabs);
					DPRINT("%.*s%d edf_resched, resume\n", ind, tabs, m->machno);
					/* Running, not yet at deadline, leave it */
					DLEAVE;
					return;


@@ 640,7 654,7 @@ edf_resched(Task *t)
			/* Released, but deadline is past, release at t->t */
			t->r = t->t;
		}
		DPRINT("%.*sedf_resched, schedule release\n", ind, tabs);
		DPRINT("%.*s%d edf_resched, schedule release\n", ind, tabs, m->machno);
		xt = edfpop();
		assert(xt == t);
		edfenqueue(&qwaitrelease, t);


@@ 651,7 665,7 @@ edf_resched(Task *t)
	case EdfDeadline:
		if (t->r <= now){
			if (t->t < now){
				DPRINT("%.*sedf_resched, rerelease\n", ind, tabs);
				DPRINT("%.*s%d edf_resched, rerelease\n", ind, tabs, m->machno);
				/* Period passed, rerelease */
				t->r = now;
				edf_release(t);


@@ 660,11 674,11 @@ edf_resched(Task *t)
			}
			if (now < t->d && (t->flags & Useblocking) == 0){
				if (t->S > 0){
					DPRINT("%.*sedf_resched, resume\n", ind, tabs);
					DPRINT("%.*s%d edf_resched, resume\n", ind, tabs, m->machno);
					/* Released, not yet at deadline, release (again) */
					t->state = EdfReleased;
					edfenqueue(&qreleased, t);
					if(devsched) devsched(t, now, SResume);
					if(devrt) devrt(t, now, SResume);
					DLEAVE;
					return;
				}else


@@ 673,7 687,7 @@ edf_resched(Task *t)
			/* Released, but deadline is past, release at t->t */
			t->r = t->t;
		}
		DPRINT("%.*sedf_resched, schedule release\n", ind, tabs);
		DPRINT("%.*s%d edf_resched, schedule release\n", ind, tabs, m->machno);
		edfenqueue(&qwaitrelease, t);
		t->state = EdfAwaitrelease;
		edf_setclock();


@@ 685,15 699,15 @@ edf_resched(Task *t)
void
edf_release(Task *t)
{
	DENTER("%.*sedf_release, %s, %d\n", ind, tabs, edf_statename[t->state], t->runq.n);
	DENTER("%.*s%d edf_release, %s, %d\n", ind, tabs, m->machno, edf_statename[t->state], t->runq.n);
	assert(t->runq.n > 0 || (up && up->task == t));
	t->t = t->r + t->T;
	t->d = t->r + t->D;
	if(devsched) devsched(t, t->d, SDeadline);
	if(devrt) devrt(t, t->d, SDeadline);
	t->S = t->C;
	t->state = EdfReleased;
	edfenqueue(&qreleased, t);
	if(devsched) devsched(t, now, SRelease);
	if(devrt) devrt(t, now, SRelease);
	edf_setclock();
	DLEAVE;
}


@@ 727,7 741,7 @@ edf_runproc(void)
	DENTER("edf_runproc %lud\n", nilcount);
	if (nt && (t == nil || (nt->D < t->Δ && nt->d < t->d))){
		/* released task is better than current */
		DPRINT("%.*sedf_runproc: released\n", ind, tabs);
		DPRINT("%.*s%d edf_runproc: released\n", ind, tabs, m->machno);
		edfdequeue(&qreleased);
		assert(nt->runq.n >= 1);
		edfpush(nt);


@@ 735,7 749,7 @@ edf_runproc(void)
		t = nt;
		t->scheduled = now;
	}else{
		DPRINT("%.*sedf_runproc: current\n", ind, tabs);
		DPRINT("%.*s%d edf_runproc: current\n", ind, tabs, m->machno);
	}

	assert (t->runq.n);

M port/edf.h => port/edf.h +2 -1
@@ 11,6 11,7 @@ enum {
	Useblocking = 0x2,
};

typedef vlong	Time;
typedef uvlong	Ticks;

typedef struct Task		Task;


@@ 97,7 98,7 @@ extern Taskq		qreleased;
extern Taskq		qextratime;
extern Taskq		edfstack[];
extern int			edf_stateupdate;
extern void		(*devsched)(Task *, Ticks, int);
extern void		(*devrt)(Task *, Ticks, int);
extern char *		edf_statename[];

#pragma	varargck	type	"T"		Time