~kris/9p

9hist

567ca0b09330727481c3858b999efb066df127d0 — David du Colombier 24 years ago 66e2d3a
Plan 9 from Bell Labs 2002-03-20
6 files changed, 183 insertions(+), 107 deletions(-)

M port/devrealtime.c
M port/devrealtime.h
M port/edf.c
M port/edf.h
M port/qlock.c
M port/sysproc.c
M port/devrealtime.c => port/devrealtime.c +136 -64
@@ 66,7 66,7 @@ dumptask(char *p, char *e, Task *t, Ticks now)
	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);
		edf_statename[t->state], t->D, t->Delta, t->T, t->C, t->S);
	n = t->r - now;
	if (n >= 0)
		c = ' ';


@@ 214,7 214,7 @@ devrtinit(void)
static Chan *
devrtattach(char *param)
{
	return devattach(L'⌛', param);
	return devattach(L'Σ', param);
}

static Walkqid *


@@ 327,6 327,7 @@ devrtread(Chan *c, void *v, long n, vlong offs)
	Task *t;
	int s, i, fst;
	Ticks now;
	Time tim;

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


@@ 342,13 343,18 @@ devrtread(Chan *c, void *v, long n, vlong offs)
		return devdirread(c, v, n, nil, 0, schedgen);

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


@@ 403,10 409,10 @@ devrtread(Chan *c, void *v, long n, vlong offs)
					}
				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Δ));
			if (resources[i].Delta)
				p = seprint(p, e, " Δ=%T", ticks2time(resources[i].Delta));
			else if (resources[i].testDelta)
				p = seprint(p, e, " testΔ=%T", ticks2time(resources[i].testDelta));
			p = seprint(p, e, "\n");
		}
		return readstr(offs, v, n, buf);


@@ 450,10 456,11 @@ devrtread(Chan *c, void *v, long n, vlong offs)
			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->Delta)
			p = seprint(p, e, " Δ=%T", ticks2time(t->Delta));
		else if (t->testDelta)
			p = seprint(p, e, " testΔ=%T", ticks2time(t->testDelta));
		p = seprint(p, e, " yieldonblock=%d", (t->flags & Verbose) != 0);
		if (t->nres){
			p = seprint(p, e, " resources='");
			fst = 0;


@@ 603,6 610,49 @@ proctotask(Task *t, Proc *p, int add)
	return nil;
}

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

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

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


@@ 611,6 661,7 @@ devrtwrite(Chan *c, void *va, long n, vlong)
	Resource **rp, *r;
	Proc **pp;
	Task *t;
	Ticks ticks;
	Time time;
	long pid;
	Proc *p;


@@ 652,18 703,60 @@ devrtwrite(Chan *c, void *va, long n, vlong)
			if (strcmp(a, "T") == 0){
				if (e=parsetime(&time, v))
					error(e);
				ticks = time2ticks(time);
				edf_expel(t);
				t->T = time2ticks(time);
				switch(add){
				case -1:
					if (ticks > t->T)
						t->T = 0;
					else
						t->T -= ticks;
					break;
				case 0:
					t->T = ticks;
					break;
				case 1:
					t->T += ticks;
					break;
				}
			}else if (strcmp(a, "D") == 0){
				if (e=parsetime(&time, v))
					error(e);
				ticks = time2ticks(time);
				edf_expel(t);
				t->D = time2ticks(time);
				switch(add){
				case -1:
					if (ticks > t->D)
						t->D = 0;
					else
						t->D -= ticks;
					break;
				case 0:
					t->D = ticks;
					break;
				case 1:
					t->D += ticks;
					break;
				}
			}else if (strcmp(a, "C") == 0){
				if (e=parsetime(&time, v))
					error(e);
				ticks = time2ticks(time);
				edf_expel(t);
				t->C = time2ticks(time);
				switch(add){
				case -1:
					if (ticks > t->C)
						t->C = 0;
					else
						t->C -= ticks;
					break;
				case 0:
					t->C = ticks;
					break;
				case 1:
					t->C += ticks;
					break;
				}
			}else if (strcmp(a, "resources") == 0){
				if (v == nil)
					error("resources: value missing");


@@ 703,13 796,17 @@ devrtwrite(Chan *c, void *va, long n, vlong)
				}
				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 (strcmp("self", rargs[j]) == 0){
						p = up;
					}else{
						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);
				}


