## 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"
.
|