Plan 9 from Bell Labs’s /usr/web/sources/extra/9hist/port/edf.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


## diffname port/edf.c 2002/0315
## diff -e /dev/null /n/emeliedump/2002/0315/sys/src/9/port/edf.c
0a
/* EDF scheduling */
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"../port/error.h"
#include	"../port/devsched.h"
#include	"../port/edf.h"

/* debugging */
int			edfprint = 0;
char			tabs[16] = "																";
int			ind;
#define DPRINT	if(edfprint)iprint
#define DENTER	ind++;if(edfprint)iprint
#define DLEAVE	ind--

char *edf_statename[] = {
	[EdfUnused] =		"Unused",
	[EdfExpelled] =		"Expelled",
	[EdfAdmitted] =	"Admitted",
	[EdfIdle] =			"Idle",
	[EdfAwaitrelease] =	"Awaitrelease",
	[EdfReleased] =		"Released",
	[EdfRunning] =		"Running",
	[EdfExtra] =		"Extra",
	[EdfPreempted] =	"Preempted",
	[EdfBlocked] =		"Blocked",
	[EdfDeadline] =		"Deadline",
};

static Cycintr	schedpoint;		/* First scheduling point */
static Ticks	utilization;		/* Current utilization */
static int		initialized;
static uvlong	fasthz;	
static Ticks	now;
QLock		edfschedlock;		/* schedulability, held for
							 */
Lock			edflock;

Task			tasks[Maxtasks];
int			ntasks;
Resource		resources[Maxresources];
int			nresources;
int			edf_stateupdate;

enum{
	Deadline,	/* Invariant for schedulability test: Deadline < Release */
	Release,
};

static int earlierrelease(Task *t1, Task *t2) {return t1->r < t2->r;}
static int earlierdeadline(Task *t1, Task *t2) {return t1->d < t2->d;}

/* Tasks waiting for release, head earliest release time */
Taskq		qwaitrelease =	{{0}, nil, earlierrelease};

/* Released tasks waiting to run, head earliest deadline */
Taskq		qreleased	=	{{0}, nil, earlierdeadline};

/* Exhausted EDF tasks, append at end */
Taskq		qextratime;

/* Tasks admitted waiting for first release */
Taskq		qadmit;

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

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

static void		edf_intr(Ureg*, Cycintr*);
static void		edf_resched(Task *t);
static void		setΔ(void);
static void		testΔ(Task *thetask);
static char *	edf_testschedulability(Task *thetask);
static void		edf_setclock(void);

void
edf_init(void)
{
	if (initialized)
		return;
	ilock(&edflock);
	if (initialized){
		iunlock(&edflock);
		return;
	}
	fastticks(&fasthz);
	schedpoint.f = edf_intr;
	schedpoint.a = &schedpoint;
	schedpoint.when = 0;
	initialized = 1;
	iunlock(&edflock);
}

int
isedf(Proc *p)
{
	return p && p->task && p->task->state >= EdfIdle;
}

int
edf_anyready(void)
{
	/* If any edf tasks (with runnable procs in them) are released,
	 * at least one of them must be on the stack
	 */
	return edfstack[m->machno].head != nil;
}

static void
edfpush(Task *t)
{
	Taskq *q;

	DENTER("%.*sedfpush, %s, %d\n", ind, tabs, 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);
	}
	t->rnext = q->head;
	if(devsched) devsched(t, now, SRun);
	q->head = t;
	DLEAVE;
}

static Task*
edfpop(void)
{
	Task *t;
	Taskq *q;

	DENTER("%.*sedfpop\n", ind, tabs);
	q = edfstack + m->machno;
	if (t = q->head){
		assert(t->state == EdfRunning);
		q->head = t->rnext;
		t->rnext = nil;
		if (q->head){
			assert(q->head->state == EdfPreempted);
			q->head->state = EdfRunning;
			if(devsched) devsched(q->head, now, SRun);
		}
	}
	DLEAVE;
	return t;
}

static Task*
edfenqueue(Taskq *q, Task *t)
{
	Task *tt, **ttp;

	ilock(q);
	DENTER("%.*sedfenqueue, %s, %d\n", ind, tabs, edf_statename[t->state], t->runq.n);
	t->rnext = nil;
	if (q->head == nil) {
		q->head = t;
		DLEAVE;
		iunlock(q);
		return t;
	}
	SET(tt);
	for (ttp = &q->head; *ttp; ttp = &tt->rnext) {
		tt = *ttp;
		if (q->before && q->before(t, tt)) {
			t->rnext = tt;
			*ttp = t;
			break;
		}
	}
	if (*ttp == nil)
		tt->rnext = t;
	if (t != q->head)
		t = nil;
	DLEAVE;
	iunlock(q);
	return t;
}

static Task*
edfdequeue(Taskq *q)
{
	Task *t;

	DENTER("%.*sedfdequeue\n", ind, tabs);
	ilock(q);
	if (t = q->head){
		q->head = t->rnext;
		t->rnext = nil;
	}
	iunlock(q);
	DLEAVE;
	return t;
}

static void
edfqremove(Taskq *q, Task *t)
{
	Task **tp;

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

void
edf_block(Proc *p)
{
	Task *t, *pt;

	/* 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);

	assert(t);
	assert(t->state == EdfRunning);
	if (t->runq.n){
		/* There's another runnable proc in the running task, leave task where it is */
		iunlock(&edflock);
		DLEAVE;
		return;
	}
	pt = edfpop();
	assert(pt == t);
	t->state = EdfBlocked;
	if(devsched) devsched(t, now, SBlock);
	DLEAVE;
	iunlock(&edflock);
}

static void
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);
	SET(nt);
	if (p){
		nt = p->task;
		assert(nt);
		assert(nt->state == EdfRunning);
	}
	t = edfpop();

	if(p != nil && nt != t){
		DPRINT("%.*sedfdeadline, %s, %d\n", ind, tabs, 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);
	edf_resched(t);
	DLEAVE;
}

void
edf_deadline(Proc *p)
{
	DENTER("%.*sedf_deadline\n", ind, tabs);
	/* Task has reached its deadline */
	ilock(&edflock);
	now = fastticks(nil);
	edfdeadline(p, SYield);
	iunlock(&edflock);
	DLEAVE;
}

char *
edf_admit(Task *t)
{
	char *err;

	if (t->state != EdfExpelled)
		return "task state";	/* should never happen */
	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);
	now = fastticks(nil);

	t->state = EdfAdmitted;
	if (up->task == t){
		DPRINT("%.*sedf_admitting self\n", ind, tabs);
		/* 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);
		t->S = t->C;
		t->scheduled = now;
		t->state = EdfRunning;
		if(devsched) devsched(t, now, SRun);
		setΔ();
		assert(t->runq.n > 0 || (up && up->task == t));
		edfpush(t);
		edf_setclock();
	}else{
		if (t->runq.n){
			if (edfstack[m->machno].head == nil){
				t->state = EdfAdmitted;
				t->r = now;
				edf_release(t);
				setΔ();
				edf_resched(t);
			}else{
				edfenqueue(&qadmit, t);
			}
		}
	}
	DLEAVE;
	iunlock(&edflock);
	qunlock(&edfschedlock);
	return nil;
}

void
edf_expel(Task *t)
{
	Task *tt;

	qlock(&edfschedlock);
	ilock(&edflock);
	DENTER("%.*sedf_expel, %s, %d\n", ind, tabs, edf_statename[t->state], t->runq.n);
	now = fastticks(nil);
	switch(t->state){
	case EdfUnused:
	case EdfExpelled:
		/* That was easy */
		DLEAVE;
		iunlock(&edflock);
		qunlock(&edfschedlock);
		return;
	case EdfAdmitted:
	case EdfIdle:
		/* Just reset state */
		break;
	case EdfAwaitrelease:
		edfqremove(&qwaitrelease, t);
		break;
	case EdfReleased:
		edfqremove(&qreleased, t);
		break;
	case EdfRunning:
		/* Task must be expelling itself */
		tt = edfpop();
		assert(t == tt);
		break;
	case EdfExtra:
		edfqremove(&qextratime, t);
		break;
	case EdfPreempted:
		edfqremove(edfstack + m->machno, t);
		break;
	case EdfBlocked:
	case EdfDeadline:
		break;
	}
	t->state = EdfExpelled;
	if(devsched) devsched(t, now, SExpel);
	setΔ();
	DLEAVE;
	iunlock(&edflock);
	qunlock(&edfschedlock);
	return;
}