@@ 717,15 814,25 @@ devrtwrite(Chan *c, void *va, long n, vlong)
				/* Do the admission test */
				if (e = edf_admit(t))
					error(e);
			}else if (strcmp(a, "expel") == 0){
				/* Do the admission test */
				edf_expel(t);
			}else if (strcmp(a, "remove") == 0){
				/* Do the admission test */
				removetask(t);
				return n;	/* Ignore any subsequent commands */
			}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)
			}else if (strcmp(a, "yieldonblock") == 0){
				if (v == nil)
					error("yieldonblock: value missing");
				if (add != 0)
					error("yieldonblock: cannot increment/decrement");
				if (atoi(v) == 0)
					t->flags &= ~Useblocking;
				else
					t->flags |= Useblocking;


@@ 745,10 852,8 @@ devrtwrite(Chan *c, void *va, long n, vlong)
static void
devrtremove(Chan *c)
{
	int s, i;
	int s;
	Task *t;
	Proc *p, **pp;
	Resource *r;

	if ((c->qid.path & Qistask) == 0)
		error(Eperm);


@@ 756,44 861,11 @@ devrtremove(Chan *c)
	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);
	removetask(t);
}

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

	devreset,

M port/devrealtime.h => port/devrealtime.h +7 -6
@@ 1,10 1,11 @@

typedef vlong	Time;
typedef struct	Schedevent Schedevent;

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


