~kris/9p

9hist

1d66c87010321514f6f3921c40fc5d63f52067a5 — David du Colombier 23 years ago 53c6dbe
Plan 9 from Bell Labs 2002-09-27
4 files changed, 266 insertions(+), 418 deletions(-)

M port/devrealtime.c
D port/devrealtime.h
M port/edf.c
M port/nulledf.c
M port/devrealtime.c => port/devrealtime.c +44 -315
@@ 6,8 6,7 @@
#include "io.h"
#include "ureg.h"
#include "../port/error.h"
#include	"../port/devrealtime.h"
#include "../port/edf.h"
#include	"../port/realtime.h"

#pragma	varargck	type	"T"		vlong



@@ 22,10 21,6 @@ static QLock elock;
static Ref logopens;
static Ref debugopens;
static uvlong fasthz;	
static int taskno;

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

enum {
	Qistask = 0x10000,


@@ 73,69 68,7 @@ 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)
{
	vlong n;
	char c;

	p = seprint(p, e, "{%s, D%U, Δ%U,T%U, C%U, S%U",
		edfstatename[t->state], t->D, t->Delta, 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;
}
static int taskno;

static Task *
taskinit(void)


@@ 168,7 101,7 @@ taskfree(Task *t)
	if (decref(t))
		return;
	assert(t->procs.n == 0);
	assert(t->res.n == 0);
	assert(t->csns.n == 0);
	free(t->user);
	free(t);
}


@@ 381,7 314,6 @@ devrtread(Chan *c, void *v, long n, vlong offs)
	Ticks now;
	Time tim;
	List *l;
	Resource *r;

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


@@ 450,29 382,7 @@ devrtread(Chan *c, void *v, long n, vlong offs)
			qunlock(&edfschedlock);
			nexterror();
		}
		p = buf;
		e = p + sizeof(buf);
		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='");
				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 (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");
		}
		seprintresources(buf, buf + sizeof(buf));
		qunlock(&edfschedlock);
		poperror();
		return readstr(offs, v, n, buf);


@@ 482,7 392,7 @@ devrtread(Chan *c, void *v, long n, vlong offs)
		e = p + sizeof(buf);
		qlock(&edfschedlock);
		qunlock(&edfschedlock);
		p = seprint(p, e, "\n");
		seprint(p, e, "\n");
		return readstr(offs, v, n, buf);
	case Qdebug:
		p = buf;


@@ 530,15 440,9 @@ 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->res.n){
		if (t->csns.n){
			p = seprint(p, e, " resources='");
			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 = seprintcsn(p, e, &t->csns);
			p = seprint(p, e, "'");
		}
		if (t->procs.n){


@@ 569,72 473,6 @@ devrtread(Chan *c, void *v, long n, vlong offs)
	return n0 - n;
}

static Resource *
resource(char *name, int add)
{
	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("resource: malloc");
	kstrdup(&r->name, name);
	enlist(&resources, r);
	return r;
}

void
resourcefree(Resource *r)
{
	if (decref(r))
		return;
	delist(&resources, r);
	assert(r->tasks.n == 0);
	free(r->name);
	free(r);
}

static void
removetask(Task *t)
{
	Proc *p;
	Resource *r;
	List *l;

	edf->edfexpel(t);
	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;
		ready(p);
		t->runq.n--;
	}
	t->runq.tail = nil;
	assert(t->runq.n == 0);
	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;
	if (delist(&tasks, t))
		taskfree(t);
}