static void
edf_timer(void)
{
	Ticks used;
	Task *t;

	// If up is not set, we're running inside the scheduler
	// for non-real-time processes. 
	if (up && isedf(up)) {
		t = up->task;
		assert(t->scheduled > 0);
	
		used = now - t->scheduled;
		t->scheduled = now;

		if (t->r < now){
			if (t->S <= used)
				t->S = 0LL;
			else
				t->S -= used;
	
			if (t->d <= now || t->S == 0LL){
				/* Task has reached its deadline/slice, remove from queue */
				edfdeadline(up, SSlice);
				while (t = edfstack[m->machno].head){
					if (now < t->d)
						break;
					edfdeadline(nil, SSlice);
				}	
			}
		}
	}

	while((t = qwaitrelease.head) && t->r <= now){
		/* There's something waiting to be released and its time has come */
		edfdequeue(&qwaitrelease);
		edf_release(t);
	}
}

static void
edf_setclock(void)
{
	Ticks ticks;
	Task *t;

	DENTER("%.*sedf_setclock\n", ind, tabs);
	ticks = ~0ULL;
	if ((t = qwaitrelease.head) && t->r < ticks)
		ticks = t->r;
	if (t = edfstack[m->machno].head){
		if (t->d < ticks)
			ticks = t->d;
		if (now + t->S < ticks)
			ticks = now + t->S;
	}
	if (schedpoint.when > now && schedpoint.when <= ticks){
		DLEAVE;
		return;
	}
	if (schedpoint.when){
		DPRINT("%.*scycintrdel %T\n", ind, tabs, ticks2time(schedpoint.when));
		cycintrdel(&schedpoint);
		schedpoint.when = 0;
	}
	if (ticks <= now){
		DPRINT("%.*sedf_timer: %T too late\n", ind, tabs, ticks2time(now-ticks));
		ticks = now;
	}
	if (ticks != ~0ULL) {
		DPRINT("%.*sprogram timer in %T\n", ind, tabs, ticks2time(ticks-now));
		schedpoint.when = ticks;
		cycintradd(&schedpoint);
		DPRINT("%.*scycintradd %T\n", ind, tabs, ticks2time(schedpoint.when-now));
	}
	clockintrsched();
	DLEAVE;
}
	
static void
edf_intr(Ureg *, Cycintr *cy)
{

	DENTER("%.*sedf_intr\n", ind, tabs);
	/* Timer interrupt
	 * Timed events are:
	 * 1. release a task (look in qwaitrelease)
	 * 2. task reaches deadline
	 */
	now = fastticks(nil);

	assert(cy == &schedpoint && schedpoint.when <= now);

	if(active.exiting)
		return;

	ilock(&edflock);
	edf_timer();
	edf_setclock();
	iunlock(&edflock);
	DLEAVE;
	sched();
	splhi();
}

void
edf_bury(Proc *p)
{
	Task *t;
	Proc **pp;

	DPRINT("%.*sedf_bury\n", ind, tabs);
	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);
		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;
		}
	if (t->runq.head == nil){
		edfpop();
		t->state = EdfBlocked;
	}
	if (t->nproc == 0){
		assert(t->runq.head == nil);
		t->state = EdfIdle;
	}
	if(devsched) devsched(t, now, SBlock);
	p->task = nil;
	iunlock(&edflock);
}

void
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);
	if ((t = p->task) == nil){
		/* Must be a race */
		iunlock(&edflock);
		DPRINT("%.*sedf ready race, pid %lud\n", ind, tabs, p->pid);
		return;
	}
	p->rnext = 0;
	p->readytime = m->ticks;
	p->state = Ready;
	t->runq.n++;
	if(t->runq.tail){
		t->runq.tail->rnext = p;
		t->runq.tail = p;
	}else{
		t->runq.head = p;
		t->runq.tail = p;

		/* first proc to become runnable in this task */
		now = fastticks(nil);
		edf_resched(t);
	}
	DLEAVE;
	iunlock(&edflock);
}

static void
edf_resched(Task *t)
{
	Task *xt;

	DENTER("%.*sedf_resched, %s, %d\n", ind, tabs, 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);
		}
		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);
		if (t->state == EdfRunning)
			edfpop();

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

	/* There are runnable processes */

	switch (t->state){
	case EdfUnused:
		iprint("%.*sattempt to schedule unused task\n", ind, tabs);
	case EdfExpelled:
		DLEAVE;
		return;	/* Not admitted */
	case EdfIdle:
		/* task was idle, schedule release now or later */
		if (t->r < now){
			if (t->t < now)
				t->t = now + t->T;
			t->r = t->t;
		}
		edf_release(t);
		break;
	case EdfAwaitrelease:
	case EdfReleased:
	case EdfExtra:
	case EdfPreempted:
		/* dealt with by timer */
		break;
	case EdfAdmitted:
		/* test whether task can be started */
		if (edfstack[m->machno].head != nil){
			DLEAVE;
			return;
		}
		/* fall through */
	case EdfRunning:
		if (t->r <= now){
			if (t->t < now){
				DPRINT("%.*sedf_resched, rerelease\n", ind, tabs);
				/* Period passed, rerelease */
				t->r = now;
				xt = edfpop();
				assert(xt == t);
				edf_release(t);
				DLEAVE;
				return;
			}
			if (now < t->d){
				if (t->S > 0){
					DPRINT("%.*sedf_resched, resume\n", ind, tabs);
					/* Running, not yet at deadline, leave it */
					DLEAVE;
					return;
				}else
					t->d = now;
			}
			/* Released, but deadline is past, release at t->t */
			t->r = t->t;
		}
		DPRINT("%.*sedf_resched, schedule release\n", ind, tabs);
		xt = edfpop();
		assert(xt == t);
		edfenqueue(&qwaitrelease, t);
		t->state = EdfAwaitrelease;
		edf_setclock();
		break;
	case EdfBlocked:
	case EdfDeadline:
		if (t->r <= now){
			if (t->t < now){
				DPRINT("%.*sedf_resched, rerelease\n", ind, tabs);
				/* Period passed, rerelease */
				t->r = now;
				edf_release(t);
				DLEAVE;
				return;
			}
			if (now < t->d && (t->flags & Useblocking) == 0){
				if (t->S > 0){
					DPRINT("%.*sedf_resched, resume\n", ind, tabs);
					/* Released, not yet at deadline, release (again) */
					t->state = EdfReleased;
					edfenqueue(&qreleased, t);
					if(devsched) devsched(t, now, SResume);
					DLEAVE;
					return;
				}else
					t->d = now;
			}
			/* Released, but deadline is past, release at t->t */
			t->r = t->t;
		}
		DPRINT("%.*sedf_resched, schedule release\n", ind, tabs);
		edfenqueue(&qwaitrelease, t);
		t->state = EdfAwaitrelease;
		edf_setclock();
		break;
	}
	DLEAVE;
}

