From 1d66c87010321514f6f3921c40fc5d63f52067a5 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Fri, 27 Sep 2002 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 2002-09-27 --- port/devrealtime.c | 359 ++++++--------------------------------------- port/devrealtime.h | 28 ---- port/edf.c | 295 +++++++++++++++++++++++++++---------- port/nulledf.c | 2 +- 4 files changed, 266 insertions(+), 418 deletions(-) delete mode 100644 port/devrealtime.h diff --git a/port/devrealtime.c b/port/devrealtime.c index 01377e4864a7063f0e55a1a44b19d3e5e026590d..6817fec9deb92dcb8719876fc370be9b0afe5428 100644 --- a/port/devrealtime.c +++ b/port/devrealtime.c @@ -6,8 +6,7 @@ #include "io.h" #include "ureg.h" #include "../port/error.h" -#include "../port/devrealtime.h" -#include "../port/edf.h" +#include "../port/realtime.h" #pragma varargck type "T" vlong @@ -22,10 +21,6 @@ static QLock elock; static Ref logopens; static Ref debugopens; static uvlong fasthz; -static int taskno; - -static int timeconv(Fmt *); -static char * parsetime(Time *, char *); enum { Qistask = 0x10000, @@ -73,69 +68,7 @@ static char *schedstatename[] = { [SExpel] = "Expel", }; -Task * -findtask(int taskno) -{ - List *l; - Task *t; - - for (l = tasks.next; l; l = l->next) - if ((t = l->i) && t->taskno == taskno) - return t; - return nil; -} - -static char* -dumptask(char *p, char *e, Task *t, Ticks now) -{ - vlong n; - char c; - - p = seprint(p, e, "{%s, D%U, Δ%U,T%U, C%U, S%U", - edfstatename[t->state], t->D, t->Delta, t->T, t->C, t->S); - n = t->r - now; - if (n >= 0) - c = ' '; - else { - n = -n; - c = '-'; - } - p = seprint(p, e, ", r%c%U", c, (uvlong)n); - n = t->d - now; - if (n >= 0) - c = ' '; - else { - n = -n; - c = '-'; - } - p = seprint(p, e, ", d%c%U", c, (uvlong)n); - n = t->t - now; - if (n >= 0) - c = ' '; - else { - n = -n; - c = '-'; - } - p = seprint(p, e, ", t%c%U}", c, (uvlong)n); - return p; -} - -static char* -dumpq(char *p, char *e, Taskq *q, Ticks now) -{ - Task *t; - - t = q->head; - for(;;){ - if (t == nil) - return seprint(p, e, "\n"); - p = dumptask(p, e, t, now); - t = t->rnext; - if (t) - seprint(p, e, ", "); - } - return nil; -} +static int taskno; static Task * taskinit(void) @@ -168,7 +101,7 @@ taskfree(Task *t) if (decref(t)) return; assert(t->procs.n == 0); - assert(t->res.n == 0); + assert(t->csns.n == 0); free(t->user); free(t); } @@ -381,7 +314,6 @@ devrtread(Chan *c, void *v, long n, vlong offs) Ticks now; Time tim; List *l; - Resource *r; n0 = n; // print("schedread 0x%lux\n", (ulong)c->qid.path); @@ -450,29 +382,7 @@ devrtread(Chan *c, void *v, long n, vlong offs) qunlock(&edfschedlock); nexterror(); } - p = buf; - e = p + sizeof(buf); - for (l = resources.next; l; l = l->next){ - r = l->i; - assert(r); - p = seprint(p, e, "name=%s", r->name); - if (r->tasks.n){ - List *l; - - p = seprint(p, e, " tasks='"); - for (l = r->tasks.next; l; l = l->next) { - if (l != r->tasks.next) - p = seprint(p, e, " "); - p = seprint(p, e, "%d", ((Task *)l->i)->taskno); - } - p = seprint(p, e, "'"); - } - if (r->Delta) - p = seprint(p, e, " Δ=%T", ticks2time(r->Delta)); - else if (r->testDelta) - p = seprint(p, e, " testΔ=%T", ticks2time(r->testDelta)); - p = seprint(p, e, "\n"); - } + seprintresources(buf, buf + sizeof(buf)); qunlock(&edfschedlock); poperror(); return readstr(offs, v, n, buf); @@ -482,7 +392,7 @@ devrtread(Chan *c, void *v, long n, vlong offs) e = p + sizeof(buf); qlock(&edfschedlock); qunlock(&edfschedlock); - p = seprint(p, e, "\n"); + seprint(p, e, "\n"); return readstr(offs, v, n, buf); case Qdebug: p = buf; @@ -530,15 +440,9 @@ devrtread(Chan *c, void *v, long n, vlong offs) else if (t->testDelta) p = seprint(p, e, " testΔ=%T", ticks2time(t->testDelta)); p = seprint(p, e, " yieldonblock=%d", (t->flags & Verbose) != 0); - if (t->res.n){ + if (t->csns.n){ p = seprint(p, e, " resources='"); - for (l = t->res.next; l; l = l->next){ - r = l->i; - assert(r); - if (l != t->res.next) - p = seprint(p, e, " "); - p = seprint(p, e, "%s", r->name); - } + p = seprintcsn(p, e, &t->csns); p = seprint(p, e, "'"); } if (t->procs.n){ @@ -569,72 +473,6 @@ devrtread(Chan *c, void *v, long n, vlong offs) return n0 - n; } -static Resource * -resource(char *name, int add) -{ - Resource *r; - List *l; - - for (l = resources.next; l; l = l->next) - if ((r = l->i) && strcmp(r->name, name) == 0) - return r; - if (add < 0) - return nil; - r = malloc(sizeof(Resource)); - if (r == nil) - error("resource: malloc"); - kstrdup(&r->name, name); - enlist(&resources, r); - return r; -} - -void -resourcefree(Resource *r) -{ - if (decref(r)) - return; - delist(&resources, r); - assert(r->tasks.n == 0); - free(r->name); - free(r); -} - -static void -removetask(Task *t) -{ - Proc *p; - Resource *r; - List *l; - - edf->edfexpel(t); - while (l = t->procs.next){ - p = l->i; - assert(p); - p->task = nil; - delist(&t->procs, p); - } - while (p = t->runq.head){ - /* put runnable procs on regular run queue */ - t->runq.head = p->rnext; - ready(p); - t->runq.n--; - } - t->runq.tail = nil; - assert(t->runq.n == 0); - while (l = t->res.next){ - r = l->i; - if (delist(&r->tasks, t)) - taskfree(t); - if (delist(&t->res, r)) - resourcefree(r); - } - free(t->user); - t->user = nil; - t->state = EdfUnused; - if (delist(&tasks, t)) - taskfree(t); -} - static long devrtwrite(Chan *c, void *va, long n, vlong) { @@ -646,6 +484,7 @@ devrtwrite(Chan *c, void *va, long n, vlong) Time time; long pid; Proc *p; + CSN *l; a = va; if (c->mode == OREAD) @@ -707,6 +546,7 @@ devrtwrite(Chan *c, void *va, long n, vlong) } if (t->T < time2ticks(10000000/HZ)) error("period too short"); + DEBUG("Task %d, T=%T\n", t->taskno, ticks2time(t->T)); }else if (strcmp(a, "D") == 0){ if (e=parsetime(&time, v)) error(e); @@ -726,6 +566,7 @@ devrtwrite(Chan *c, void *va, long n, vlong) t->D += ticks; break; } + DEBUG("Task %d, D=%T\n", t->taskno, ticks2time(t->D)); }else if (strcmp(a, "C") == 0){ if (e=parsetime(&time, v)) error(e); @@ -747,40 +588,54 @@ devrtwrite(Chan *c, void *va, long n, vlong) } if (t->C < time2ticks(10000000/HZ)) error("cost too small"); + DEBUG("Task %d, C=%T\n", t->taskno, ticks2time(t->C)); }else if (strcmp(a, "resources") == 0){ if (v == nil) error("resources: value missing"); edf->edfexpel(t); + if (add < 0) + error("can't remove resources yet"); if (add == 0){ List *l; - - while (l = t->res.next) { + + while (l = t->csns.next) { r = l->i; assert(r); if (delist(&r->tasks, t)) taskfree(t); - if (delist(&t->res, r)) + if (delist(&t->csns, r)) resourcefree(r); } - assert(t->res.n == 0); + assert(t->csns.n == 0); add = 1; + USED(add); } - nrargs = tokenize(v, rargs, nelem(rargs)); - for (j = 0; j < nrargs; j++) - if (r = resource(rargs[j], add)){ - if (add > 0){ - if (enlist(&r->tasks, t)) - incref(t); - if (enlist(&t->res, r)) - incref(r); - }else{ - if (delist(&r->tasks, t)) - taskfree(t); - if (delist(&t->res, r)) - resourcefree(r); - } - }else - error("resource not found"); + v = parseresource(&t->csns, nil, v); + if (v && *v) + error("resources: parse error"); + }else if (strcmp(a, "acquire") == 0){ + if (v == nil) + error("acquire: value missing"); + if ((r = resource(v, 0)) == nil) + error("acquire: no such resource"); + for (l = (CSN*)t->csns.next; l; l = (CSN*)l->next){ + if (l->i == r){ +DEBUG("l->p (0x%p) == t->curcsn (0x%p) && l->S (%T) != 0\n", l->p, t->curcsn, ticks2time(l->S)); + if(l->p == t->curcsn && l->S != 0) + break; + } + } + if (l == nil) + error("acquire: no access or resource exhausted"); + edf->resacquire(t, l); + }else if (strcmp(a, "release") == 0){ + if (v == nil) + error("release: value missing"); + if ((r = resource(v, 0)) == nil) + error("release: no such resource"); + if (t->curcsn->i != r) + error("release: release not held or illegal release order"); + edf->resrelease(t); }else if (strcmp(a, "procs") == 0){ if (v == nil) error("procs: value missing"); @@ -904,129 +759,3 @@ Dev realtimedevtab = { devrtremove, devwstat, }; - -static int -timeconv(Fmt *f) -{ - char buf[128], *sign; - Time t; - Ticks ticks; - - buf[0] = 0; - switch(f->r) { - case 'U': - ticks = va_arg(f->args, Ticks); - t = ticks2time(ticks); - break; - case 'T': // Time in nanoseconds - t = va_arg(f->args, Time); - break; - default: - return fmtstrcpy(f, "(timeconv)"); - } - if (t < 0) { - sign = "-"; - t = -t; - } - else - sign = ""; - if (t > Onesecond) - sprint(buf, "%s%d.%.3ds", sign, (int)(t / Onesecond), (int)(t % Onesecond)/1000000); - else if (t > Onemillisecond) - sprint(buf, "%s%d.%.3dms", sign, (int)(t / Onemillisecond), (int)(t % Onemillisecond)/1000); - else if (t > Onemicrosecond) - sprint(buf, "%s%d.%.3dµs", sign, (int)(t / Onemicrosecond), (int)(t % Onemicrosecond)); - else - sprint(buf, "%s%dns", sign, (int)t); - return fmtstrcpy(f, buf); -} - -static char * -parsetime(Time *rt, char *s) -{ - uvlong ticks; - ulong l; - char *e, *p; - static int p10[] = {100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1}; - - if (s == nil) - return("missing value"); - ticks=strtoul(s, &e, 10); - if (*e == '.'){ - p = e+1; - l = strtoul(p, &e, 10); - if(e-p > nelem(p10)) - return "too many digits after decimal point"; - if(e-p == 0) - return "ill-formed number"; - l *= p10[e-p-1]; - }else - l = 0; - if (*e){ - if(strcmp(e, "s") == 0) - ticks = 1000000000 * ticks + l; - else if (strcmp(e, "ms") == 0) - ticks = 1000000 * ticks + l/1000; - else if (strcmp(e, "µs") == 0 || strcmp(e, "us") == 0) - ticks = 1000 * ticks + l/1000000; - else if (strcmp(e, "ns") != 0) - return "unrecognized unit"; - } - *rt = ticks; - return nil; -} - -int -putlist(Head *h, List *l) -{ - l->next = h->next; - h->next = l; - h->n++; - return 1; -} - -int -enlist(Head *h, void *i) -{ - List *l; - - for (l = h->next; l; l = l->next) - if (l->i == i){ - /* already on the list */ - return 0; - } - l = malloc(sizeof(List)); - if (l == nil) - panic("malloc in enlist"); - l->i = i; - l->next = h->next; - h->next = l; - h->n++; - return 1; -} - -int -delist(Head *h, void *i) -{ - List *l, **p; - - for (p = &h->next; l = *p; p = &l->next) - if (l->i == i){ - *p = l->next; - free(l); - h->n--; - return 1; - } - return 0; -} - -void * -findlist(Head *h, void *i) -{ - List *l; - - for (l = h->next; l; l = l->next) - if (l->i == i) - return i; - return nil; -} diff --git a/port/devrealtime.h b/port/devrealtime.h deleted file mode 100644 index b8279f8bfd4777cc1a80484537145e95ee13547f..0000000000000000000000000000000000000000 --- a/port/devrealtime.h +++ /dev/null @@ -1,28 +0,0 @@ - -typedef vlong Time; -typedef struct Schedevent Schedevent; - -#define Onemicrosecond ((Time)1000ULL) -#define Onemillisecond ((Time)1000*Onemicrosecond) -#define Onesecond ((Time)1000*Onemillisecond) - -enum SEvent { - SAdmit, /* new proc arrives*/ - SRelease, /* released, but not yet scheduled (on qreleased) */ - SRun, /* one of this task's procs started running */ - SPreempt, /* the running proc was preempted */ - SBlock, /* none of the procs are runnable as a result of sleeping */ - SResume, /* one or more procs became runnable */ - SDeadline, /* proc's deadline */ - SYield, /* proc reached voluntary early deadline */ - SSlice, /* slice exhausted */ - SExpel, /* proc is gone */ -}; -typedef enum SEvent SEvent; - -struct Schedevent { - ushort tid; /* Task ID */ - SEvent etype; /* Event type */ - Time ts; /* Event time */ -}; - diff --git a/port/edf.c b/port/edf.c index 7b33ee2965d819c38a88eee93b334152df6c65c4..42a134bb85687439ce7e4b8173d37ae460cea706 100644 --- a/port/edf.c +++ b/port/edf.c @@ -5,8 +5,7 @@ #include "dat.h" #include "fns.h" #include "../port/error.h" -#include "../port/devrealtime.h" -#include "../port/edf.h" +#include "../port/realtime.h" /* debugging */ int edfprint = 0; @@ -30,7 +29,6 @@ static Timer deadlinetimer[MAXMACH]; /* Time of next deadline */ static Timer releasetimer[MAXMACH]; /* Time of next release */ static int initialized; -static uvlong fasthz; static Ticks now; /* Edfschedlock protects modification of sched params, including resources */ QLock edfschedlock; @@ -62,6 +60,8 @@ Taskq qextratime; /* Running/Preempted EDF tasks, head running, one stack per processor */ Taskq edfstack[MAXMACH]; +static Task *qschedulability; + void (*devrt)(Task*, Ticks, int); static void edfresched(Task *t); @@ -83,7 +83,6 @@ edfinit(void) iunlock(&edflock); return; } - fastticks(&fasthz); for (i = 0; i < conf.nmach; i++){ deadlinetimer[i].f = edfdeadlineintr; deadlinetimer[i].a = &deadlinetimer[i]; @@ -298,7 +297,9 @@ edfdeadline(Proc *p) static char * edfadmit(Task *t) { - char *err; + char *err, *p; + static char csndump[512]; + CSN *c; /* Called with edfschedlock held */ if (t->state != EdfExpelled) @@ -316,11 +317,19 @@ edfadmit(Task *t) if (t->C > t->D) return "C > D"; + resourcetimes(t, &t->csns); + + DEBUG("task %d: T %T, C %T, D %T, tΔ %T\n", + t->taskno, ticks2time(t->T), ticks2time(t->C), + ticks2time(t->D), ticks2time(t->testDelta)); + p = seprintresources(csndump, csndump+sizeof csndump); + seprintcsn(p, csndump+sizeof csndump, &t->csns); + DEBUG("%s\n", csndump); + if (err = edftestschedulability(t)){ return err; } ilock(&edflock); - qunlock(&edfschedlock); DPRINT("%d edfadmit, %s, %d\n", m->machno, edfstatename[t->state], t->runq.n); now = fastticks(nil); @@ -339,6 +348,10 @@ edfadmit(Task *t) t->periods++; if(devrt) devrt(t, now, SRun); setdelta(); + for (c = (CSN*)t->csns.next; c; c = (CSN*)c->next){ + DEBUG("admit csn: C=%T\n", ticks2time(c->C)); + c->S = c->C; + } assert(t->runq.n > 0 || (up && up->task == t)); edfpush(t); if (deadlinetimer[m->machno].when) @@ -357,7 +370,6 @@ edfadmit(Task *t) } } iunlock(&edflock); - qlock(&edfschedlock); return nil; } @@ -413,13 +425,14 @@ static void edfreleaseintr(Ureg*, Timer*) { Task *t; + extern int panicking; DPRINT("%d edfreleaseintr\n", m->machno); timerdel(&releasetimer[m->machno]); releasetimer[m->machno].when = 0; - if(active.exiting) + if(panicking || active.exiting) return; ilock(&edflock); @@ -442,18 +455,23 @@ edfdeadlineintr(Ureg*, Timer*) Ticks used; Task *t; + Resource *r; + char buf[128]; + int noted; + extern int panicking; DPRINT("%d edfdeadlineintr\n", m->machno); timerdel(&deadlinetimer[m->machno]); deadlinetimer[m->machno].when = 0; - if(active.exiting) + if(panicking || active.exiting) return; ilock(&edflock); // If up is not set, we're running inside the scheduler - // for non-real-time processes. + // for non-real-time processes. + noted = 0; if (up && isedf(up)) { now = fastticks(nil); @@ -465,18 +483,33 @@ edfdeadlineintr(Ureg*, Timer*) t->total += used; if (t->r < now){ - if (t->S <= used) + if (t->curcsn){ + if (t->curcsn->S <= used){ + t->curcsn->S = 0LL; + r = t->curcsn->i; + noted++; + snprint(buf, sizeof buf, "sys: deadline miss: resource %s", r->name); + }else + t->curcsn->S -= used; + } + + if (t->S <= used){ t->S = 0LL; - else + if (!noted){ + noted++; + snprint(buf, sizeof buf, "sys: deadline miss: runtime"); + } + }else t->S -= used; - - if (t->d <= now || t->S == 0LL){ + + if (t->d <= now || t->S == 0LL || t->curcsn == 0LL){ /* Task has reached its deadline/slice, remove from queue */ if (t->d <= now){ t->missed++; misseddeadlines++; } deadline(up, SSlice); + while (t = edfstack[m->machno].head){ if (now < t->d) break; @@ -486,6 +519,8 @@ edfdeadlineintr(Ureg*, Timer*) } } iunlock(&edflock); + if (noted) + postnote(up, 1, buf, NUser); sched(); splhi(); } @@ -667,12 +702,18 @@ edfresched(Task *t) static void edfrelease(Task *t) { + CSN *c; + DPRINT("%d edfrelease, %s, %d\n", m->machno, edfstatename[t->state], t->runq.n); assert(t->runq.n > 0 || (up && up->task == t)); t->t = t->r + t->T; t->d = t->r + t->D; if(devrt) devrt(t, t->d, SDeadline); t->S = t->C; + for (c = (CSN*)t->csns.next; c; c = (CSN*)c->next){ + DEBUG("release csn: C=%T\n", ticks2time(c->C)); + c->S = c->C; + } t->state = EdfReleased; edfenqueue(&qreleased, t); if(devrt) devrt(t, now, SRelease); @@ -781,29 +822,44 @@ setdelta(void) { Resource *r; Task *t; - List *lr, *lt; + int R; + List *lr, *l; + TaskLink *lt; + CSN *c; for (lr = resources.next; lr; lr = lr->next){ r = lr->i; assert(r); - r->Delta = ~0LL; - for (lt = r->tasks.next; lt; lt = lt->next){ + r->Delta = Infinity; + R = 1; + for (lt = (TaskLink*)r->tasks.next; lt; lt = (TaskLink*)lt->next){ t = lt->i; assert(t); - if (t->D < r->Delta) + if (t->D < r->Delta){ r->Delta = t->D; + } + if (lt->R == 0){ + R = 0; + } } + if (R) + r->Delta = Infinity; /* Read-only resource, no exclusion */ } - for (lt = tasks.next; lt ; lt = lt->next){ - t = lt->i; + + /* Enumerate the critical sections */ + for (l = tasks.next; l ; l = l->next){ + t = l->i; assert(t); - if (t->state < EdfIdle) + if (t->state <= EdfExpelled) continue; - t->Delta = t->D; - for (lr = t->res.next; lr; lr = lr->next){ - r = lr->i; + t->Delta = Infinity; + for (c = (CSN*)t->csns.next; c; c = (CSN*)c->next){ + r = c->i; assert(r); - if (r->Delta < t->Delta) + c->Delta = r->Delta; + if (c->p && c->p->Delta < c->Delta) + c->Delta = c->p->Delta; + if (c->C == t->C && r->Delta < t->Delta) t->Delta = r->Delta; } } @@ -814,55 +870,104 @@ testdelta(Task *thetask) { Resource *r; Task *t; - List *lr, *lt; + int R; + List *lr, *l; + TaskLink *lt; + CSN *c; for (lr = resources.next; lr; lr = lr->next){ r = lr->i; assert(r); - r->testDelta = ~0ULL; - for (lt = r->tasks.next; lt; lt = lt->next){ + DEBUG("Resource %s: ", r->name); + r->testDelta = Infinity; + R = 1; + for (lt = (TaskLink*)r->tasks.next; lt; lt = (TaskLink*)lt->next){ t = lt->i; assert(t); - if (t->D < r->testDelta) + if (t->D < r->testDelta){ r->testDelta = t->D; + DEBUG("%d→%T ", t->taskno, ticks2time(t->D)); + } + if (lt->R == 0){ + DEBUG("%d→X ", t->taskno); + R = 0; + } } + if (R) + r->testDelta = Infinity; /* Read-only resource, no exclusion */ + DEBUG("tΔ = %T\n", ticks2time(r->testDelta)); } - for (lt = tasks.next; lt ; lt = lt->next){ - t = lt->i; + + /* Enumerate the critical sections */ + for (l = tasks.next; l ; l = l->next){ + t = l->i; assert(t); if (t->state <= EdfExpelled && t != thetask) continue; - t->testDelta = t->D; - for (lr = t->res.next; lr; lr = lr->next){ - r = lr->i; + t->testDelta = Infinity; + for (c = (CSN*)t->csns.next; c; c = (CSN*)c->next){ + r = c->i; assert(r); - if (r->testDelta < t->testDelta) + c->testDelta = r->testDelta; + if (c->p && c->p->testDelta < c->testDelta) + c->testDelta = c->p->testDelta; + if (c->C == t->C && r->testDelta < t->testDelta) t->testDelta = r->testDelta; + DEBUG("Task %d Resource %s: tΔ = %T\n", + t->taskno, r->name, ticks2time(r->testDelta)); } } } static Ticks -blockcost(Ticks ticks, Task *thetask) +blockcost(Ticks ticks, Task *task, Task *thetask) { + Ticks Cb, Cbt; + List *l; + Resource *r; + CSN *c, *lc; + int R; Task *t; - Ticks Cb; - List *lt; Cb = 0; - for (lt = tasks.next; lt ; lt = lt->next){ - t = lt->i; - assert(t); - if (t->state <= EdfExpelled && t != thetask) - continue; - if (t->testDelta <= ticks && ticks < t->D && Cb < t->C) - Cb = t->C; + /* for each resource in task t, find all CSNs that refer to the + * resource. If their Δ <= ticks < D and c->C > current CB + * Cb = c->C + */ + DEBUG("blockcost task %d: ", task->taskno); + for (c = (CSN*)task->csns.next; c; c = (CSN*)c->next){ + r = c->i; + assert(r); + + DEBUG("%s ", r->name); + Cbt = Cb; + R = 1; /* R == 1: resource is only used in read-only mode */ + for (l = tasks.next; l; l = l->next){ + t = l->i; + if (t->state <= EdfExpelled && t != thetask) + continue; /* csn belongs to an irrelevant task */ + for (lc = (CSN*)t->csns.next; lc; lc = (CSN*)lc->next){ + if (lc->i != r) + continue; /* wrong resource */ + if (lc->R == 0) + R = 0; /* Resource is used in exclusive mode */ + DEBUG("(%T≤%T<%T: %T) ", + ticks2time(lc->testDelta), ticks2time(ticks), ticks2time(t->D), + ticks2time(lc->C)); + if (lc->testDelta <= ticks && ticks < t->D && Cbt < lc->C) + Cbt = lc->C; + } + } + if (R == 0){ + DEBUG("%T, ", ticks2time(Cbt)); + Cb = Cbt; + } + DEBUG("ro, "); } + DEBUG("Cb = %T\n", ticks2time(Cb)); return Cb; } -static Task *qschedulability; - static void testenq(Task *t) { @@ -898,7 +1003,7 @@ edftestschedulability(Task *thetask) /* initialize */ testdelta(thetask); if (thetask && (thetask->flags & Verbose)) - pprint("schedulability test\n"); + pprint("schedulability test for task %d\n", thetask->taskno); qschedulability = nil; for (l = tasks.next; l; l = l->next){ t = l->i; @@ -908,7 +1013,7 @@ edftestschedulability(Task *thetask) t->testtype = Release; t->testtime = 0; if (thetask && (thetask->flags & Verbose)) - pprint("\tInit: enqueue task %lud\n", t->taskno); + pprint("\tInit: enqueue task %d\n", t->taskno); testenq(t); } H=0; @@ -920,24 +1025,32 @@ edftestschedulability(Task *thetask) switch (t->testtype){ case Deadline: H += t->C; - Cb = blockcost(ticks, thetask); + Cb = blockcost(ticks, t, thetask); if (thetask && (thetask->flags & Verbose)) - pprint("\tStep %3d, Ticks %T, task %lud, deadline, H += %T → %T, Cb = %T\n", + pprint("\tStep %3d, Ticks %T, task %d, deadline, H += %T → %T, Cb = %T\n", steps, ticks2time(ticks), t->taskno, ticks2time(t->C), ticks2time(H), ticks2time(Cb)); - if (H+Cb>ticks) + if (H+Cb>ticks){ + if (thetask && (thetask->flags & Verbose)) + pprint("task %d not schedulable: H=%T + Cb=%T > ticks=%T\n", + thetask->taskno, ticks2time(H), ticks2time(Cb), ticks2time(ticks)); return "not schedulable"; + } t->testtime += t->T - t->D; t->testtype = Release; testenq(t); break; case Release: if (thetask && (thetask->flags & Verbose)) - pprint("\tStep %3d, Ticks %T, task %lud, release, G %T, C%T\n", + pprint("\tStep %3d, Ticks %T, task %d, release, G %T, C%T\n", steps, ticks2time(ticks), t->taskno, ticks2time(t->C), ticks2time(G)); - if(ticks && G <= ticks) + if(ticks && G <= ticks){ + if (thetask && (thetask->flags & Verbose)) + pprint("task %d schedulable: G=%T <= ticks=%T\n", + thetask->taskno, ticks2time(G), ticks2time(ticks)); return nil; + } G += t->C; t->testtime += t->D; t->testtype = Deadline; @@ -950,32 +1063,64 @@ edftestschedulability(Task *thetask) return "probably not schedulable"; } -static uvlong -uvmuldiv(uvlong x, ulong num, ulong den) +static void +resacquire(Task *t, CSN *c) { - /* multiply, then divide, avoiding overflow */ - uvlong hi; + Ticks now, when, used; - hi = (x & 0xffffffff00000000LL) >> 32; - x &= 0xffffffffLL; - hi *= num; - return (x*num + (hi%den << 32)) / den + (hi/den << 32); + now = fastticks(nil); + used = now - t->scheduled; + t->scheduled = now; + t->total += used; + t->S -= used; + if (t->curcsn) + t->curcsn->S -= used; + when = now + c->S; + if (when < deadlinetimer[m->machno].when){ + timerdel(&deadlinetimer[m->machno]); + deadlinetimer[m->machno].when = when; + timeradd(&deadlinetimer[m->machno]); + } + t->Delta = c->Delta; + t->curcsn = c; + /* priority is going up, no need to reschedule */ } -Time -ticks2time(Ticks ticks) +static void +resrelease(Task *t) { - assert(ticks >= 0); - if (fasthz == 0) - fastticks(&fasthz); - return uvmuldiv(ticks, Onesecond, fasthz); -} + Ticks now, when, used; + CSN *c; -Ticks -time2ticks(Time time) -{ - assert(time >= 0); - return uvmuldiv(time, fasthz, Onesecond); + c = t->curcsn; + assert(c); + t->curcsn = c->p; + now = fastticks(nil); + used = now - t->scheduled; + t->scheduled = now; + t->total += used; + t->S -= used; + c->S -= used; + if (now + t->S > t->d) + when = t->d; + else + when = now + t->S; + if (t->curcsn){ + t->curcsn->S -= c->S; /* the sins of the fathers shall be visited upon the children */ + t->Delta = t->curcsn->Delta; + if (when > now + t->curcsn->S) + when = now + t->curcsn->S; + }else + t->Delta = Infinity; + c->S = 0LL; /* don't allow reuse */ + if (deadlinetimer[m->machno].when) + timerdel(&deadlinetimer[m->machno]); + deadlinetimer[m->machno].when = when; + timeradd(&deadlinetimer[m->machno]); + + qunlock(&edfschedlock); + sched(); /* reschedule */ + qlock(&edfschedlock); } Edfinterface realedf = { @@ -989,4 +1134,6 @@ Edfinterface realedf = { .edfexpel = edfexpel, .edfadmit = edfadmit, .edfdeadline = edfdeadline, + .resacquire = resacquire, + .resrelease = resrelease, }; diff --git a/port/nulledf.c b/port/nulledf.c index db630b20ee238e3a5dd7e43cb8d27a4c1c17021a..c9aeafee5f9b3df381ac94bae8f481ad7b5a0d50 100644 --- a/port/nulledf.c +++ b/port/nulledf.c @@ -4,7 +4,7 @@ #include "dat.h" #include "fns.h" #include "../port/error.h" -#include "../port/edf.h" +#include "../port/realtime.h" static int isedf(Proc*)