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

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


## diffname port/devrealtime.c 2002/0316
## diff -e /dev/null /n/emeliedump/2002/0316/sys/src/9/port/devrealtime.c
0a
#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;
}
.
## diffname port/devrealtime.c 2002/0319
## diff -e /n/emeliedump/2002/0316/sys/src/9/port/devrealtime.c /n/emeliedump/2002/0319/sys/src/9/port/devrealtime.c
698a
						}
.
697c
						if (*pp){
.
694a
				}
.
693c
				if (add <= 0){
.
649c
				v++;
.
641a
				*v = '\0';
.
## diffname port/devrealtime.c 2002/0320
## diff -e /n/emeliedump/2002/0319/sys/src/9/port/devrealtime.c /n/emeliedump/2002/0320/sys/src/9/port/devrealtime.c
796c
	L'Σ',
.
759,792c
	removetask(t);
.
750,751d
748c
	int s;
.
726,728c
			}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)
.
719a
			}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 */
.
706,712c
					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);
					}
.
666c
				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;
				}
.
664a
				ticks = time2ticks(time);
.
661c
				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;
				}
.
659a
				ticks = time2ticks(time);
.
656c
				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;
				}
.
654a
				ticks = time2ticks(time);
.
613a
	Ticks ticks;
.
605a
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);
}

.
453,456c
		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);
.
406,409c
			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));
.
353a
		if (n >= sizeof(Ticks)){
			memmove((char*)v + sizeof(Time) + sizeof(Ticks), &fasthz, sizeof(Ticks));
			n -= sizeof(Ticks);
		}
.
351c
			memmove((char*)v + sizeof(Time), &now, sizeof(Ticks));
.
348c
		tim = ticks2time(now);
 		memmove(v, &tim, sizeof(Time));
.
345c
		if (n < sizeof(Time))
.
329a
	Time tim;
.
217c
	return devattach(L'Σ', param);
.
69c
		edf_statename[t->state], t->D, t->Delta, t->T, t->C, t->S);
.
## diffname port/devrealtime.c 2002/0322
## diff -e /n/emeliedump/2002/0320/sys/src/9/port/devrealtime.c /n/emeliedump/2002/0322/sys/src/9/port/devrealtime.c
868c
	'R',
.
217c
	return devattach('R', param);
.
192c
	if(edfprint)iprint("wakesched\n");
.
174c
	if(edfprint)iprint("state %s\n", edf_statename[etype]);
.
16,17d
## diffname port/devrealtime.c 2002/0329
## diff -e /n/emeliedump/2002/0322/sys/src/9/port/devrealtime.c /n/emeliedump/2002/0329/sys/src/9/port/devrealtime.c
172c
	if(edfprint)iprint("state %s\n", schedstatename[etype]);
.
59a
static char *schedstatename[] = {
	[SRelease] =	"Release",
	[SRun] =		"Run",
	[SPreempt] =	"Preempt",
	[SBlock] =		"Block",
	[SResume] =	"Resume",
	[SDeadline] =	"Deadline",
	[SYield] =		"Yield",
	[SSlice] =		"Slice",
	[SExpel] =		"Expel",
};

.
## diffname port/devrealtime.c 2002/0404
## diff -e /n/emeliedump/2002/0329/sys/src/9/port/devrealtime.c /n/emeliedump/2002/0404/sys/src/9/port/devrealtime.c
265a
	if (havecycintr() == 0)
		error("no edf on multiprocessors");
.
232a
	if (havecycintr() == 0)
		error("no edf on multiprocessors");
.
226a
	if(havecycintr() == 0)
		error("no edf on multiprocessors");
.
## diffname port/devrealtime.c 2002/0405
## diff -e /n/emeliedump/2002/0404/sys/src/9/port/devrealtime.c /n/emeliedump/2002/0405/sys/src/9/port/devrealtime.c
270c
	if (havetimer() == 0)
.
235c
	if (havetimer() == 0)
.
227c
	if(havetimer() == 0)
.
## diffname port/devrealtime.c 2002/0410
## diff -e /n/emeliedump/2002/0405/sys/src/9/port/devrealtime.c /n/emeliedump/2002/0410/sys/src/9/port/devrealtime.c
857c
					edfdeadline(up);	/* schedule next release */
.
835c
				edfexpel(t);
.
831c
				if (e = edfadmit(t))
.
804c
					edfexpel(t);
.
779c
				edfexpel(t);
.
761c
				edfexpel(t);
.
742c
				edfexpel(t);
.
723c
				edfexpel(t);
.
637c
	edfexpel(t);
.
468c
		p = seprint(p, e, " state=%s", edfstatename[t->state]);
.
295c
		edfinit();
.
270,271d
235,236d
227,228d
79c
		edfstatename[t->state], t->D, t->Delta, t->T, t->C, t->S);