void
edf_release(Task *t)
{
	DENTER("%.*sedf_release, %s, %d\n", ind, tabs, 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);
	t->S = t->C;
	t->state = EdfReleased;
	edfenqueue(&qreleased, t);
	if(devsched) devsched(t, now, SRelease);
	edf_setclock();
	DLEAVE;
}

Proc *
edf_runproc(void)
{
	/* Return an edf proc to run or nil */
	
	Task *t, *nt;
	Proc *p;
//	Ticks when;
	static ulong nilcount;

	/* Figure out if the current proc should be preempted*/
	ilock(&edflock);
	assert(ind < nelem(tabs));
	now = fastticks(nil);

	/* first candidate is at the top of the stack of running procs */
	t = edfstack[m->machno].head;

	/* check out head of the release queue for a proc with a better deadline */
	nt = qreleased.head;

	if (t == nil && nt == nil){
		nilcount++;
		iunlock(&edflock);
		return nil;
	}
	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);
		edfdequeue(&qreleased);
		assert(nt->runq.n >= 1);
		edfpush(nt);
		nt->state = EdfRunning;
		t = nt;
		t->scheduled = now;
	}else{
		DPRINT("%.*sedf_runproc: current\n", ind, tabs);
	}

	assert (t->runq.n);

	/* Get first proc off t's run queue
	 * No need to lock runq, edflock always held to access runq
	 */
	t->state = EdfRunning;
	p = t->runq.head;
	if ((t->runq.head = p->rnext) == nil)
		t->runq.tail = nil;
	t->runq.n--;
	p->state = Scheding;
	if(p->mp != MACHP(m->machno))
		p->movetime = MACHP(0)->ticks + HZ/10;
	p->mp = MACHP(m->machno);
	edf_setclock();
	DLEAVE;
	iunlock(&edflock);
	return p;
}

static Lock	waitlock;

int
edf_waitlock(Lock *l)
{
	iprint("edf_waitlock\n");
	ilock(&waitlock);	/* can't afford normal locks here */
	if (l->key == 0){
		/* race on lock, don't block, just return */
		iunlock(&waitlock);
		return 0;
	}
	edf_block(up);
	up->rnext = l->edfwaiting;	/* enqueue on lock */
	l->edfwaiting = up;
	up->state = Scheding;
	up->lockwait = l;
	iunlock(&waitlock);
	return 1;
}

void
edf_releaselock(Lock *l)
{
	Proc *p;

	iprint("edf_releaselock\n");
	ilock(&waitlock);	/* can't afford normal locks here */
	if(l->edfwaiting == nil){
		iunlock(&waitlock);
		return;
	}
	p = l->edfwaiting;
	l->edfwaiting = p->rnext;
	assert(p->lockwait == l);
	if(p->state != Scheding)
		print("edf_releaselock: %s %lud %s\n", p->text, p->pid, statename[p->state]);
	p->lockwait = nil;
	iunlock(&waitlock);
	edf_ready(p);
}


/* Schedulability testing and its supporting routines */

static void
setΔ(void)
{
	Resource *r, **rr;
	Task **tt, *t;

	for (r = resources; r < resources + nelem(resources); r++){
		if (r->name == nil)
			continue;
		r->Δ = ~0LL;
		for (tt = r->tasks; tt < r->tasks + nelem(r->tasks); tt++)
			if (*tt && (*tt)->D < r->Δ)
				r->Δ = (*tt)->D;
	}
	for (t = tasks; t < tasks + nelem(tasks); t++){
		if (t->state < EdfIdle)
			continue;
		t->Δ = t->D;
		for (rr = t->res; rr < t->res + nelem(t->res); rr++)
			if (*rr && (*rr)->Δ < t->Δ)
				t->Δ = (*rr)->Δ;
	}
}

static void
testΔ(Task *thetask)
{
	Resource *r, **rr;
	Task **tt, *t;

	for (r = resources; r < resources + nelem(resources); r++){
		if (r->name == nil)
			continue;
		r->testΔ = ~0ULL;
		for (tt = r->tasks; tt < r->tasks + nelem(r->tasks); tt++)
			if (*tt && (*tt)->D < r->testΔ)
				r->testΔ = (*tt)->D;
	}
	for (t = tasks; t < tasks + nelem(tasks); t++){
		if (t->state <= EdfExpelled && t != thetask)
			continue;
		t->testΔ = t->D;
		for (rr = t->res; rr < t->res + nelem(t->res); rr++)
			if (*rr && (*rr)->testΔ < t->testΔ)
				t->testΔ = (*rr)->testΔ;
	}
}

static Ticks
blockcost(Ticks ticks, Task *thetask)
{
	Task *t;
	Ticks Cb;

	Cb = 0;
	for (t = tasks; t < tasks + Maxtasks; t++){
		if (t->state <= EdfExpelled && t != thetask)
			continue;
		if (t->testΔ <= ticks && ticks < t->D && Cb < t->C)
			Cb = t->C;
	}
	return Cb;
}

static Task *qschedulability;

static void
testenq(Task *t)
{
	Task *tt, **ttp;

	t->testnext = nil;
	if (qschedulability == nil) {
		qschedulability = t;
		return;
	}
	SET(tt);
	for (ttp = &qschedulability; *ttp; ttp = &tt->testnext) {
		tt = *ttp;
		if (t->testtime < tt->testtime
		|| (t->testtime == tt->testtime && t->testtype < tt->testtype)){
			t->testnext = tt;
			*ttp = t;
			return;
		}
	}
	assert(tt->testnext == nil);
	tt->testnext = t;
}

static char *
edf_testschedulability(Task *thetask)
{
	Task *t;
	Ticks H, G, Cb, ticks;
	int steps;

	/* initialize */
	testΔ(thetask);
	if (thetask && (thetask->flags & Verbose))
		pprint("schedulability test\n");
	qschedulability = nil;
	for (t = tasks; t < tasks + Maxtasks; 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);
		testenq(t);
	}
	H=0;
	G=0;
	ticks = 0;
	for(steps = 0; steps < Maxsteps; steps++){
		t = qschedulability;
		qschedulability = t->testnext;
		ticks = t->testtime;
		switch (t->testtype){
		case Deadline:
			H += t->C;
			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,
					ticks2time(t->C), ticks2time(H), ticks2time(Cb));
			if (H+Cb>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",
					steps, ticks2time(ticks), t - tasks,
					ticks2time(t->C), ticks2time(G));
			if(ticks && G <= ticks)
				return nil;
			G += t->C;
			t->testtime += t->D;
			t->testtype = Deadline;
			testenq(t);
			break;
		default:
			assert(0);
		}
	}
	return "probably not schedulable";
}

static uvlong
uvmuldiv(uvlong x, ulong num, ulong den)
{
	/* multiply, then divide, avoiding overflow */
	uvlong hi;

	hi = (x & 0xffffffff00000000LL) >> 32;
	x &= 0xffffffffLL;
	hi *= num;
	return (x*num + (hi%den << 32)) / den + (hi/den << 32);
}

Time
ticks2time(Ticks ticks)
{
	assert(ticks >= 0);
	return uvmuldiv(ticks, Onesecond, fasthz);
}