static long
devrtwrite(Chan *c, void *va, long n, vlong)
{


@@ 646,6 484,7 @@ devrtwrite(Chan *c, void *va, long n, vlong)
	Time time;
	long pid;
	Proc *p;
	CSN *l;

	a = va;
	if (c->mode == OREAD)


@@ 707,6 546,7 @@ devrtwrite(Chan *c, void *va, long n, vlong)
				}
				if (t->T < time2ticks(10000000/HZ))
					error("period too short");
				DEBUG("Task %d, T=%T\n", t->taskno, ticks2time(t->T));
			}else if (strcmp(a, "D") == 0){
				if (e=parsetime(&time, v))
					error(e);


@@ 726,6 566,7 @@ devrtwrite(Chan *c, void *va, long n, vlong)
					t->D += ticks;
					break;
				}
				DEBUG("Task %d, D=%T\n", t->taskno, ticks2time(t->D));
			}else if (strcmp(a, "C") == 0){
				if (e=parsetime(&time, v))
					error(e);


@@ 747,40 588,54 @@ devrtwrite(Chan *c, void *va, long n, vlong)
				}
				if (t->C < time2ticks(10000000/HZ))
					error("cost too small");
				DEBUG("Task %d, C=%T\n", t->taskno, ticks2time(t->C));
			}else if (strcmp(a, "resources") == 0){
				if (v == nil)
					error("resources: value missing");
				edf->edfexpel(t);
				if (add < 0)
					error("can't remove resources yet");
				if (add == 0){
					List *l;

					while (l = t->res.next) {
	
					while (l = t->csns.next) {
						r = l->i;
						assert(r);
						if (delist(&r->tasks, t))
							taskfree(t);
						if (delist(&t->res, r))
						if (delist(&t->csns, r))
							resourcefree(r);
					}
					assert(t->res.n == 0);
					assert(t->csns.n == 0);
					add = 1;
					USED(add);
				}
				nrargs = tokenize(v, rargs, nelem(rargs));
				for (j = 0; j < nrargs; j++)
					if (r = resource(rargs[j], add)){
						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");
				v = parseresource(&t->csns, nil, v);
				if (v && *v)
					error("resources: parse error");
			}else if (strcmp(a, "acquire") == 0){
				if (v == nil)
					error("acquire: value missing");
				if ((r = resource(v, 0)) == nil)
					error("acquire: no such resource");
				for (l = (CSN*)t->csns.next; l; l = (CSN*)l->next){
					if (l->i == r){
DEBUG("l->p (0x%p) == t->curcsn (0x%p) && l->S (%T) != 0\n", l->p, t->curcsn, ticks2time(l->S));
						if(l->p == t->curcsn && l->S != 0)
						break;
					}
				}
				if (l == nil)
					error("acquire: no access or resource exhausted");
				edf->resacquire(t, l);
			}else if (strcmp(a, "release") == 0){
				if (v == nil)
					error("release: value missing");
				if ((r = resource(v, 0)) == nil)
					error("release: no such resource");
				if (t->curcsn->i != r)
					error("release: release not held or illegal release order");
				edf->resrelease(t);
			}else if (strcmp(a, "procs") == 0){
				if (v == nil)
					error("procs: value missing");


@@ 904,129 759,3 @@ Dev realtimedevtab = {
	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){
		if(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;
}

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;
}

D port/devrealtime.h => port/devrealtime.h +0 -28
@@ 1,28 0,0 @@

typedef vlong	Time;
typedef struct	Schedevent Schedevent;

#define Onemicrosecond			((Time)1000ULL)
#define Onemillisecond			((Time)1000*Onemicrosecond)
#define Onesecond				((Time)1000*Onemillisecond)

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 {
	ushort	tid;		/* Task ID */
	SEvent	etype;	/* Event type */
	Time		ts;		/* Event time */
};


M port/edf.c => port/edf.c +221 -74
@@ 5,8 5,7 @@
#include	"dat.h"
#include	"fns.h"
#include	"../port/error.h"
#include	"../port/devrealtime.h"
#include	"../port/edf.h"
#include	"../port/realtime.h"

/* debugging */
int			edfprint = 0;


@@ 30,7 29,6 @@ static Timer	deadlinetimer[MAXMACH];	/* Time of next deadline */
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;


@@ 62,6 60,8 @@ Taskq		qextratime;
/* Running/Preempted EDF tasks, head running, one stack per processor */
Taskq		edfstack[MAXMACH];

static Task *qschedulability;

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

static void		edfresched(Task *t);


@@ 83,7 83,6 @@ edfinit(void)
		iunlock(&edflock);
		return;
	}
	fastticks(&fasthz);
	for (i = 0; i < conf.nmach; i++){
		deadlinetimer[i].f = edfdeadlineintr;
		deadlinetimer[i].a = &deadlinetimer[i];


@@ 298,7 297,9 @@ edfdeadline(Proc *p)
static char *
edfadmit(Task *t)
{
	char *err;
	char *err, *p;
	static char csndump[512];
	CSN *c;

	/* Called with edfschedlock held */
	if (t->state != EdfExpelled)


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

	resourcetimes(t, &t->csns);

	DEBUG("task %d: T %T, C %T, D %T, tΔ %T\n",
		t->taskno, ticks2time(t->T), ticks2time(t->C),
		ticks2time(t->D), ticks2time(t->testDelta));
	p = seprintresources(csndump, csndump+sizeof csndump);
	seprintcsn(p, csndump+sizeof csndump, &t->csns);
	DEBUG("%s\n", csndump);

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



@@ 339,6 348,10 @@ edfadmit(Task *t)
		t->periods++;
		if(devrt) devrt(t, now, SRun);
		setdelta();
		for (c = (CSN*)t->csns.next; c; c = (CSN*)c->next){
			DEBUG("admit csn: C=%T\n", ticks2time(c->C));
			c->S = c->C;
		}
		assert(t->runq.n > 0 || (up && up->task == t));
		edfpush(t);
		if (deadlinetimer[m->machno].when)


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



@@ 413,13 425,14 @@ static void
edfreleaseintr(Ureg*, Timer*)
{
	Task *t;
	extern int panicking;

	DPRINT("%d edfreleaseintr\n", m->machno);

	timerdel(&releasetimer[m->machno]);
	releasetimer[m->machno].when = 0;

	if(active.exiting)
	if(panicking || active.exiting)
		return;

	ilock(&edflock);


@@ 442,18 455,23 @@ edfdeadlineintr(Ureg*, Timer*)

	Ticks used;
	Task *t;
	Resource *r;
	char buf[128];
	int noted;
	extern int panicking;

	DPRINT("%d edfdeadlineintr\n", m->machno);

	timerdel(&deadlinetimer[m->machno]);
	deadlinetimer[m->machno].when = 0;

	if(active.exiting)
	if(panicking || active.exiting)
		return;

	ilock(&edflock);
	// If up is not set, we're running inside the scheduler
	// for non-real-time processes. 
	// for non-real-time processes.
	noted = 0;
	if (up && isedf(up)) {
		now = fastticks(nil);



@@ 465,18 483,33 @@ edfdeadlineintr(Ureg*, Timer*)
		t->total += used;

		if (t->r < now){
			if (t->S <= used)
			if (t->curcsn){
				if (t->curcsn->S <= used){
					t->curcsn->S = 0LL;
					r = t->curcsn->i;
					noted++;
					snprint(buf, sizeof buf, "sys: deadline miss: resource %s", r->name);
				}else
					t->curcsn->S -= used;
			}

			if (t->S <= used){
				t->S = 0LL;
			else
				if (!noted){
					noted++;
					snprint(buf, sizeof buf, "sys: deadline miss: runtime");
				}
			}else
				t->S -= used;
	
			if (t->d <= now || t->S == 0LL){

			if (t->d <= now || t->S == 0LL || t->curcsn == 0LL){
				/* Task has reached its deadline/slice, remove from queue */
				if (t->d <= now){
					t->missed++;
					misseddeadlines++;
				}
				deadline(up, SSlice);

				while (t = edfstack[m->machno].head){
					if (now < t->d)
						break;


@@ 486,6 519,8 @@ edfdeadlineintr(Ureg*, Timer*)
		}
	}
	iunlock(&edflock);
	if (noted)
		postnote(up, 1, buf, NUser);
	sched();
	splhi();
}


@@ 667,12 702,18 @@ edfresched(Task *t)
static void
edfrelease(Task *t)
{
	CSN *c;

	DPRINT("%d edfrelease, %s, %d\n", m->machno, edfstatename[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(devrt) devrt(t, t->d, SDeadline);
	t->S = t->C;
	for (c = (CSN*)t->csns.next; c; c = (CSN*)c->next){
		DEBUG("release csn: C=%T\n", ticks2time(c->C));
		c->S = c->C;
	}
	t->state = EdfReleased;
	edfenqueue(&qreleased, t);
	if(devrt) devrt(t, now, SRelease);


@@ 781,29 822,44 @@ setdelta(void)
{
	Resource *r;
	Task *t;
	List *lr, *lt;
	int R;
	List *lr, *l;
	TaskLink *lt;
	CSN *c;

	for (lr = resources.next; lr; lr = lr->next){
		r = lr->i;
		assert(r);
		r->Delta = ~0LL;
		for (lt = r->tasks.next; lt; lt = lt->next){
		r->Delta = Infinity;
		R = 1;
		for (lt = (TaskLink*)r->tasks.next; lt; lt = (TaskLink*)lt->next){
			t = lt->i;
			assert(t);
			if (t->D < r->Delta)
			if (t->D < r->Delta){
				r->Delta = t->D;
			}
			if (lt->R == 0){
				R = 0;
			}
		}
		if (R)
			r->Delta = Infinity;	/* Read-only resource, no exclusion */
	}
	for (lt = tasks.next; lt ; lt = lt->next){
		t = lt->i;

	/* Enumerate the critical sections */
	for (l = tasks.next; l ; l = l->next){
		t = l->i;
		assert(t);
		if (t->state < EdfIdle)
		if (t->state <= EdfExpelled)
			continue;
		t->Delta = t->D;
		for (lr = t->res.next; lr; lr = lr->next){
			r = lr->i;
		t->Delta = Infinity;
		for (c = (CSN*)t->csns.next; c; c = (CSN*)c->next){
			r = c->i;
			assert(r);
			if (r->Delta < t->Delta)
			c->Delta = r->Delta;
			if (c->p && c->p->Delta < c->Delta)
				c->Delta = c->p->Delta;
			if (c->C == t->C && r->Delta < t->Delta)
				t->Delta = r->Delta;
		}
	}


@@ 814,55 870,104 @@ testdelta(Task *thetask)
{
	Resource *r;
	Task *t;
	List *lr, *lt;
	int R;
	List *lr, *l;
	TaskLink *lt;
	CSN *c;

	for (lr = resources.next; lr; lr = lr->next){
		r = lr->i;
		assert(r);
		r->testDelta = ~0ULL;
		for (lt = r->tasks.next; lt; lt = lt->next){
		DEBUG("Resource %s: ", r->name);
		r->testDelta = Infinity;
		R = 1;
		for (lt = (TaskLink*)r->tasks.next; lt; lt = (TaskLink*)lt->next){
			t = lt->i;
			assert(t);
			if (t->D < r->testDelta)
			if (t->D < r->testDelta){
				r->testDelta = t->D;
				DEBUG("%d→%T ", t->taskno, ticks2time(t->D));
			}
			if (lt->R == 0){
				DEBUG("%d→X ", t->taskno);
				R = 0;
			}
		}
		if (R)
			r->testDelta = Infinity;	/* Read-only resource, no exclusion */
		DEBUG("tΔ = %T\n", ticks2time(r->testDelta));
	}
	for (lt = tasks.next; lt ; lt = lt->next){
		t = lt->i;

	/* Enumerate the critical sections */
	for (l = tasks.next; l ; l = l->next){
		t = l->i;
		assert(t);
		if (t->state <= EdfExpelled && t != thetask)
			continue;
		t->testDelta = t->D;
		for (lr = t->res.next; lr; lr = lr->next){
			r = lr->i;
		t->testDelta = Infinity;
		for (c = (CSN*)t->csns.next; c; c = (CSN*)c->next){
			r = c->i;
			assert(r);
			if (r->testDelta < t->testDelta)
			c->testDelta = r->testDelta;
			if (c->p && c->p->testDelta < c->testDelta)
				c->testDelta = c->p->testDelta;
			if (c->C == t->C && r->testDelta < t->testDelta)
				t->testDelta = r->testDelta;
			DEBUG("Task %d Resource %s: tΔ = %T\n",
				t->taskno, r->name, ticks2time(r->testDelta));
		}
	}
}

static Ticks
blockcost(Ticks ticks, Task *thetask)
blockcost(Ticks ticks, Task *task, Task *thetask)
{
	Ticks Cb, Cbt;
	List *l;
	Resource *r;
	CSN *c, *lc;
	int R;
	Task *t;
	Ticks Cb;
	List *lt;

	Cb = 0;
	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)
			Cb = t->C;
	/* for each resource in task t, find all CSNs that refer to the
	 * resource.  If their Δ <= ticks < D and c->C > current CB
	 * Cb = c->C
	 */
	DEBUG("blockcost task %d: ", task->taskno);
	for (c = (CSN*)task->csns.next; c; c = (CSN*)c->next){
		r = c->i;
		assert(r);

		DEBUG("%s ", r->name);
		Cbt = Cb;
		R = 1;	/* R == 1: resource is only used in read-only mode  */
		for (l = tasks.next; l; l = l->next){
			t = l->i;
			if (t->state <= EdfExpelled && t != thetask)
				continue;	/* csn belongs to an irrelevant task */
			for (lc = (CSN*)t->csns.next; lc; lc = (CSN*)lc->next){
				if (lc->i != r)
					continue;	/* wrong resource */
				if (lc->R == 0)
					R = 0;	/* Resource is used in exclusive mode */
				DEBUG("(%T≤%T<%T: %T) ",
					ticks2time(lc->testDelta), ticks2time(ticks), ticks2time(t->D),
					ticks2time(lc->C));
				if (lc->testDelta <= ticks && ticks < t->D && Cbt < lc->C)
					Cbt = lc->C;
			}
		}
		if (R == 0){
			DEBUG("%T, ", ticks2time(Cbt));
			Cb = Cbt;
		}
		DEBUG("ro, ");
	}
	DEBUG("Cb = %T\n", ticks2time(Cb));
	return Cb;
}

static Task *qschedulability;

static void
testenq(Task *t)
{


@@ 898,7 1003,7 @@ edftestschedulability(Task *thetask)
	/* initialize */
	testdelta(thetask);
	if (thetask && (thetask->flags & Verbose))
		pprint("schedulability test\n");
		pprint("schedulability test for task %d\n", thetask->taskno);
	qschedulability = nil;
	for (l = tasks.next; l; l = l->next){
		t = l->i;


@@ 908,7 1013,7 @@ edftestschedulability(Task *thetask)
		t->testtype = Release;
		t->testtime = 0;
		if (thetask && (thetask->flags & Verbose))
			pprint("\tInit: enqueue task %lud\n", t->taskno);
			pprint("\tInit: enqueue task %d\n", t->taskno);
		testenq(t);
	}
	H=0;


@@ 920,24 1025,32 @@ edftestschedulability(Task *thetask)
		switch (t->testtype){
		case Deadline:
			H += t->C;
			Cb = blockcost(ticks, thetask);
			Cb = blockcost(ticks, t, thetask);
			if (thetask && (thetask->flags & Verbose))
				pprint("\tStep %3d, Ticks %T, task %lud, deadline, H += %T → %T, Cb = %T\n",
				pprint("\tStep %3d, Ticks %T, task %d, deadline, H += %T → %T, Cb = %T\n",
					steps, ticks2time(ticks), t->taskno,
					ticks2time(t->C), ticks2time(H), ticks2time(Cb));
			if (H+Cb>ticks)
			if (H+Cb>ticks){
				if (thetask && (thetask->flags & Verbose))
					pprint("task %d not schedulable: H=%T + Cb=%T > ticks=%T\n",
						thetask->taskno, ticks2time(H), ticks2time(Cb), ticks2time(ticks));
				return "not schedulable";
			}
			t->testtime += t->T - t->D;
			t->testtype = Release;
			testenq(t);
			break;
		case Release:
			if (thetask && (thetask->flags & Verbose))
				pprint("\tStep %3d, Ticks %T, task %lud, release, G  %T, C%T\n",
				pprint("\tStep %3d, Ticks %T, task %d, release, G  %T, C%T\n",
					steps, ticks2time(ticks), t->taskno,
					ticks2time(t->C), ticks2time(G));
			if(ticks && G <= ticks)
			if(ticks && G <= ticks){
				if (thetask && (thetask->flags & Verbose))
					pprint("task %d schedulable: G=%T <= ticks=%T\n",
						thetask->taskno, ticks2time(G), ticks2time(ticks));
				return nil;
			}
			G += t->C;
			t->testtime += t->D;
			t->testtype = Deadline;


@@ 950,32 1063,64 @@ edftestschedulability(Task *thetask)
	return "probably not schedulable";
}

static uvlong
uvmuldiv(uvlong x, ulong num, ulong den)
static void
resacquire(Task *t, CSN *c)
{
	/* multiply, then divide, avoiding overflow */
	uvlong hi;
	Ticks now, when, used;

	hi = (x & 0xffffffff00000000LL) >> 32;
	x &= 0xffffffffLL;
	hi *= num;
	return (x*num + (hi%den << 32)) / den + (hi/den << 32);
	now = fastticks(nil);
	used = now - t->scheduled;
	t->scheduled = now;
	t->total += used;
	t->S -= used;
	if (t->curcsn)
		t->curcsn->S -= used;
	when = now + c->S;
	if (when < deadlinetimer[m->machno].when){
		timerdel(&deadlinetimer[m->machno]);
		deadlinetimer[m->machno].when = when;
		timeradd(&deadlinetimer[m->machno]);
	}
	t->Delta = c->Delta;
	t->curcsn = c;
	/* priority is going up, no need to reschedule */
}

Time
ticks2time(Ticks ticks)
static void
resrelease(Task *t)
{
	assert(ticks >= 0);
	if (fasthz == 0)
		fastticks(&fasthz);
	return uvmuldiv(ticks, Onesecond, fasthz);
}
	Ticks now, when, used;
	CSN *c;

Ticks
time2ticks(Time time)
{
	assert(time >= 0);
	return uvmuldiv(time, fasthz, Onesecond);
	c = t->curcsn;
	assert(c);
	t->curcsn = c->p;
	now = fastticks(nil);
	used = now - t->scheduled;
	t->scheduled = now;
	t->total += used;
	t->S -= used;
	c->S -= used;
	if (now + t->S > t->d)
		when = t->d;
	else
		when = now + t->S;
	if (t->curcsn){
		t->curcsn->S -= c->S;	/* the sins of the fathers shall be visited upon the children */
		t->Delta = t->curcsn->Delta;
		if (when > now + t->curcsn->S)
			when = now + t->curcsn->S;
	}else
		t->Delta = Infinity;
	c->S = 0LL;	/* don't allow reuse */
	if (deadlinetimer[m->machno].when)
		timerdel(&deadlinetimer[m->machno]);
	deadlinetimer[m->machno].when = when;
	timeradd(&deadlinetimer[m->machno]);

	qunlock(&edfschedlock);
	sched();	/* reschedule */
	qlock(&edfschedlock);
}

Edfinterface realedf = {


@@ 989,4 1134,6 @@ Edfinterface realedf = {
	.edfexpel		= edfexpel,
	.edfadmit		= edfadmit,
	.edfdeadline	= edfdeadline,
	.resacquire	= resacquire,
	.resrelease	= resrelease,
};

M port/nulledf.c => port/nulledf.c +1 -1
@@ 4,7 4,7 @@
#include	"dat.h"
#include	"fns.h"
#include	"../port/error.h"
#include	"../port/edf.h"
#include	"../port/realtime.h"

static int
isedf(Proc*)