.
## diffname port/devrealtime.c 2002/0416
## diff -e /n/emeliedump/2002/0410/sys/src/9/port/devrealtime.c /n/emeliedump/2002/0416/sys/src/9/port/devrealtime.c
769a
				if (t->C < time2ticks(10000000/HZ))
					error("cost too small");
.
731a
				if (t->T < time2ticks(10000000/HZ))
					error("period too short");
.
## diffname port/devrealtime.c 2002/0503
## diff -e /n/emeliedump/2002/0416/sys/src/9/port/devrealtime.c /n/emeliedump/2002/0503/sys/src/9/port/devrealtime.c
497a
		if (t->periods)
			p = seprint(p, e, " n=%lud", t->periods);
		if (t->missed)
			p = seprint(p, e, " m=%lud", t->missed);
		if (t->preemptions)
			p = seprint(p, e, " p=%lud", t->preemptions);
		if (t->total)
			p = seprint(p, e, " t=%T", ticks2time(t->total));
		if (t->aged)
			p = seprint(p, e, " c=%T", ticks2time(t->aged));
.
## diffname port/devrealtime.c 2002/0621
## diff -e /n/emeliedump/2002/0503/sys/src/9/port/devrealtime.c /n/emeliedump/2002/0621/sys/src/9/port/devrealtime.c
969,976c
	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";
	}
.
849d
845d
842d
838d
## diffname port/devrealtime.c 2002/0704
## diff -e /n/emeliedump/2002/0621/sys/src/9/port/devrealtime.c /n/emeliedump/2002/0704/sys/src/9/port/devrealtime.c
860,861c
				if (edf->isedf(up) && up->task == t){
					edf->edfdeadline(up);	/* schedule next release */
.
841c
				edf->edfexpel(t);
.
838c
				if (e = edf->edfadmit(t))
.
812c
					edf->edfexpel(t);
.
787c
				edf->edfexpel(t);
.
767c
				edf->edfexpel(t);
.
748c
				edf->edfexpel(t);
.
727c
				edf->edfexpel(t);
.
641c
	edf->edfexpel(t);
.
289c
		edf->edfinit();
.
221a
	edf = &realedf;
.
15a
extern Edfinterface	realedf, *edf;
.
## diffname port/devrealtime.c 2002/0831
## diff -e /n/emeliedump/2002/0704/sys/src/9/port/devrealtime.c /n/emeliedump/2002/0831/sys/src/9/port/devrealtime.c
977a
	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;
.
886a
	poperror();
	qunlock(&edfschedlock);
.
885a
	qlock(&edfschedlock);
	if (waserror()){
		qunlock(&edfschedlock);
		nexterror();
	}
.
883,884c
	t = findtask(s);
	if (t == nil)
.
869a
		poperror();
		qunlock(&edfschedlock);
.
864a
					qlock(&edfschedlock);
.
863a
					qunlock(&edfschedlock);
.
845a
				poperror();
				qunlock(&edfschedlock);
.
836,837c
					if(p->task && p->task != t)
						error("proc belongs to another task");
					if (add > 0){
						enlist(&t->procs, p);
						p->task = t;
					}else{
						delist(&t->procs, p);
						p->task = nil;
					}
.
817,820c
					List *l;

					while (l = t->procs.next){
						p = l->i;
						assert(p->task == t);
						delist(&t->procs, p);
						p->task = nil;
					}
.
802,806c
						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);
.
791,796c
					List *l;

					while (l = t->res.next) {
						r = l->i;
						assert(r);
						if (delist(&r->tasks, t))
							taskfree(t);
						if (delist(&t->res, r))
							resourcefree(r);
					}
					assert(t->res.n == 0);
.
705d
703c
		qlock(&edfschedlock);
		if (waserror()){
			qunlock(&edfschedlock);
			nexterror();
		}
		t = findtask(s);
		if (t == nil)
.
683,684c
	Resource *r;
.
675c
	if (delist(&tasks, t))
		taskfree(t);
.
670,673c
	free(t->user);
	t->user = nil;
.
655,668c
	while (l = t->res.next){
		r = l->i;
		if (delist(&r->tasks, t))
			taskfree(t);
		if (delist(&t->res, r))
			resourcefree(r);
.
644,646c
	while (l = t->procs.next){
		p = l->i;
		assert(p);
		p->task = nil;
		delist(&t->procs, p);
	}
.
642d
640a
	List *l;
.
638,639c
	Proc *p;
.
570,634d
544,567c
	if (decref(r))
		return;
	delist(&resources, r);
	assert(r->tasks.n == 0);
	free(r->name);
	free(r);
.
541,542c
void
resourcefree(Resource *r)
.
534,538c
	enlist(&resources, r);
	return r;
.
532c
		error("resource: malloc");
.
530a
	r = malloc(sizeof(Resource));
.
522,529c
	for (l = resources.next; l; l = l->next)
		if ((r = l->i) && strcmp(r->name, name) == 0)
			return r;
	if (add < 0)
.
519,520c
	Resource *r;
	List *l;
.
510a
		qunlock(&edfschedlock);
.
490,497c
			for (l = t->procs.next; l; l = l->next){
				Proc *pr = l->i;
				assert(pr);
				if (l != t->procs.next)
					p = seprint(p, e, " ");
				p = seprint(p, e, "%lud", pr->pid);
			}
.
488c
		if (t->procs.n){
.
478,485c
			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);
			}