Ticks
time2ticks(Time time)
{
	assert(time >= 0);
	return uvmuldiv(time, fasthz, Onesecond);
}
.
## diffname port/edf.c 2002/0316
## diff -e /n/emeliedump/2002/0315/sys/src/9/port/edf.c /n/emeliedump/2002/0316/sys/src/9/port/edf.c
738c
		DPRINT("%.*s%d edf_runproc: current\n", ind, tabs, m->machno);
.
730c
		DPRINT("%.*s%d edf_runproc: released\n", ind, tabs, m->machno);
.
696c
	if(devrt) devrt(t, now, SRelease);
.
692c
	if(devrt) devrt(t, t->d, SDeadline);
.
688c
	DENTER("%.*s%d edf_release, %s, %d\n", ind, tabs, m->machno, edf_statename[t->state], t->runq.n);
.
676c
		DPRINT("%.*s%d edf_resched, schedule release\n", ind, tabs, m->machno);
.
667c
					if(devrt) devrt(t, now, SResume);
.
663c
					DPRINT("%.*s%d edf_resched, resume\n", ind, tabs, m->machno);
.
654c
				DPRINT("%.*s%d edf_resched, rerelease\n", ind, tabs, m->machno);
.
643c
		DPRINT("%.*s%d edf_resched, schedule release\n", ind, tabs, m->machno);
.
633c
					DPRINT("%.*s%d edf_resched, resume\n", ind, tabs, m->machno);
.
622c
				DPRINT("%.*s%d edf_resched, rerelease\n", ind, tabs, m->machno);
.
593c
		iprint("%.*s%d attempt to schedule unused task\n", ind, tabs, m->machno);
.
583c
			if(devrt) devrt(t, now, SBlock);
.
577c
		DPRINT("%.*s%d edf_resched, nothing runnable\n", ind, tabs, m->machno);
.
570c
			if(devrt) devrt(t, now, SBlock);
.
565c
	DENTER("%.*s%d edf_resched, %s, %d\n", ind, tabs, m->machno, edf_statename[t->state], t->runq.n);
.
538c
		DPRINT("%.*s%d edf ready race, pid %lud\n", ind, tabs, m->machno, p->pid);
.
534c
	DENTER("%.*s%d edf_ready, %s, %d\n", ind, tabs, m->machno, edf_statename[p->task->state], p->task->runq.n);
.
523c
	if(devrt) devrt(t, now, SBlock);
.
506c
		DPRINT("%.*s%d edf bury race, pid %lud\n", ind, tabs, m->machno, p->pid);
.
500c
	DPRINT("%.*s%d edf_bury\n", ind, tabs, m->machno);
.
472c
	DENTER("%.*s%d edf_intr\n", ind, tabs, m->machno);
.
462c
		DPRINT("%.*s%d cycintradd %T\n", ind, tabs, m->machno, ticks2time(schedpoint.when-now));
.
459c
		DPRINT("%.*s%d program timer in %T\n", ind, tabs, m->machno, ticks2time(ticks-now));
.
455c
		DPRINT("%.*s%d edf_timer: %T too late\n", ind, tabs, m->machno, ticks2time(now-ticks));
.
450c
		DPRINT("%.*s%d cycintrdel %T\n", ind, tabs, m->machno, ticks2time(schedpoint.when));
.
435c
	DENTER("%.*s%d edf_setclock\n", ind, tabs, m->machno);
.
381c
	if(devrt) devrt(t, now, SExpel);
.
345c
	DENTER("%.*s%d edf_expel, %s, %d\n", ind, tabs, m->machno, edf_statename[t->state], t->runq.n);
.
314c
		if(devrt) devrt(t, now, SRun);
.
310c
		if(devrt) devrt(t, t->d, SDeadline);
.
305c
		DPRINT("%.*s%d edf_admitting self\n", ind, tabs, m->machno);
.
303a
	if(devrt) devrt(t, t->d, SAdmit);
.
300c
	DENTER("%.*s%d edf_admit, %s, %d\n", ind, tabs, m->machno, edf_statename[t->state], t->runq.n);
.
293a

	/* 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";

.
278c
	DENTER("%.*s%d edf_deadline\n", ind, tabs, m->machno);
.
270c
	if(devrt) devrt(t, now, why);
.
263c
		DPRINT("%.*s%d edfdeadline, %s, %d\n", ind, tabs, m->machno, edf_statename[p->task->state], p->task->runq.n);
.
253c
	DENTER("%.*s%d edfdeadline, %s, %d\n", ind, tabs, m->machno, edf_statename[p->task->state], p->task->runq.n);
.
242c
	if(devrt) devrt(t, now, SBlock);
.
229c
	DENTER("%.*s%d edf_block, %s, %d\n", ind, tabs, m->machno, edf_statename[t->state], t->runq.n);
.
208c
	DENTER("%.*s%d edfqremove, %s, %d\n", ind, tabs, m->machno, edf_statename[t->state], t->runq.n);
.
191c
	DENTER("%.*s%d edfdequeue\n", ind, tabs, m->machno);
.
160c
	DENTER("%.*s%d edfenqueue, %s, %d\n", ind, tabs, m->machno, edf_statename[t->state], t->runq.n);
.
147c
			if(devrt) devrt(q->head, now, SRun);
.
138c
	DENTER("%.*s%d edfpop\n", ind, tabs, m->machno);
.
127c
	if(devrt) devrt(t, now, SRun);
.
124c
		if(devrt) devrt(q->head, now, SPreempt);
.
118c
	DENTER("%.*s%d edfpush, %s, %d\n", ind, tabs, m->machno, edf_statename[t->state], t->runq.n);
.
71c
void (*devrt)(Task*, Ticks, int);
.
8c
#include	"../port/devrealtime.h"
.
## diffname port/edf.c 2002/0319
## diff -e /n/emeliedump/2002/0316/sys/src/9/port/edf.c /n/emeliedump/2002/0319/sys/src/9/port/edf.c
779a
	Task *t;

.
## diffname port/edf.c 2002/0320
## diff -e /n/emeliedump/2002/0319/sys/src/9/port/edf.c /n/emeliedump/2002/0320/sys/src/9/port/edf.c
988a
	if (fasthz == 0)
		fastticks(&fasthz);
.
920c
	testdelta(thetask);
.
880c
		if (t->testDelta <= ticks && ticks < t->D && Cb < t->C)
.
865,866c
			if (*rr && (*rr)->testDelta < t->testDelta)
				t->testDelta = (*rr)->testDelta;
.
863c
		t->testDelta = t->D;
.
857,858c
			if (*tt && (*tt)->D < r->testDelta)
				r->testDelta = (*tt)->D;
.
855c
		r->testDelta = ~0ULL;
.
847c
testdelta(Task *thetask)
.
841,842c
			if (*rr && (*rr)->Delta < t->Delta)
				t->Delta = (*rr)->Delta;
.
839c
		t->Delta = t->D;
.
833,834c
			if (*tt && (*tt)->D < r->Delta)
				r->Delta = (*tt)->D;
.
831c
		r->Delta = ~0LL;
.
823c
setdelta(void)
.
780,781d
742c
	if (nt && (t == nil || (nt->d < t->d && nt->D < t->Delta))){
.
396c
	setdelta();
.
339c
				setdelta();
.
329c
		setdelta();
.
263c
		iprint("edfdeadline, %s, %d\n", edf_statename[p->task->state], p->task->runq.n);
.
258d
231,232d
228a
	assert(t);
	if (t->state != EdfRunning){
		/* called by a proc just joining the task */
		iunlock(&edflock);
		return;
	}