@@ 20,8 21,8 @@ enum SEvent {
typedef enum SEvent	SEvent;

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


M port/edf.c => port/edf.c +31 -28
@@ 72,8 72,8 @@ void (*devrt)(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 void		setdelta(void);
static void		testdelta(Task *thetask);
static char *	edf_testschedulability(Task *thetask);
static void		edf_setclock(void);



@@ 226,10 226,14 @@ edf_block(Proc *p)
	/* The current proc has blocked */
	ilock(&edflock);
	t = p->task;
	assert(t);
	if (t->state != EdfRunning){
		/* called by a proc just joining the task */
		iunlock(&edflock);
		return;
	}
	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);
	if (t->runq.n){
		/* There's another runnable proc in the running task, leave task where it is */
		iunlock(&edflock);


@@ 255,12 259,11 @@ edfdeadline(Proc *p, SEvent why)
	if (p){
		nt = p->task;
		assert(nt);
		assert(nt->state == EdfRunning);
	}
	t = edfpop();

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


@@ 326,7 329,7 @@ edf_admit(Task *t)
		t->scheduled = now;
		t->state = EdfRunning;
		if(devrt) devrt(t, now, SRun);
		setΔ();
		setdelta();
		assert(t->runq.n > 0 || (up && up->task == t));
		edfpush(t);
		edf_setclock();


@@ 336,7 339,7 @@ edf_admit(Task *t)
				t->state = EdfAdmitted;
				t->r = now;
				edf_release(t);
				setΔ();
				setdelta();
				edf_resched(t);
			}else{
				edfenqueue(&qadmit, t);


@@ 393,7 396,7 @@ edf_expel(Task *t)
	}
	t->state = EdfExpelled;
	if(devrt) devrt(t, now, SExpel);
	setΔ();
	setdelta();
	DLEAVE;
	iunlock(&edflock);
	qunlock(&edfschedlock);


@@ 739,7 742,7 @@ edf_runproc(void)
		return nil;
	}
	DENTER("edf_runproc %lud\n", nilcount);
	if (nt && (t == nil || (nt->D < t->Δ && nt->d < t->d))){
	if (nt && (t == nil || (nt->d < t->d && nt->D < t->Delta))){
		/* released task is better than current */
		DPRINT("%.*s%d edf_runproc: released\n", ind, tabs, m->machno);
		edfdequeue(&qreleased);


@@ 777,8 780,6 @@ static Lock	waitlock;
int
edf_waitlock(Lock *l)
{
	Task *t;

	iprint("edf_waitlock\n");
	ilock(&waitlock);	/* can't afford normal locks here */
	if (l->key == 0){


@@ 820,7 821,7 @@ edf_releaselock(Lock *l)
/* Schedulability testing and its supporting routines */

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


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

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


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



@@ 877,7 878,7 @@ blockcost(Ticks ticks, Task *thetask)
	for (t = tasks; t < tasks + Maxtasks; t++){
		if (t->state <= EdfExpelled && t != thetask)
			continue;
		if (t->testΔ <= ticks && ticks < t->D && Cb < t->C)
		if (t->testDelta <= ticks && ticks < t->D && Cb < t->C)
			Cb = t->C;
	}
	return Cb;


@@ 917,7 918,7 @@ edf_testschedulability(Task *thetask)
	int steps;

	/* initialize */
	testΔ(thetask);
	testdelta(thetask);
	if (thetask && (thetask->flags & Verbose))
		pprint("schedulability test\n");
	qschedulability = nil;


@@ 986,6 987,8 @@ Time
ticks2time(Ticks ticks)
{
	assert(ticks >= 0);
	if (fasthz == 0)
		fastticks(&fasthz);
	return uvmuldiv(ticks, Onesecond, fasthz);
}


M port/edf.h => port/edf.h +4 -4
@@ 38,7 38,7 @@ typedef enum Edfstate	Edfstate;
struct Edf {
	/* time intervals */
	Ticks	D;		/* Deadline */
	Ticks	Δ;		/* Inherited deadline */
	Ticks	Delta;		/* Inherited deadline */
	Ticks	T;		/* period */
	Ticks	C;		/* Cost */
	Ticks	S;		/* Slice: time remaining in this period */


@@ 47,7 47,7 @@ struct Edf {
	Ticks	d;		/* (this) deadline */
	Ticks	t;		/* Start of next period, t += T at release */
	/* for schedulability testing */
	Ticks	testΔ;
	Ticks	testDelta;
	int		testtype;	/* Release or Deadline */
	Ticks	testtime;
	Task	*	testnext;


@@ 82,9 82,9 @@ struct Resource
	char	*	name;
	Task *	tasks[Ntask];	/* may contain holes */
	int		ntasks;
	Ticks	Δ;
	Ticks	Delta;
	/* for schedulability testing */
	Ticks	testΔ;
	Ticks	testDelta;
};

extern Lock		edftestlock;	/* for atomic admitting/expelling */

M port/qlock.c => port/qlock.c +4 -4
@@ 38,10 38,10 @@ rwstats.qlockq++;
	q->tail = mp;
	mp->qnext = 0;
	mp->state = Queueing;
	if (isedf(mp))
		edf_block(mp);
	up->qpc = getcallerpc(&q);
	unlock(&q->use);
	if (isedf(mp))
		edf_block(mp);
	sched();
}



@@ 104,9 104,9 @@ rwstats.rlockq++;
	q->tail = mp;
	mp->qnext = 0;
	mp->state = QueueingR;
	unlock(&q->use);
	if (isedf(mp))
		edf_block(mp);
	unlock(&q->use);
	sched();
}



@@ 162,9 162,9 @@ rwstats.wlockq++;
	q->tail = mp;
	mp->qnext = 0;
	mp->state = QueueingW;
	unlock(&q->use);
	if (isedf(mp))
		edf_block(mp);
	unlock(&q->use);
	sched();
}


M port/sysproc.c => port/sysproc.c +1 -1
@@ 825,9 825,9 @@ sysrendezvous(ulong *arg)
	up->rendhash = *l;
	*l = up;
	up->state = Rendezvous;
	unlock(up->rgrp);
	if (isedf(up))
		edf_block(up);
	unlock(up->rgrp);

	sched();