.
476c
		if (t->res.n){
.
460c
		}
.
458c
		qlock(&edfschedlock);
		t = findtask(s);
		if (t == nil){
			qunlock(&edfschedlock);
.
449d
431a
	case Qdump:
		p = buf;
		e = p + sizeof(buf);
		qlock(&edfschedlock);
		qunlock(&edfschedlock);
		p = seprint(p, e, "\n");
		return readstr(offs, v, n, buf);
.
429a
		qunlock(&edfschedlock);
		poperror();
.
424,427c
			if (r->Delta)
				p = seprint(p, e, " Δ=%T", ticks2time(r->Delta));
			else if (r->testDelta)
				p = seprint(p, e, " testΔ=%T", ticks2time(r->testDelta));
.
414,421c
				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);
				}
.
408,412c
		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;

.
405a
		qlock(&edfschedlock);
		if(waserror()){
			qunlock(&edfschedlock);
			nexterror();
		}
.
342a
	List *l;
	Resource *r;
.
340c
	int s, i;
.
293,303c
		t = taskinit();
		c->qid.vers = t->taskno;
		qunlock(&edfschedlock);
.
291a
		qlock(&edfschedlock);
.
287a
	case Qdump:
		if (mode != OREAD) 
			error(Eperm);
		break;
.
244,262d
186c
	events[wevent].tid = t->taskno;
.
171,175c
	qunlock(&edfschedlock);
.
169c
	}else{
		owner = t->user;
		if (owner == nil)
			owner = eve;
		tab = &t->dir;
		devdir(c, tab->qid, tab->name, tab->length, owner, tab->perm, dp);
.
147a
		}
.
146c
		if (l == nil){
			qunlock(&edfschedlock);
.
143,144c
		SET(t);
		for (l = tasks.next; l; l = l->next)
			if ((t = l->i) && taskindex-- == 0)
.
141a
		qlock(&edfschedlock);

.
140a
		}
.
139c
		if ((t = findtask(taskindex)) == nil){
			qunlock(&edfschedlock);
.
137a
		qlock(&edfschedlock);
.
135a
	Task *t;
	List *l;
.
124a
static Task *
taskinit(void)
{
	Dirtab *d;
	Task *t;

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

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

.
72a
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;
}

.
53a
	"dump",		{Qdump},				0,	0444,
.
34a
	Qdump,
.
24a
static int taskno;
.
## diffname port/devrealtime.c 2002/0927
## diff -e /n/emeliedump/2002/0831/sys/src/9/port/devrealtime.c /n/emeliedump/2002/0927/sys/src/9/port/devrealtime.c
907,1032d
768,783c
				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);
.
766a
					USED(add);
.
765c
					assert(t->csns.n == 0);
.
762c
						if (delist(&t->csns, r))
.
756,757c
	
					while (l = t->csns.next) {
.
753a
				if (add < 0)
					error("can't remove resources yet");
.
749a
				DEBUG("Task %d, C=%T\n", t->taskno, ticks2time(t->C));
.
728a
				DEBUG("Task %d, D=%T\n", t->taskno, ticks2time(t->D));
.
709a
				DEBUG("Task %d, T=%T\n", t->taskno, ticks2time(t->T));
.
648a
	CSN *l;
.
572,637d
535,541c
			p = seprintcsn(p, e, &t->csns);
.
533c
		if (t->csns.n){
.
485c
		seprint(p, e, "\n");
.
453,475c
		seprintresources(buf, buf + sizeof(buf));
.
384d
171c
	assert(t->csns.n == 0);
.
82,139d
76,80c
static int taskno;
.
27,29d
25d
9,10c
#include	"../port/realtime.h"
.
## diffname port/devrealtime.c 2002/1119
## diff -e /n/emeliedump/2002/0927/sys/src/9/port/devrealtime.c /n/emeliedump/2002/1119/sys/src/9/port/devrealtime.c
9c
#include	"realtime.h"
#include	"../port/edf.h"
.
## diffname port/devrealtime.c 2003/0110
## diff -e /n/emeliedump/2002/1119/sys/src/9/port/devrealtime.c /n/emeliedump/2003/0110/sys/src/9/port/devrealtime.c
8,10c
#include "error.h"
#include "realtime.h"
#include "edf.h"
.

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].