.
75,76c
static void		setdelta(void);
static void		testdelta(Task *thetask);
.
## diffname port/edf.c 2002/0321
## diff -e /n/emeliedump/2002/0320/sys/src/9/port/edf.c /n/emeliedump/2002/0321/sys/src/9/port/edf.c
261c
		if (nt == nil || nt->state != EdfRunning)
			return;
.
## diffname port/edf.c 2002/0322
## diff -e /n/emeliedump/2002/0321/sys/src/9/port/edf.c /n/emeliedump/2002/0322/sys/src/9/port/edf.c
805d
784d
774d
756c
		DPRINT("%d edf_runproc: current\n", m->machno);
.
748c
		DPRINT("%d edf_runproc: released\n", m->machno);
.
745c
	DPRINT("edf_runproc %lud\n", nilcount);
.
731d
716d
706c
	DPRINT("%d edf_release, %s, %d\n", m->machno, edf_statename[t->state], t->runq.n);
.
700d
694c
		DPRINT("%d edf_resched, schedule release\n", m->machno);
.
686d
681c
					DPRINT("%d edf_resched, resume\n", m->machno);
.
676d
672c
				DPRINT("%d edf_resched, rerelease\n", m->machno);
.
661c
		DPRINT("%d edf_resched, schedule release\n", m->machno);
.
653d
651c
					DPRINT("%d edf_resched, resume\n", m->machno);
.
646d
640c
				DPRINT("%d edf_resched, rerelease\n", m->machno);
.
633d
613d
611c
		iprint("%d attempt to schedule unused task\n", m->machno);
.
603d
595c
		DPRINT("%d edf_resched, nothing runnable\n", m->machno);
.
590d
583c
	DPRINT("%d edf_resched, %s, %d\n", m->machno, edf_statename[t->state], t->runq.n);
.
574d
556c
		DPRINT("%d edf ready race, pid %lud\n", m->machno, p->pid);
.
552c
	DPRINT("%d edf_ready, %s, %d\n", m->machno, edf_statename[p->task->state], p->task->runq.n);
.
524c
		DPRINT("%d edf bury race, pid %lud\n", m->machno, p->pid);
.
518c
	DPRINT("%d edf_bury\n", m->machno);
.
507d
490c
	DPRINT("%d edf_intr\n", m->machno);
.
483d
480c
		DPRINT("%d cycintradd %T\n", m->machno, ticks2time(schedpoint.when-now));
.
477c
		DPRINT("%d program timer in %T\n", m->machno, ticks2time(ticks-now));
.
473c
		DPRINT("%d edf_timer: %T too late\n", m->machno, ticks2time(now-ticks));
.
468c
		DPRINT("%d cycintrdel %T\n", m->machno, ticks2time(schedpoint.when));
.
464d
453c
	DPRINT("%d edf_setclock\n", m->machno);
.
401d
369d
363c
	DPRINT("%d edf_expel, %s, %d\n", m->machno, edf_statename[t->state], t->runq.n);
.
350d
323c
		DPRINT("%d edf_admitting self\n", m->machno);
.
317c
	DPRINT("%d edf_admit, %s, %d\n", m->machno, edf_statename[t->state], t->runq.n);
.
288d
282c
	DPRINT("%d edf_deadline\n", m->machno);
.
276d
257c
	DPRINT("%d edfdeadline, %s, %d\n", m->machno, edf_statename[p->task->state], p->task->runq.n);
.
247d
240d
235c
	DPRINT("%d edf_block, %s, %d\n", m->machno, edf_statename[t->state], t->runq.n);
.
217d
212d
208c
	DPRINT("%d edfqremove, %s, %d\n", m->machno, edf_statename[t->state], t->runq.n);
.
198d
191c
	DPRINT("%d edfdequeue\n", m->machno);
.
181d
164d
160c
	DPRINT("%d edfenqueue, %s, %d\n", m->machno, edf_statename[t->state], t->runq.n);
.
150d
138c
	DPRINT("%d edfpop\n", m->machno);
.
129d
118c
	DPRINT("%d edfpush, %s, %d\n", m->machno, edf_statename[t->state], t->runq.n);
.
16,17d
13,14d
## diffname port/edf.c 2002/0327
## diff -e /n/emeliedump/2002/0322/sys/src/9/port/edf.c /n/emeliedump/2002/0327/sys/src/9/port/edf.c
740c

	when = now + t->S;
	if (t->d < when)
		when = t->d;

	if (cycdeadline.when){
		if(cycdeadline.when == when){
			iunlock(&edflock);
			return p;
		}
		DPRINT("%d cycintrdel %T\n", m->machno, ticks2time(cycdeadline.when));
		cycintrdel(&cycdeadline);
	}
	if (when <= now){
		DPRINT("%d edf_timer: %T too late\n", m->machno, ticks2time(now-when));
		when = now;
	}
	DPRINT("%d program timer in %T\n", m->machno, ticks2time(when-now));
	cycdeadline.when = when;
	cycintradd(&cycdeadline);
	DPRINT("%d cycintradd %T\n", m->machno, ticks2time(cycdeadline.when-now));
	clockintrsched();
.
694c
	Ticks when;
.
684d
664,667c
		schedrelease(t);
.
636,638c
		schedrelease(t);
.
633d
421,485d
394a
	DPRINT("%d edfdeadlineintr\n", m->machno);
	/* Task reached deadline
	 */
	now = fastticks(nil);

	if(active.exiting)
		return;

	ilock(&edflock);
.
391a
	Task *t;

	now = fastticks(nil);

	if(active.exiting)
		return;

	ilock(&edflock);
	while((t = qwaitrelease.head) && t->r <= now){
		/* There's something waiting to be released and its time has come */
		edfdequeue(&qwaitrelease);
		edf_release(t);
	}
	iunlock(&edflock);
	sched();
	splhi();
}

static void
edfdeadlineintr(Ureg *, Cycintr *cy)
{
.
390c
edfreleaseintr(void)
.
361c
		if (edfqremove(&qwaitrelease, t))
			edfreleasetimer();
.
321d
258c
	if (cycdeadline.when){
		cycintrdel(&cycdeadline);
		cycdeadline.when = 0;
		clockintrsched();
	}
.
210a
edfreleasetimer(void)
{
	Task *t;

	t = qwaitrelease.head;
	DPRINT("edf_schedrelease clock\n");
	if (cycrelease.when == t->r)
		return;
	if (cycrelease.when){
		DPRINT("%d cycintrdel %T\n", m->machno, ticks2time(cycrelease.when));
		cycintrdel(&cycrelease);
	}
	cycrelease.when = t->r;
	if (cycrelease.when <= now){
		DPRINT("%d edf_timer: %T too late\n", m->machno, ticks2time(now-ticks));
		cycrelease.when = now;
	}
	DPRINT("%d program timer in %T\n", m->machno, ticks2time(ticks-now));
	cycintradd(&cycrelease);
	DPRINT("%d cycintradd %T\n", m->machno, ticks2time(cycrelease.when-now));
	clockintrsched();
}

void
edf_schedrelease(Task *t)
{
	Ticks ticks;

	DPRINT("%d edf_schedrelease\n", m->machno);
	/* Schedule a task for release */
	t->state = EdfAwaitrelease;
	if (edfenqueue(&qwaitrelease, t))
		edfreleasetimer();
}

void
.
209a
			
.
204c
			return t;
.
202a
			t = (tp == &q->head) ? q->head : nil;
.
193c
static Task*
.
87,89c
	cycdeadline.f = edfdeadlineintr;
	cycdeadline.a = &cycdeadline;
	cycdeadline.when = 0;
	cycrelease.f = edfreleaseintr;
	cycrelease.a = &cycrelease;
	cycrelease.when = 0;
.
74c
static void		edfreleaseintr(void);
.
69c
static void		edfdeadlineintr(Ureg*, Cycintr*);
.
29c
static Cycintr	cycdeadline;		/* Time of next deadline */
static Cycintr	cycrelease;		/* Time of next release */

.
## diffname port/edf.c 2002/0328
## diff -e /n/emeliedump/2002/0327/sys/src/9/port/edf.c /n/emeliedump/2002/0328/sys/src/9/port/edf.c
770,810d
765d
758,762d
755d
749a
	if (when < now){
		DPRINT("%d edf_timer: %T too late\n", m->machno, ticks2time(now-when));
		when = now;
	}
.
673c
		t->state = EdfAwaitrelease;
		if (edfenqueue(&qwaitrelease, t))
			edfreleasetimer();
.
647c
		t->state = EdfAwaitrelease;
		if (edfenqueue(&qwaitrelease, t))
			edfreleasetimer();
.
474a
		now = fastticks(nil);

.
467a
	cycdeadline.when = 0;

.
464,466d
459a
	/* Task reached deadline */

.
458c
edfdeadlineintr(Ureg*, Cycintr*)
.
449a
		edfreleasetimer();
.
446a
	now = fastticks(nil);
.
442a
	cycrelease.when = 0;

.
441c
	DPRINT("%d edfreleaseintr\n", m->machno);
.
437c
edfreleaseintr(Ureg*, Cycintr*)
.
242,253d
237d
234,235d
231,232c
	if (cycrelease.when <= now)
.
229d
226,227c
	DPRINT("edfreleasetimer clock\n");
	if (cycrelease.when)
.
222,224c
	if ((t = qwaitrelease.head) == nil)
.
213a
	return nil;
.
76c
static void		edfreleaseintr(Ureg *, Cycintr *cy);
static void		edfdeadlineintr(Ureg*, Cycintr*);
.
71d
36,37c
QLock		edfschedlock;
.
## diffname port/edf.c 2002/0329
## diff -e /n/emeliedump/2002/0328/sys/src/9/port/edf.c /n/emeliedump/2002/0329/sys/src/9/port/edf.c
484a
		if (up->nlocks)
			iprint("have %lud locks at deadline\n", up->nlocks);
.
212d
208d
202d
193d
188d
178d
162d
157d
32d
## diffname port/edf.c 2002/0330
## diff -e /n/emeliedump/2002/0329/sys/src/9/port/edf.c /n/emeliedump/2002/0330/sys/src/9/port/edf.c
443a
	clockintrsched();
.
442a
	cycintrdel(&cycdeadline);
.
415a
	clockintrsched();
.
414a
	cycintrdel(&cycrelease);
.
## diffname port/edf.c 2002/0404
## diff -e /n/emeliedump/2002/0330/sys/src/9/port/edf.c /n/emeliedump/2002/0404/sys/src/9/port/edf.c
872d
480,481d
## diffname port/edf.c 2002/0405
## diff -e /n/emeliedump/2002/0404/sys/src/9/port/edf.c /n/emeliedump/2002/0405/sys/src/9/port/edf.c
749c
	timeradd(&cycdeadline);
.
746c
		timerdel(&cycdeadline);
.
445c
	timerdel(&cycdeadline);
.
436c
edfdeadlineintr(Ureg*, Timer*)
.
415c
	timerdel(&cycrelease);
.
409c
edfreleaseintr(Ureg*, Timer*)
.
274c
		timerdel(&cycdeadline);
.
221c
	timeradd(&cycrelease);
.
217c
		timerdel(&cycrelease);
.
73,74c
static void		edfreleaseintr(Ureg *, Timer *cy);
static void		edfdeadlineintr(Ureg*, Timer*);
.
29,30c
static Timer	cycdeadline;		/* Time of next deadline */
static Timer	cycrelease;		/* Time of next release */
.
## diffname port/edf.c 2002/0410
## diff -e /n/emeliedump/2002/0405/sys/src/9/port/edf.c /n/emeliedump/2002/0410/sys/src/9/port/edf.c
848c
edftestschedulability(Task *thetask)
.
748,750c
	deadlinetimer[m->machno].when = when;
	timeradd(&deadlinetimer[m->machno]);
.
746c
		timerdel(&deadlinetimer[m->machno]);
.
741,742c
	if (deadlinetimer[m->machno].when){
		if(deadlinetimer[m->machno].when == when){
.
738c
		DPRINT("%d edftimer: %T too late\n", m->machno, ticks2time(now-when));
.
717c
runt:
.
715c
		DPRINT("%d edfrunproc: current\n", m->machno);
.
707c
		DPRINT("%d edfrunproc: released\n", m->machno);
.
705a
		if (conf.nmach > 1){
			for (i = 0; i < conf.nmach; i++){
				if (i == m->machno)
					continue;
				xt = edfstack[i].head;
				if (xt && xt->Delta <= nt->D){
					DPRINT("%d edfrunproc: interprocessor conflict, run current\n", m->machno);
					if (t)
						goto runt;
					nilcount++;
					iunlock(&edflock);
					return nil;
				}
			}
		}
.
704c
	DPRINT("edfrunproc %lud\n", nilcount);
.
687a
	int i;
.
684c
	Task *t, *nt, *xt;
.
680c
edfrunproc(void)
.
668c
	DPRINT("%d edfrelease, %s, %d\n", m->machno, edfstatename[t->state], t->runq.n);
.
666c
edfrelease(Task *t)
.
646c
					DPRINT("%d edfresched, resume\n", m->machno);
.
641c
				edfrelease(t);
.
638c
				DPRINT("%d edfresched, rerelease\n", m->machno);
.
619c
					DPRINT("%d edfresched, resume\n", m->machno);
.
614c
				edfrelease(t);
.
609c
				DPRINT("%d edfresched, rerelease\n", m->machno);
.
592c
		edfrelease(t);
.
567c
		DPRINT("%d edfresched, nothing runnable\n", m->machno);
.
556c
	DPRINT("%d edfresched, %s, %d\n", m->machno, edfstatename[t->state], t->runq.n);
.
552c
edfresched(Task *t)
.
546c
		edfresched(t);
.
526c
	DPRINT("%d edfready, %s, %d\n", m->machno, edfstatename[p->task->state], p->task->runq.n);
.
521c
edfready(Proc *p)
.
492c
	DPRINT("%d edfbury\n", m->machno);
.
487c
edfbury(Proc *p)
.
476c
					deadline(nil, SSlice);
.
472c
				deadline(up, SSlice);
.
445,447c
	timerdel(&deadlinetimer[m->machno]);
	deadlinetimer[m->machno].when = 0;
.
428c
		edfrelease(t);
.
415,417c
	timerdel(&releasetimer[m->machno]);
	releasetimer[m->machno].when = 0;
.
365c
	DPRINT("%d edfexpel, %s, %d\n", m->machno, edfstatename[t->state], t->runq.n);
.
359c
edfexpel(Task *t)
.
347,349c
				edfresched(t);
.
345c
				edfrelease(t);
.
339a
		if (deadlinetimer[m->machno].when)
			timerdel(&deadlinetimer[m->machno]);
		deadlinetimer[m->machno].when = t->d;
		timeradd(&deadlinetimer[m->machno]);
.
327c
		DPRINT("%d edfadmitting self\n", m->machno);
.
321c
	DPRINT("%d edfadmit, %s, %d\n", m->machno, edfstatename[t->state], t->runq.n);
.
316c
	if (err = edftestschedulability(t)){
.
296c
edfadmit(Task *t)
.
291c
	deadline(p, SYield);
.
287c
	DPRINT("%d edfdeadline\n", m->machno);
.
285c
edfdeadline(Proc *p)
.
281c
	edfresched(t);
.
273,276c
	if (deadlinetimer[m->machno].when){
		timerdel(&deadlinetimer[m->machno]);
		deadlinetimer[m->machno].when = 0;
.
269c
		iprint("deadline, %s, %d\n", edfstatename[p->task->state], p->task->runq.n);
.
259c
	DPRINT("%d deadline, %s, %d\n", m->machno, edfstatename[p->task->state], p->task->runq.n);
.
254c
deadline(Proc *p, SEvent why)
.
239c
	DPRINT("%d edfblock, %s, %d\n", m->machno, edfstatename[t->state], t->runq.n);
.
226c
edfblock(Proc *p)
.
216,222c
	if (releasetimer[m->machno].when)
		timerdel(&releasetimer[m->machno]);
	releasetimer[m->machno].when = t->r;
	if (releasetimer[m->machno].when <= now)
		releasetimer[m->machno].when = now;
	timeradd(&releasetimer[m->machno]);
.
196c
	DPRINT("%d edfqremove, %s, %d\n", m->machno, edfstatename[t->state], t->runq.n);
.
156c
	DPRINT("%d edfenqueue, %s, %d\n", m->machno, edfstatename[t->state], t->runq.n);
.
117c
	DPRINT("%d edfpush, %s, %d\n", m->machno, edfstatename[t->state], t->runq.n);
.
104c
edfanyready(void)
.
87,92c
	for (i = 0; i < conf.nmach; i++){
		deadlinetimer[i].f = edfdeadlineintr;
		deadlinetimer[i].a = &deadlinetimer[i];
		deadlinetimer[i].when = 0;
		releasetimer[i].f = edfreleaseintr;
		releasetimer[i].a = &releasetimer[i];
		releasetimer[i].when = 0;
	}
.
78a
	int i;

.
77c
edfinit(void)
.
74a
static char *	edftestschedulability(Task *thetask);
.
72d
69c
static void		edfresched(Task *t);
.
61,63d
42c
int			edfstateupdate;
.
29,30c
static Timer	deadlinetimer[MAXMACH];	/* Time of next deadline */
static Timer	releasetimer[MAXMACH];		/* Time of next release */
.
15c
char *edfstatename[] = {
.
## diffname port/edf.c 2002/0411
## diff -e /n/emeliedump/2002/0410/sys/src/9/port/edf.c /n/emeliedump/2002/0411/sys/src/9/port/edf.c
688a
	if (edfstack[m->machno].head == nil && qreleased.head== nil){
		// quick way out
		nilcount++;
		return nil;
	}
.
107,110c
	return edfstack[m->machno].head || qreleased.head;
.
## diffname port/edf.c 2002/0420
## diff -e /n/emeliedump/2002/0411/sys/src/9/port/edf.c /n/emeliedump/2002/0420/sys/src/9/port/edf.c
467a
				if (t->S > 0LL)
					misseddeadlines++;
.
42a
int			misseddeadlines;
.
## diffname port/edf.c 2002/0503
## diff -e /n/emeliedump/2002/0420/sys/src/9/port/edf.c /n/emeliedump/2002/0503/sys/src/9/port/edf.c
743a
	t->periods++;
.
733a
		t->periods++;
.
731d
470a
				}
.
469c
				if (t->d <= now){
					t->missed++;
.
459a
		t->total += used;
.
332a
		t->periods++;
.
274a
	used = now - t->scheduled;
	t->S -= used;
	t->scheduled = now;
	t->total += used;
	t->aged = (t->aged*31 + t->C - t->S) >> 5;
.
254a
	Ticks used;
.
## diffname port/edf.c 2002/0704
## diff -e /n/emeliedump/2002/0503/sys/src/9/port/edf.c /n/emeliedump/2002/0704/sys/src/9/port/edf.c
963a

Edfinterface realedf = {
	.isedf		= isedf,
	.edfbury		= edfbury,
	.edfanyready	= edfanyready,
	.edfready		= edfready,
	.edfrunproc	= edfrunproc,
	.edfblock		= edfblock,
	.edfinit		= edfinit,
	.edfexpel		= edfexpel,
	.edfadmit		= edfadmit,
	.edfdeadline	= edfdeadline,
};
.
688c
static Proc *
.
674c
static void
.
529c
static void
.
495c
static void
.
364c
static void
.
298c
static char *
.
287c
static void
.
223c
static void
.
105c
static int
.
99c
static int
.
74c
static void
.
51a
static void	edfrelease(Task *t);
.
## diffname port/edf.c 2002/0831
## diff -e /n/emeliedump/2002/0704/sys/src/9/port/edf.c /n/emeliedump/2002/0831/sys/src/9/port/edf.c
922c
					steps, ticks2time(ticks), t->taskno,
.
911c
					steps, ticks2time(ticks), t->taskno,
.
896c
			pprint("\tInit: enqueue task %lud\n", t->taskno);
.
890c
	for (l = tasks.next; l; l = l->next){
		t = l->i;
		assert(t);
.
883a
	List *l;
.
843c
	for (lt = tasks.next; lt ; lt = lt->next){
		t = lt->i;
		assert(t);
.
840a
	List *lt;
.
830,832c
		for (lr = t->res.next; lr; lr = lr->next){
			r = lr->i;
			assert(r);
			if (r->testDelta < t->testDelta)
				t->testDelta = r->testDelta;
		}
.
826c
	for (lt = tasks.next; lt ; lt = lt->next){
		t = lt->i;
		assert(t);
.
822,824c
		for (lt = r->tasks.next; lt; lt = lt->next){
			t = lt->i;
			assert(t);
			if (t->D < r->testDelta)
				r->testDelta = t->D;
		}
.
818,820c
	for (lr = resources.next; lr; lr = lr->next){
		r = lr->i;
		assert(r);
.
815,816c
	Resource *r;
	Task *t;
	List *lr, *lt;
.
806,808c
		for (lr = t->res.next; lr; lr = lr->next){
			r = lr->i;
			assert(r);
			if (r->Delta < t->Delta)
				t->Delta = r->Delta;
		}
.
802c
	for (lt = tasks.next; lt ; lt = lt->next){
		t = lt->i;
		assert(t);
.
798,800c
		for (lt = r->tasks.next; lt; lt = lt->next){
			t = lt->i;
			assert(t);
			if (t->D < r->Delta)
				r->Delta = t->D;
		}
.
794,796c
	for (lr = resources.next; lr; lr = lr->next){
		r = lr->i;
		assert(r);
.
791,792c
	Resource *r;
	Task *t;
	List *lr, *lt;
.
567c
	if (t->procs.n == 0){
.
521c
	if (t->procs.n == 0){
.
512,516c
	delist(&t->procs, p);
.
500d
411d
379d
370c
	/* Called with edfschedlock held */
.
361c
	qlock(&edfschedlock);
.
324a
	qunlock(&edfschedlock);
.
321d
319d
303a
	/* Called with edfschedlock held */
.
38,41c
Head		tasks;
Head		resources;
.
34a
/* Edfschedlock protects modification of sched params, including resources */
.
## diffname port/edf.c 2002/0912
## diff -e /n/emeliedump/2002/0831/sys/src/9/port/edf.c /n/emeliedump/2002/0912/sys/src/9/port/edf.c
736d
## diffname port/edf.c 2002/0927
## diff -e /n/emeliedump/2002/0912/sys/src/9/port/edf.c /n/emeliedump/2002/0927/sys/src/9/port/edf.c
991a
	.resacquire	= resacquire,
	.resrelease	= resrelease,
.
974,978c
	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);
.
968,972c
	Ticks now, when, used;
	CSN *c;
.
965,966c
static void
resrelease(Task *t)
.
959,962c
	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 */
.
956,957c
	Ticks now, when, used;
.
953,954c
static void
resacquire(Task *t, CSN *c)
.
940a
			}
.
939c
			if(ticks && G <= ticks){
				if (thetask && (thetask->flags & Verbose))
					pprint("task %d schedulable: G=%T <= ticks=%T\n",
						thetask->taskno, ticks2time(G), ticks2time(ticks));
.
936c
				pprint("\tStep %3d, Ticks %T, task %d, release, G  %T, C%T\n",
.
929a
			}
.
928c
			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));
.
925c
				pprint("\tStep %3d, Ticks %T, task %d, deadline, H += %T → %T, Cb = %T\n",
.
923c
			Cb = blockcost(ticks, t, thetask);
.
911c
			pprint("\tInit: enqueue task %d\n", t->taskno);
.
901c
		pprint("schedulability test for task %d\n", thetask->taskno);
.
864,865d
860a
	DEBUG("Cb = %T\n", ticks2time(Cb));
.
853,859c
	/* 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, ");
.
849,850d
847a
	Ticks Cb, Cbt;
	List *l;
	Resource *r;
	CSN *c, *lc;
	int R;
.
846c
blockcost(Ticks ticks, Task *task, Task *thetask)
.
840a
			DEBUG("Task %d Resource %s: tΔ = %T\n",
				t->taskno, r->name, ticks2time(r->testDelta));
.
839c
			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)
.
835,837c
		t->testDelta = Infinity;
		for (c = (CSN*)t->csns.next; c; c = (CSN*)c->next){
			r = c->i;
.
830,831c

	/* Enumerate the critical sections */
	for (l = tasks.next; l ; l = l->next){
		t = l->i;
.
828a
		if (R)
			r->testDelta = Infinity;	/* Read-only resource, no exclusion */
		DEBUG("tΔ = %T\n", ticks2time(r->testDelta));
.
827a
				DEBUG("%d→%T ", t->taskno, ticks2time(t->D));
			}
			if (lt->R == 0){
				DEBUG("%d→X ", t->taskno);
				R = 0;
			}
.
826c
			if (t->D < r->testDelta){
.
822,823c
		DEBUG("Resource %s: ", r->name);
		r->testDelta = Infinity;
		R = 1;
		for (lt = (TaskLink*)r->tasks.next; lt; lt = (TaskLink*)lt->next){
.
817c
	int R;
	List *lr, *l;
	TaskLink *lt;
	CSN *c;
.
806c
			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)
.
802,804c
		t->Delta = Infinity;
		for (c = (CSN*)t->csns.next; c; c = (CSN*)c->next){
			r = c->i;
.
800c
		if (t->state <= EdfExpelled)
.
797,798c

	/* Enumerate the critical sections */
	for (l = tasks.next; l ; l = l->next){
		t = l->i;
.
795a
		if (R)
			r->Delta = Infinity;	/* Read-only resource, no exclusion */
.
794a
			}
			if (lt->R == 0){
				R = 0;
			}
.
793c
			if (t->D < r->Delta){
.
789,790c
		r->Delta = Infinity;
		R = 1;
		for (lt = (TaskLink*)r->tasks.next; lt; lt = (TaskLink*)lt->next){
.
784c
	int R;
	List *lr, *l;
	TaskLink *lt;
	CSN *c;
.
675a
	for (c = (CSN*)t->csns.next; c; c = (CSN*)c->next){
		DEBUG("release csn: C=%T\n", ticks2time(c->C));
		c->S = c->C;
	}
.
669a
	CSN *c;

.
488a
	if (noted)
		postnote(up, 1, buf, NUser);
.
479a

.
472,473c

			if (t->d <= now || t->S == 0LL || t->curcsn == 0LL){
.
470c
				if (!noted){
					noted++;
					snprint(buf, sizeof buf, "sys: deadline miss: runtime");
				}
			}else
.
468c
			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){
.
456c
	// for non-real-time processes.
	noted = 0;
.
451c
	if(panicking || active.exiting)
.
444a
	Resource *r;
	char buf[128];
	int noted;
	extern int panicking;
.
422c
	if(panicking || active.exiting)
.
415a
	extern int panicking;
.
360d
341a
		for (c = (CSN*)t->csns.next; c; c = (CSN*)c->next){
			DEBUG("admit csn: C=%T\n", ticks2time(c->C));
			c->S = c->C;
		}
.
323d
318a
	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);

.
301c
	char *err, *p;
	static char csndump[512];
	CSN *c;
.
86d
64a
static Task *qschedulability;

.
33d
8,9c
#include	"../port/realtime.h"
.
## diffname port/edf.c 2002/1001
## diff -e /n/emeliedump/2002/0927/sys/src/9/port/edf.c /n/emeliedump/2002/1001/sys/src/9/port/edf.c
1115a
	if(devrt) devrt(t, now, SResrel);
.
1085a
	if(devrt) devrt(t, now, SResacq);
.
488a
					resrelease(t);
.
465,466c
	if (timer)
		timer->when = 0;
.
452c
edfdeadlineintr(Ureg*, Timer *timer)
.
72c
static char *	edftestschedulability(Task*);
static void		resrelease(Task*);
.
69,70c
static void		testdelta(Task*);
static void		edfreleaseintr(Ureg*, Timer*);
.
67c
static void		edfresched(Task*);
.
## diffname port/edf.c 2002/1119
## diff -e /n/emeliedump/2002/1001/sys/src/9/port/edf.c /n/emeliedump/2002/1119/sys/src/9/port/edf.c
8c
#include	"realtime.h"
#include	"../port/edf.h"
.
## diffname port/edf.c 2002/1217
## diff -e /n/emeliedump/2002/1119/sys/src/9/port/edf.c /n/emeliedump/2002/1217/sys/src/9/port/edf.c
776c
		assert(nt->runq.n >= 1 || (up && up->task == nt));
.
740a

.
## diffname port/edf.c 2002/1218
## diff -e /n/emeliedump/2002/1217/sys/src/9/port/edf.c /n/emeliedump/2002/1218/sys/src/9/port/edf.c
1122,1123d
1084d
809,814c
	if(deadlinetimer[m->machno].when == when){
		iunlock(&edflock);
		return p;
.
480a

		assert(t->state == EdfRunning);
.
359,360d
216,217d
## diffname port/edf.c 2002/1219
## diff -e /n/emeliedump/2002/1218/sys/src/9/port/edf.c /n/emeliedump/2002/1219/sys/src/9/port/edf.c
1078c
	if (deadlinetimer[m->machno].when == 0 || when < deadlinetimer[m->machno].when){
.
474,475d
468a
	now = fastticks(nil);
.
463,465d
450c
edfdeadlineintr(Ureg*, Timer *)
.
437a
	ilock(&edflock);
.
436d
430,432d
## diffname port/edf.c 2003/0201
## diff -e /n/emeliedump/2002/1219/sys/src/9/port/edf.c /n/emeliedump/2003/0201/sys/src/9/port/edf.c
517c
		postnote(up, 0, buf, NUser);
.

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].