19ef1f84bSDavid du Colombier /* EDF scheduling */
29ef1f84bSDavid du Colombier #include "u.h"
39ef1f84bSDavid du Colombier #include "../port/lib.h"
49ef1f84bSDavid du Colombier #include "mem.h"
59ef1f84bSDavid du Colombier #include "dat.h"
69ef1f84bSDavid du Colombier #include "fns.h"
79ef1f84bSDavid du Colombier #include "../port/error.h"
89ef1f84bSDavid du Colombier
99ef1f84bSDavid du Colombier #include "../port/edf.h"
10*d46407a3SDavid du Colombier #include <ptrace.h>
119ef1f84bSDavid du Colombier
129ef1f84bSDavid du Colombier /* debugging */
139ef1f84bSDavid du Colombier enum {
149ef1f84bSDavid du Colombier Dontprint = 1,
159ef1f84bSDavid du Colombier };
169ef1f84bSDavid du Colombier
179ef1f84bSDavid du Colombier #define DPRINT if(Dontprint){}else print
189ef1f84bSDavid du Colombier
199ef1f84bSDavid du Colombier static long now; /* Low order 32 bits of time in µs */
209ef1f84bSDavid du Colombier extern ulong delayedscheds;
219ef1f84bSDavid du Colombier extern Schedq runq[Nrq];
229ef1f84bSDavid du Colombier extern int nrdy;
239ef1f84bSDavid du Colombier extern ulong runvec;
249ef1f84bSDavid du Colombier
259ef1f84bSDavid du Colombier /* Statistics stuff */
269ef1f84bSDavid du Colombier ulong nilcount;
279ef1f84bSDavid du Colombier ulong scheds;
289ef1f84bSDavid du Colombier ulong edfnrun;
299ef1f84bSDavid du Colombier int misseddeadlines;
309ef1f84bSDavid du Colombier
319ef1f84bSDavid du Colombier /* Edfschedlock protects modification of admission params */
329ef1f84bSDavid du Colombier int edfinited;
339ef1f84bSDavid du Colombier QLock edfschedlock;
349ef1f84bSDavid du Colombier static Lock thelock;
359ef1f84bSDavid du Colombier
369ef1f84bSDavid du Colombier enum{
379ef1f84bSDavid du Colombier Dl, /* Invariant for schedulability test: Dl < Rl */
389ef1f84bSDavid du Colombier Rl,
399ef1f84bSDavid du Colombier };
409ef1f84bSDavid du Colombier
419ef1f84bSDavid du Colombier static char *testschedulability(Proc*);
429ef1f84bSDavid du Colombier static Proc *qschedulability;
439ef1f84bSDavid du Colombier
449ef1f84bSDavid du Colombier enum {
459ef1f84bSDavid du Colombier Onemicrosecond = 1,
469ef1f84bSDavid du Colombier Onemillisecond = 1000,
479ef1f84bSDavid du Colombier Onesecond = 1000000,
489ef1f84bSDavid du Colombier OneRound = Onemillisecond/2,
499ef1f84bSDavid du Colombier };
509ef1f84bSDavid du Colombier
519ef1f84bSDavid du Colombier static int
timeconv(Fmt * f)529ef1f84bSDavid du Colombier timeconv(Fmt *f)
539ef1f84bSDavid du Colombier {
549ef1f84bSDavid du Colombier char buf[128], *sign;
559ef1f84bSDavid du Colombier vlong t;
569ef1f84bSDavid du Colombier
579ef1f84bSDavid du Colombier buf[0] = 0;
589ef1f84bSDavid du Colombier switch(f->r) {
599ef1f84bSDavid du Colombier case 'U':
609ef1f84bSDavid du Colombier t = va_arg(f->args, uvlong);
619ef1f84bSDavid du Colombier break;
629ef1f84bSDavid du Colombier case 't': /* vlong in nanoseconds */
639ef1f84bSDavid du Colombier t = va_arg(f->args, long);
649ef1f84bSDavid du Colombier break;
659ef1f84bSDavid du Colombier default:
669ef1f84bSDavid du Colombier return fmtstrcpy(f, "(timeconv)");
679ef1f84bSDavid du Colombier }
689ef1f84bSDavid du Colombier if (t < 0) {
699ef1f84bSDavid du Colombier sign = "-";
709ef1f84bSDavid du Colombier t = -t;
719ef1f84bSDavid du Colombier }
729ef1f84bSDavid du Colombier else
739ef1f84bSDavid du Colombier sign = "";
749ef1f84bSDavid du Colombier if (t > Onesecond){
759ef1f84bSDavid du Colombier t += OneRound;
76406c76faSDavid du Colombier snprint(buf, sizeof buf, "%s%d.%.3ds", sign,
77406c76faSDavid du Colombier (int)(t / Onesecond),
789ef1f84bSDavid du Colombier (int)(t % Onesecond)/Onemillisecond);
799ef1f84bSDavid du Colombier }else if (t > Onemillisecond)
80406c76faSDavid du Colombier snprint(buf, sizeof buf, "%s%d.%.3dms", sign,
81406c76faSDavid du Colombier (int)(t / Onemillisecond), (int)(t % Onemillisecond));
829ef1f84bSDavid du Colombier else
83406c76faSDavid du Colombier snprint(buf, sizeof buf, "%s%dµs", sign, (int)t);
849ef1f84bSDavid du Colombier return fmtstrcpy(f, buf);
859ef1f84bSDavid du Colombier }
869ef1f84bSDavid du Colombier
879ef1f84bSDavid du Colombier long edfcycles;
889ef1f84bSDavid du Colombier
899ef1f84bSDavid du Colombier Edf*
edflock(Proc * p)909ef1f84bSDavid du Colombier edflock(Proc *p)
919ef1f84bSDavid du Colombier {
929ef1f84bSDavid du Colombier Edf *e;
939ef1f84bSDavid du Colombier
949ef1f84bSDavid du Colombier if (p->edf == nil)
959ef1f84bSDavid du Colombier return nil;
969ef1f84bSDavid du Colombier ilock(&thelock);
979ef1f84bSDavid du Colombier if((e = p->edf) && (e->flags & Admitted)){
989ef1f84bSDavid du Colombier thelock.pc = getcallerpc(&p);
999ef1f84bSDavid du Colombier #ifdef EDFCYCLES
1009ef1f84bSDavid du Colombier edfcycles -= lcycles();
1019ef1f84bSDavid du Colombier #endif
1029ef1f84bSDavid du Colombier now = µs();
1039ef1f84bSDavid du Colombier return e;
1049ef1f84bSDavid du Colombier }
1059ef1f84bSDavid du Colombier iunlock(&thelock);
1069ef1f84bSDavid du Colombier return nil;
1079ef1f84bSDavid du Colombier }
1089ef1f84bSDavid du Colombier
1099ef1f84bSDavid du Colombier void
edfunlock(void)1109ef1f84bSDavid du Colombier edfunlock(void)
1119ef1f84bSDavid du Colombier {
1129ef1f84bSDavid du Colombier
1139ef1f84bSDavid du Colombier #ifdef EDFCYCLES
1149ef1f84bSDavid du Colombier edfcycles += lcycles();
1159ef1f84bSDavid du Colombier #endif
1169ef1f84bSDavid du Colombier edfnrun++;
1179ef1f84bSDavid du Colombier iunlock(&thelock);
1189ef1f84bSDavid du Colombier }
1199ef1f84bSDavid du Colombier
1209ef1f84bSDavid du Colombier void
edfinit(Proc * p)1219ef1f84bSDavid du Colombier edfinit(Proc*p)
1229ef1f84bSDavid du Colombier {
1239ef1f84bSDavid du Colombier if(!edfinited){
1249ef1f84bSDavid du Colombier fmtinstall('t', timeconv);
1259ef1f84bSDavid du Colombier edfinited++;
1269ef1f84bSDavid du Colombier }
1279ef1f84bSDavid du Colombier now = µs();
1289ef1f84bSDavid du Colombier DPRINT("%lud edfinit %d[%s]\n", now, p->pid, statename[p->state]);
1299ef1f84bSDavid du Colombier p->edf = malloc(sizeof(Edf));
1309ef1f84bSDavid du Colombier if(p->edf == nil)
1319ef1f84bSDavid du Colombier error(Enomem);
1329ef1f84bSDavid du Colombier return;
1339ef1f84bSDavid du Colombier }
1349ef1f84bSDavid du Colombier
1359ef1f84bSDavid du Colombier static void
deadlineintr(Ureg *,Timer * t)1369ef1f84bSDavid du Colombier deadlineintr(Ureg*, Timer *t)
1379ef1f84bSDavid du Colombier {
1389ef1f84bSDavid du Colombier /* Proc reached deadline */
1399ef1f84bSDavid du Colombier extern int panicking;
1409ef1f84bSDavid du Colombier Proc *p;
141*d46407a3SDavid du Colombier void (*pt)(Proc*, int, vlong, vlong);
1429ef1f84bSDavid du Colombier
1439ef1f84bSDavid du Colombier if(panicking || active.exiting)
1449ef1f84bSDavid du Colombier return;
1459ef1f84bSDavid du Colombier
1469ef1f84bSDavid du Colombier p = t->ta;
1479ef1f84bSDavid du Colombier now = µs();
1489ef1f84bSDavid du Colombier DPRINT("%lud deadlineintr %d[%s]\n", now, p->pid, statename[p->state]);
1499ef1f84bSDavid du Colombier /* If we're interrupting something other than the proc pointed to by t->a,
1509ef1f84bSDavid du Colombier * we've already achieved recheduling, so we need not do anything
1519ef1f84bSDavid du Colombier * Otherwise, we must cause a reschedule, but if we call sched()
1529ef1f84bSDavid du Colombier * here directly, the timer interrupt routine will not finish its business
1539ef1f84bSDavid du Colombier * Instead, we cause the resched to happen when the interrupted proc
1549ef1f84bSDavid du Colombier * returns to user space
1559ef1f84bSDavid du Colombier */
1569ef1f84bSDavid du Colombier if(p == up){
1579ef1f84bSDavid du Colombier if(up->trace && (pt = proctrace))
158*d46407a3SDavid du Colombier pt(up, SInts, 0, 0);
1599ef1f84bSDavid du Colombier up->delaysched++;
1609ef1f84bSDavid du Colombier delayedscheds++;
1619ef1f84bSDavid du Colombier }
1629ef1f84bSDavid du Colombier }
1639ef1f84bSDavid du Colombier
1649ef1f84bSDavid du Colombier static void
release(Proc * p)1659ef1f84bSDavid du Colombier release(Proc *p)
1669ef1f84bSDavid du Colombier {
1679ef1f84bSDavid du Colombier /* Called with edflock held */
1689ef1f84bSDavid du Colombier Edf *e;
169*d46407a3SDavid du Colombier void (*pt)(Proc*, int, vlong, vlong);
1709ef1f84bSDavid du Colombier long n;
1719ef1f84bSDavid du Colombier vlong nowns;
1729ef1f84bSDavid du Colombier
1739ef1f84bSDavid du Colombier e = p->edf;
1749ef1f84bSDavid du Colombier e->flags &= ~Yield;
1759ef1f84bSDavid du Colombier if(e->d - now < 0){
1769ef1f84bSDavid du Colombier e->periods++;
1779ef1f84bSDavid du Colombier e->r = now;
1789ef1f84bSDavid du Colombier if((e->flags & Sporadic) == 0){
1799ef1f84bSDavid du Colombier /*
1809ef1f84bSDavid du Colombier * Non sporadic processes stay true to their period;
1819ef1f84bSDavid du Colombier * calculate next release time.
1829ef1f84bSDavid du Colombier * Second test limits duration of while loop.
1839ef1f84bSDavid du Colombier */
1849ef1f84bSDavid du Colombier if((n = now - e->t) > 0){
1859ef1f84bSDavid du Colombier if(n < e->T)
1869ef1f84bSDavid du Colombier e->t += e->T;
1879ef1f84bSDavid du Colombier else
1889ef1f84bSDavid du Colombier e->t = now + e->T - (n % e->T);
1899ef1f84bSDavid du Colombier }
1909ef1f84bSDavid du Colombier }else{
1919ef1f84bSDavid du Colombier /* Sporadic processes may not be released earlier than
1929ef1f84bSDavid du Colombier * one period after this release
1939ef1f84bSDavid du Colombier */
1949ef1f84bSDavid du Colombier e->t = e->r + e->T;
1959ef1f84bSDavid du Colombier }
1969ef1f84bSDavid du Colombier e->d = e->r + e->D;
1979ef1f84bSDavid du Colombier e->S = e->C;
1989ef1f84bSDavid du Colombier DPRINT("%lud release %d[%s], r=%lud, d=%lud, t=%lud, S=%lud\n",
1999ef1f84bSDavid du Colombier now, p->pid, statename[p->state], e->r, e->d, e->t, e->S);
2009ef1f84bSDavid du Colombier if(pt = proctrace){
2019ef1f84bSDavid du Colombier nowns = todget(nil);
202*d46407a3SDavid du Colombier pt(p, SRelease, nowns, 0);
203*d46407a3SDavid du Colombier pt(p, SDeadline, nowns + 1000LL*e->D, 0);
2049ef1f84bSDavid du Colombier }
2059ef1f84bSDavid du Colombier }else{
2069ef1f84bSDavid du Colombier DPRINT("%lud release %d[%s], too late t=%lud, called from %#p\n",
2079ef1f84bSDavid du Colombier now, p->pid, statename[p->state], e->t, getcallerpc(&p));
2089ef1f84bSDavid du Colombier }
2099ef1f84bSDavid du Colombier }
2109ef1f84bSDavid du Colombier
2119ef1f84bSDavid du Colombier static void
releaseintr(Ureg *,Timer * t)2129ef1f84bSDavid du Colombier releaseintr(Ureg*, Timer *t)
2139ef1f84bSDavid du Colombier {
2149ef1f84bSDavid du Colombier Proc *p;
2159ef1f84bSDavid du Colombier extern int panicking;
2169ef1f84bSDavid du Colombier Schedq *rq;
2179ef1f84bSDavid du Colombier
2189ef1f84bSDavid du Colombier if(panicking || active.exiting)
2199ef1f84bSDavid du Colombier return;
2209ef1f84bSDavid du Colombier
2219ef1f84bSDavid du Colombier p = t->ta;
2229ef1f84bSDavid du Colombier if((edflock(p)) == nil)
2239ef1f84bSDavid du Colombier return;
2249ef1f84bSDavid du Colombier DPRINT("%lud releaseintr %d[%s]\n", now, p->pid, statename[p->state]);
2259ef1f84bSDavid du Colombier switch(p->state){
2269ef1f84bSDavid du Colombier default:
2279ef1f84bSDavid du Colombier edfunlock();
2289ef1f84bSDavid du Colombier return;
2299ef1f84bSDavid du Colombier case Ready:
2309ef1f84bSDavid du Colombier /* remove proc from current runq */
2319ef1f84bSDavid du Colombier rq = &runq[p->priority];
2329ef1f84bSDavid du Colombier if(dequeueproc(rq, p) != p){
2339ef1f84bSDavid du Colombier DPRINT("releaseintr: can't find proc or lock race\n");
2349ef1f84bSDavid du Colombier release(p); /* It'll start best effort */
2359ef1f84bSDavid du Colombier edfunlock();
2369ef1f84bSDavid du Colombier return;
2379ef1f84bSDavid du Colombier }
2389ef1f84bSDavid du Colombier p->state = Waitrelease;
2399ef1f84bSDavid du Colombier /* fall through */
2409ef1f84bSDavid du Colombier case Waitrelease:
2419ef1f84bSDavid du Colombier release(p);
2429ef1f84bSDavid du Colombier edfunlock();
2439ef1f84bSDavid du Colombier if(p->state == Wakeme){
2449ef1f84bSDavid du Colombier iprint("releaseintr: wakeme\n");
2459ef1f84bSDavid du Colombier }
2469ef1f84bSDavid du Colombier ready(p);
2479ef1f84bSDavid du Colombier if(up){
2489ef1f84bSDavid du Colombier up->delaysched++;
2499ef1f84bSDavid du Colombier delayedscheds++;
2509ef1f84bSDavid du Colombier }
2519ef1f84bSDavid du Colombier return;
2529ef1f84bSDavid du Colombier case Running:
2539ef1f84bSDavid du Colombier release(p);
2549ef1f84bSDavid du Colombier edfrun(p, 1);
2559ef1f84bSDavid du Colombier break;
2569ef1f84bSDavid du Colombier case Wakeme:
2579ef1f84bSDavid du Colombier release(p);
2589ef1f84bSDavid du Colombier edfunlock();
2599ef1f84bSDavid du Colombier if(p->trend)
2609ef1f84bSDavid du Colombier wakeup(p->trend);
2619ef1f84bSDavid du Colombier p->trend = nil;
2629ef1f84bSDavid du Colombier if(up){
2639ef1f84bSDavid du Colombier up->delaysched++;
2649ef1f84bSDavid du Colombier delayedscheds++;
2659ef1f84bSDavid du Colombier }
2669ef1f84bSDavid du Colombier return;
2679ef1f84bSDavid du Colombier }
2689ef1f84bSDavid du Colombier edfunlock();
2699ef1f84bSDavid du Colombier }
2709ef1f84bSDavid du Colombier
2719ef1f84bSDavid du Colombier void
edfrecord(Proc * p)2729ef1f84bSDavid du Colombier edfrecord(Proc *p)
2739ef1f84bSDavid du Colombier {
2749ef1f84bSDavid du Colombier long used;
2759ef1f84bSDavid du Colombier Edf *e;
276*d46407a3SDavid du Colombier void (*pt)(Proc*, int, vlong, vlong);
2779ef1f84bSDavid du Colombier
2789ef1f84bSDavid du Colombier if((e = edflock(p)) == nil)
2799ef1f84bSDavid du Colombier return;
2809ef1f84bSDavid du Colombier used = now - e->s;
2819ef1f84bSDavid du Colombier if(e->d - now <= 0)
2829ef1f84bSDavid du Colombier e->edfused += used;
2839ef1f84bSDavid du Colombier else
2849ef1f84bSDavid du Colombier e->extraused += used;
2859ef1f84bSDavid du Colombier if(e->S > 0){
2869ef1f84bSDavid du Colombier if(e->S <= used){
2879ef1f84bSDavid du Colombier if(pt = proctrace)
288*d46407a3SDavid du Colombier pt(p, SSlice, 0, 0);
2899ef1f84bSDavid du Colombier DPRINT("%lud edfrecord slice used up\n", now);
2909ef1f84bSDavid du Colombier e->d = now;
2919ef1f84bSDavid du Colombier e->S = 0;
2929ef1f84bSDavid du Colombier }else
2939ef1f84bSDavid du Colombier e->S -= used;
2949ef1f84bSDavid du Colombier }
2959ef1f84bSDavid du Colombier e->s = now;
2969ef1f84bSDavid du Colombier edfunlock();
2979ef1f84bSDavid du Colombier }
2989ef1f84bSDavid du Colombier
2999ef1f84bSDavid du Colombier void
edfrun(Proc * p,int edfpri)3009ef1f84bSDavid du Colombier edfrun(Proc *p, int edfpri)
3019ef1f84bSDavid du Colombier {
3029ef1f84bSDavid du Colombier Edf *e;
303*d46407a3SDavid du Colombier void (*pt)(Proc*, int, vlong, vlong);
3049ef1f84bSDavid du Colombier long tns;
3059ef1f84bSDavid du Colombier
3069ef1f84bSDavid du Colombier e = p->edf;
3079ef1f84bSDavid du Colombier /* Called with edflock held */
3089ef1f84bSDavid du Colombier if(edfpri){
3099ef1f84bSDavid du Colombier tns = e->d - now;
3109ef1f84bSDavid du Colombier if(tns <= 0 || e->S == 0){
3119ef1f84bSDavid du Colombier /* Deadline reached or resources exhausted,
3129ef1f84bSDavid du Colombier * deschedule forthwith
3139ef1f84bSDavid du Colombier */
3149ef1f84bSDavid du Colombier p->delaysched++;
3159ef1f84bSDavid du Colombier delayedscheds++;
3169ef1f84bSDavid du Colombier e->s = now;
3179ef1f84bSDavid du Colombier return;
3189ef1f84bSDavid du Colombier }
3199ef1f84bSDavid du Colombier if(e->S < tns)
3209ef1f84bSDavid du Colombier tns = e->S;
3219ef1f84bSDavid du Colombier if(tns < 20)
3229ef1f84bSDavid du Colombier tns = 20;
3239ef1f84bSDavid du Colombier e->tns = 1000LL * tns; /* µs to ns */
3249ef1f84bSDavid du Colombier if(e->tt == nil || e->tf != deadlineintr){
3259ef1f84bSDavid du Colombier DPRINT("%lud edfrun, deadline=%lud\n", now, tns);
3269ef1f84bSDavid du Colombier }else{
3279ef1f84bSDavid du Colombier DPRINT("v");
3289ef1f84bSDavid du Colombier }
3299ef1f84bSDavid du Colombier if(p->trace && (pt = proctrace))
330*d46407a3SDavid du Colombier pt(p, SInte, todget(nil) + e->tns, 0);
3319ef1f84bSDavid du Colombier e->tmode = Trelative;
3329ef1f84bSDavid du Colombier e->tf = deadlineintr;
3339ef1f84bSDavid du Colombier e->ta = p;
3349ef1f84bSDavid du Colombier timeradd(e);
3359ef1f84bSDavid du Colombier }else{
3369ef1f84bSDavid du Colombier DPRINT("<");
3379ef1f84bSDavid du Colombier }
3389ef1f84bSDavid du Colombier e->s = now;
3399ef1f84bSDavid du Colombier }
3409ef1f84bSDavid du Colombier
3419ef1f84bSDavid du Colombier char *
edfadmit(Proc * p)3429ef1f84bSDavid du Colombier edfadmit(Proc *p)
3439ef1f84bSDavid du Colombier {
3449ef1f84bSDavid du Colombier char *err;
3459ef1f84bSDavid du Colombier Edf *e;
3469ef1f84bSDavid du Colombier int i;
3479ef1f84bSDavid du Colombier Proc *r;
348*d46407a3SDavid du Colombier void (*pt)(Proc*, int, vlong, vlong);
3499ef1f84bSDavid du Colombier long tns;
3509ef1f84bSDavid du Colombier
3519ef1f84bSDavid du Colombier e = p->edf;
3529ef1f84bSDavid du Colombier if (e->flags & Admitted)
3539ef1f84bSDavid du Colombier return "task state"; /* should never happen */
3549ef1f84bSDavid du Colombier
3559ef1f84bSDavid du Colombier /* simple sanity checks */
3569ef1f84bSDavid du Colombier if (e->T == 0)
3579ef1f84bSDavid du Colombier return "T not set";
3589ef1f84bSDavid du Colombier if (e->C == 0)
3599ef1f84bSDavid du Colombier return "C not set";
3609ef1f84bSDavid du Colombier if (e->D > e->T)
3619ef1f84bSDavid du Colombier return "D > T";
3629ef1f84bSDavid du Colombier if (e->D == 0) /* if D is not set, set it to T */
3639ef1f84bSDavid du Colombier e->D = e->T;
3649ef1f84bSDavid du Colombier if (e->C > e->D)
3659ef1f84bSDavid du Colombier return "C > D";
3669ef1f84bSDavid du Colombier
3679ef1f84bSDavid du Colombier qlock(&edfschedlock);
3689ef1f84bSDavid du Colombier if (err = testschedulability(p)){
3699ef1f84bSDavid du Colombier qunlock(&edfschedlock);
3709ef1f84bSDavid du Colombier return err;
3719ef1f84bSDavid du Colombier }
3729ef1f84bSDavid du Colombier e->flags |= Admitted;
3739ef1f84bSDavid du Colombier
3749ef1f84bSDavid du Colombier edflock(p);
3759ef1f84bSDavid du Colombier
3769ef1f84bSDavid du Colombier if(p->trace && (pt = proctrace))
377*d46407a3SDavid du Colombier pt(p, SAdmit, 0, 0);
3789ef1f84bSDavid du Colombier
3799ef1f84bSDavid du Colombier /* Look for another proc with the same period to synchronize to */
3809ef1f84bSDavid du Colombier for(i=0; (r = psincref(i)) != nil; i++) {
3819ef1f84bSDavid du Colombier if(r->state == Dead || r == p){
3829ef1f84bSDavid du Colombier psdecref(r);
3839ef1f84bSDavid du Colombier continue;
3849ef1f84bSDavid du Colombier }
3859ef1f84bSDavid du Colombier if (r->edf == nil || (r->edf->flags & Admitted) == 0){
3869ef1f84bSDavid du Colombier psdecref(r);
3879ef1f84bSDavid du Colombier continue;
3889ef1f84bSDavid du Colombier }
3899ef1f84bSDavid du Colombier if (r->edf->T == e->T)
3909ef1f84bSDavid du Colombier break;
3919ef1f84bSDavid du Colombier }
3929ef1f84bSDavid du Colombier if (r == nil){
3939ef1f84bSDavid du Colombier /* Can't synchronize to another proc, release now */
3949ef1f84bSDavid du Colombier e->t = now;
3959ef1f84bSDavid du Colombier e->d = 0;
3969ef1f84bSDavid du Colombier release(p);
3979ef1f84bSDavid du Colombier if (p == up){
3989ef1f84bSDavid du Colombier DPRINT("%lud edfadmit self %d[%s], release now: r=%lud d=%lud t=%lud\n",
3999ef1f84bSDavid du Colombier now, p->pid, statename[p->state], e->r, e->d, e->t);
4009ef1f84bSDavid du Colombier /* We're already running */
4019ef1f84bSDavid du Colombier edfrun(p, 1);
4029ef1f84bSDavid du Colombier }else{
4039ef1f84bSDavid du Colombier /* We're releasing another proc */
4049ef1f84bSDavid du Colombier DPRINT("%lud edfadmit other %d[%s], release now: r=%lud d=%lud t=%lud\n",
4059ef1f84bSDavid du Colombier now, p->pid, statename[p->state], e->r, e->d, e->t);
4069ef1f84bSDavid du Colombier p->ta = p;
4079ef1f84bSDavid du Colombier edfunlock();
4089ef1f84bSDavid du Colombier qunlock(&edfschedlock);
4099ef1f84bSDavid du Colombier releaseintr(nil, p);
4109ef1f84bSDavid du Colombier return nil;
4119ef1f84bSDavid du Colombier }
4129ef1f84bSDavid du Colombier }else{
4139ef1f84bSDavid du Colombier /* Release in synch to something else */
4149ef1f84bSDavid du Colombier e->t = r->edf->t;
4159ef1f84bSDavid du Colombier psdecref(r);
4169ef1f84bSDavid du Colombier if (p == up){
4179ef1f84bSDavid du Colombier DPRINT("%lud edfadmit self %d[%s], release at %lud\n",
4189ef1f84bSDavid du Colombier now, p->pid, statename[p->state], e->t);
4199ef1f84bSDavid du Colombier }else{
4209ef1f84bSDavid du Colombier DPRINT("%lud edfadmit other %d[%s], release at %lud\n",
4219ef1f84bSDavid du Colombier now, p->pid, statename[p->state], e->t);
4229ef1f84bSDavid du Colombier if(e->tt == nil){
4239ef1f84bSDavid du Colombier e->tf = releaseintr;
4249ef1f84bSDavid du Colombier e->ta = p;
4259ef1f84bSDavid du Colombier tns = e->t - now;
4269ef1f84bSDavid du Colombier if(tns < 20)
4279ef1f84bSDavid du Colombier tns = 20;
4289ef1f84bSDavid du Colombier e->tns = 1000LL * tns;
4299ef1f84bSDavid du Colombier e->tmode = Trelative;
4309ef1f84bSDavid du Colombier timeradd(e);
4319ef1f84bSDavid du Colombier }
4329ef1f84bSDavid du Colombier }
4339ef1f84bSDavid du Colombier }
4349ef1f84bSDavid du Colombier edfunlock();
4359ef1f84bSDavid du Colombier qunlock(&edfschedlock);
4369ef1f84bSDavid du Colombier return nil;
4379ef1f84bSDavid du Colombier }
4389ef1f84bSDavid du Colombier
4399ef1f84bSDavid du Colombier void
edfstop(Proc * p)4409ef1f84bSDavid du Colombier edfstop(Proc *p)
4419ef1f84bSDavid du Colombier {
4429ef1f84bSDavid du Colombier Edf *e;
443*d46407a3SDavid du Colombier void (*pt)(Proc*, int, vlong, vlong);
4449ef1f84bSDavid du Colombier
4459ef1f84bSDavid du Colombier if(e = edflock(p)){
4469ef1f84bSDavid du Colombier DPRINT("%lud edfstop %d[%s]\n", now, p->pid, statename[p->state]);
4479ef1f84bSDavid du Colombier if(p->trace && (pt = proctrace))
448*d46407a3SDavid du Colombier pt(p, SExpel, 0, 0);
4499ef1f84bSDavid du Colombier e->flags &= ~Admitted;
4509ef1f84bSDavid du Colombier if(e->tt)
4519ef1f84bSDavid du Colombier timerdel(e);
4529ef1f84bSDavid du Colombier edfunlock();
4539ef1f84bSDavid du Colombier }
4549ef1f84bSDavid du Colombier }
4559ef1f84bSDavid du Colombier
4569ef1f84bSDavid du Colombier static int
yfn(void *)4579ef1f84bSDavid du Colombier yfn(void *)
4589ef1f84bSDavid du Colombier {
4599ef1f84bSDavid du Colombier now = µs();
4609ef1f84bSDavid du Colombier return up->trend == nil || now - up->edf->r >= 0;
4619ef1f84bSDavid du Colombier }
4629ef1f84bSDavid du Colombier
4639ef1f84bSDavid du Colombier void
edfyield(void)4649ef1f84bSDavid du Colombier edfyield(void)
4659ef1f84bSDavid du Colombier {
4669ef1f84bSDavid du Colombier /* sleep until next release */
4679ef1f84bSDavid du Colombier Edf *e;
468*d46407a3SDavid du Colombier void (*pt)(Proc*, int, vlong, vlong);
4699ef1f84bSDavid du Colombier long n;
4709ef1f84bSDavid du Colombier
4719ef1f84bSDavid du Colombier if((e = edflock(up)) == nil)
4729ef1f84bSDavid du Colombier return;
4739ef1f84bSDavid du Colombier if(up->trace && (pt = proctrace))
474*d46407a3SDavid du Colombier pt(up, SYield, 0, 0);
4759ef1f84bSDavid du Colombier if((n = now - e->t) > 0){
4769ef1f84bSDavid du Colombier if(n < e->T)
4779ef1f84bSDavid du Colombier e->t += e->T;
4789ef1f84bSDavid du Colombier else
4799ef1f84bSDavid du Colombier e->t = now + e->T - (n % e->T);
4809ef1f84bSDavid du Colombier }
4819ef1f84bSDavid du Colombier e->r = e->t;
4829ef1f84bSDavid du Colombier e->flags |= Yield;
4839ef1f84bSDavid du Colombier e->d = now;
4849ef1f84bSDavid du Colombier if (up->tt == nil){
4859ef1f84bSDavid du Colombier n = e->t - now;
4869ef1f84bSDavid du Colombier if(n < 20)
4879ef1f84bSDavid du Colombier n = 20;
4889ef1f84bSDavid du Colombier up->tns = 1000LL * n;
4899ef1f84bSDavid du Colombier up->tf = releaseintr;
4909ef1f84bSDavid du Colombier up->tmode = Trelative;
4919ef1f84bSDavid du Colombier up->ta = up;
4929ef1f84bSDavid du Colombier up->trend = &up->sleep;
4939ef1f84bSDavid du Colombier timeradd(up);
4949ef1f84bSDavid du Colombier }else if(up->tf != releaseintr)
4959ef1f84bSDavid du Colombier print("edfyield: surprise! %#p\n", up->tf);
4969ef1f84bSDavid du Colombier edfunlock();
4979ef1f84bSDavid du Colombier sleep(&up->sleep, yfn, nil);
4989ef1f84bSDavid du Colombier }
4999ef1f84bSDavid du Colombier
5009ef1f84bSDavid du Colombier int
edfready(Proc * p)5019ef1f84bSDavid du Colombier edfready(Proc *p)
5029ef1f84bSDavid du Colombier {
5039ef1f84bSDavid du Colombier Edf *e;
5049ef1f84bSDavid du Colombier Schedq *rq;
5059ef1f84bSDavid du Colombier Proc *l, *pp;
506*d46407a3SDavid du Colombier void (*pt)(Proc*, int, vlong, vlong);
5079ef1f84bSDavid du Colombier long n;
5089ef1f84bSDavid du Colombier
5099ef1f84bSDavid du Colombier if((e = edflock(p)) == nil)
5109ef1f84bSDavid du Colombier return 0;
5119ef1f84bSDavid du Colombier
5129ef1f84bSDavid du Colombier if(p->state == Wakeme && p->r){
5139ef1f84bSDavid du Colombier iprint("edfready: wakeme\n");
5149ef1f84bSDavid du Colombier }
5159ef1f84bSDavid du Colombier if(e->d - now <= 0){
5169ef1f84bSDavid du Colombier /* past deadline, arrange for next release */
5179ef1f84bSDavid du Colombier if((e->flags & Sporadic) == 0){
5189ef1f84bSDavid du Colombier /*
5199ef1f84bSDavid du Colombier * Non sporadic processes stay true to their period;
5209ef1f84bSDavid du Colombier * calculate next release time.
5219ef1f84bSDavid du Colombier */
5229ef1f84bSDavid du Colombier if((n = now - e->t) > 0){
5239ef1f84bSDavid du Colombier if(n < e->T)
5249ef1f84bSDavid du Colombier e->t += e->T;
5259ef1f84bSDavid du Colombier else
5269ef1f84bSDavid du Colombier e->t = now + e->T - (n % e->T);
5279ef1f84bSDavid du Colombier }
5289ef1f84bSDavid du Colombier }
5299ef1f84bSDavid du Colombier if(now - e->t < 0){
5309ef1f84bSDavid du Colombier /* Next release is in the future, schedule it */
5319ef1f84bSDavid du Colombier if(e->tt == nil || e->tf != releaseintr){
5329ef1f84bSDavid du Colombier n = e->t - now;
5339ef1f84bSDavid du Colombier if(n < 20)
5349ef1f84bSDavid du Colombier n = 20;
5359ef1f84bSDavid du Colombier e->tns = 1000LL * n;
5369ef1f84bSDavid du Colombier e->tmode = Trelative;
5379ef1f84bSDavid du Colombier e->tf = releaseintr;
5389ef1f84bSDavid du Colombier e->ta = p;
5399ef1f84bSDavid du Colombier timeradd(e);
5409ef1f84bSDavid du Colombier DPRINT("%lud edfready %d[%s], release=%lud\n",
5419ef1f84bSDavid du Colombier now, p->pid, statename[p->state], e->t);
5429ef1f84bSDavid du Colombier }
5439ef1f84bSDavid du Colombier if(p->state == Running && (e->flags & (Yield|Yieldonblock)) == 0 && (e->flags & Extratime)){
5449ef1f84bSDavid du Colombier /* If we were running, we've overrun our CPU allocation
5459ef1f84bSDavid du Colombier * or missed the deadline, continue running best-effort at low priority
5469ef1f84bSDavid du Colombier * Otherwise we were blocked. If we don't yield on block, we continue
5479ef1f84bSDavid du Colombier * best effort
5489ef1f84bSDavid du Colombier */
5499ef1f84bSDavid du Colombier DPRINT(">");
5509ef1f84bSDavid du Colombier p->basepri = PriExtra;
5519ef1f84bSDavid du Colombier p->fixedpri = 1;
5529ef1f84bSDavid du Colombier edfunlock();
5539ef1f84bSDavid du Colombier return 0; /* Stick on runq[PriExtra] */
5549ef1f84bSDavid du Colombier }
5559ef1f84bSDavid du Colombier DPRINT("%lud edfready %d[%s] wait release at %lud\n",
5569ef1f84bSDavid du Colombier now, p->pid, statename[p->state], e->t);
5579ef1f84bSDavid du Colombier p->state = Waitrelease;
5589ef1f84bSDavid du Colombier edfunlock();
5599ef1f84bSDavid du Colombier return 1; /* Make runnable later */
5609ef1f84bSDavid du Colombier }
5619ef1f84bSDavid du Colombier DPRINT("%lud edfready %d %s release now\n", now, p->pid, statename[p->state]);
5629ef1f84bSDavid du Colombier /* release now */
5639ef1f84bSDavid du Colombier release(p);
5649ef1f84bSDavid du Colombier }
5659ef1f84bSDavid du Colombier edfunlock();
5669ef1f84bSDavid du Colombier DPRINT("^");
5679ef1f84bSDavid du Colombier rq = &runq[PriEdf];
5689ef1f84bSDavid du Colombier /* insert in queue in earliest deadline order */
5699ef1f84bSDavid du Colombier lock(runq);
5709ef1f84bSDavid du Colombier l = nil;
5719ef1f84bSDavid du Colombier for(pp = rq->head; pp; pp = pp->rnext){
5729ef1f84bSDavid du Colombier if(pp->edf->d > e->d)
5739ef1f84bSDavid du Colombier break;
5749ef1f84bSDavid du Colombier l = pp;
5759ef1f84bSDavid du Colombier }
5769ef1f84bSDavid du Colombier p->rnext = pp;
5779ef1f84bSDavid du Colombier if (l == nil)
5789ef1f84bSDavid du Colombier rq->head = p;
5799ef1f84bSDavid du Colombier else
5809ef1f84bSDavid du Colombier l->rnext = p;
5819ef1f84bSDavid du Colombier if(pp == nil)
5829ef1f84bSDavid du Colombier rq->tail = p;
5839ef1f84bSDavid du Colombier rq->n++;
5849ef1f84bSDavid du Colombier nrdy++;
5859ef1f84bSDavid du Colombier runvec |= 1 << PriEdf;
5869ef1f84bSDavid du Colombier p->priority = PriEdf;
5879ef1f84bSDavid du Colombier p->readytime = m->ticks;
5889ef1f84bSDavid du Colombier p->state = Ready;
5899ef1f84bSDavid du Colombier unlock(runq);
5909ef1f84bSDavid du Colombier if(p->trace && (pt = proctrace))
591*d46407a3SDavid du Colombier pt(p, SReady, 0, 0);
5929ef1f84bSDavid du Colombier return 1;
5939ef1f84bSDavid du Colombier }
5949ef1f84bSDavid du Colombier
5959ef1f84bSDavid du Colombier
5969ef1f84bSDavid du Colombier static void
testenq(Proc * p)5979ef1f84bSDavid du Colombier testenq(Proc *p)
5989ef1f84bSDavid du Colombier {
5999ef1f84bSDavid du Colombier Proc *xp, **xpp;
6009ef1f84bSDavid du Colombier Edf *e;
6019ef1f84bSDavid du Colombier
6029ef1f84bSDavid du Colombier e = p->edf;
6039ef1f84bSDavid du Colombier e->testnext = nil;
6049ef1f84bSDavid du Colombier if (qschedulability == nil) {
6059ef1f84bSDavid du Colombier qschedulability = p;
6069ef1f84bSDavid du Colombier return;
6079ef1f84bSDavid du Colombier }
6089ef1f84bSDavid du Colombier SET(xp);
6099ef1f84bSDavid du Colombier for (xpp = &qschedulability; *xpp; xpp = &xp->edf->testnext) {
6109ef1f84bSDavid du Colombier xp = *xpp;
6119ef1f84bSDavid du Colombier if (e->testtime - xp->edf->testtime < 0
6129ef1f84bSDavid du Colombier || (e->testtime == xp->edf->testtime && e->testtype < xp->edf->testtype)){
6139ef1f84bSDavid du Colombier e->testnext = xp;
6149ef1f84bSDavid du Colombier *xpp = p;
6159ef1f84bSDavid du Colombier return;
6169ef1f84bSDavid du Colombier }
6179ef1f84bSDavid du Colombier }
6189ef1f84bSDavid du Colombier assert(xp->edf->testnext == nil);
6199ef1f84bSDavid du Colombier xp->edf->testnext = p;
6209ef1f84bSDavid du Colombier }
6219ef1f84bSDavid du Colombier
6229ef1f84bSDavid du Colombier static char *
testschedulability(Proc * theproc)6239ef1f84bSDavid du Colombier testschedulability(Proc *theproc)
6249ef1f84bSDavid du Colombier {
6259ef1f84bSDavid du Colombier Proc *p;
6269ef1f84bSDavid du Colombier long H, G, Cb, ticks;
6279ef1f84bSDavid du Colombier int steps, i;
6289ef1f84bSDavid du Colombier
6299ef1f84bSDavid du Colombier /* initialize */
6309ef1f84bSDavid du Colombier DPRINT("schedulability test %d\n", theproc->pid);
6319ef1f84bSDavid du Colombier qschedulability = nil;
6329ef1f84bSDavid du Colombier for(i=0; (p = psincref(i)) != nil; i++) {
6339ef1f84bSDavid du Colombier if(p->state == Dead){
6349ef1f84bSDavid du Colombier psdecref(p);
6359ef1f84bSDavid du Colombier continue;
6369ef1f84bSDavid du Colombier }
6379ef1f84bSDavid du Colombier if ((p->edf == nil || (p->edf->flags & Admitted) == 0) && p != theproc){
6389ef1f84bSDavid du Colombier psdecref(p);
6399ef1f84bSDavid du Colombier continue;
6409ef1f84bSDavid du Colombier }
6419ef1f84bSDavid du Colombier p->edf->testtype = Rl;
6429ef1f84bSDavid du Colombier p->edf->testtime = 0;
6439ef1f84bSDavid du Colombier DPRINT("\tInit: edfenqueue %d\n", p->pid);
6449ef1f84bSDavid du Colombier testenq(p);
6459ef1f84bSDavid du Colombier psdecref(p);
6469ef1f84bSDavid du Colombier }
6479ef1f84bSDavid du Colombier H=0;
6489ef1f84bSDavid du Colombier G=0;
6499ef1f84bSDavid du Colombier for(steps = 0; steps < Maxsteps; steps++){
6509ef1f84bSDavid du Colombier p = qschedulability;
6519ef1f84bSDavid du Colombier qschedulability = p->edf->testnext;
6529ef1f84bSDavid du Colombier ticks = p->edf->testtime;
6539ef1f84bSDavid du Colombier switch (p->edf->testtype){
6549ef1f84bSDavid du Colombier case Dl:
6559ef1f84bSDavid du Colombier H += p->edf->C;
6569ef1f84bSDavid du Colombier Cb = 0;
6579ef1f84bSDavid du Colombier DPRINT("\tStep %3d, Ticks %lud, pid %d, deadline, H += %lud → %lud, Cb = %lud\n",
6589ef1f84bSDavid du Colombier steps, ticks, p->pid, p->edf->C, H, Cb);
6599ef1f84bSDavid du Colombier if (H+Cb>ticks){
6609ef1f84bSDavid du Colombier DPRINT("not schedulable\n");
6619ef1f84bSDavid du Colombier return "not schedulable";
6629ef1f84bSDavid du Colombier }
6639ef1f84bSDavid du Colombier p->edf->testtime += p->edf->T - p->edf->D;
6649ef1f84bSDavid du Colombier p->edf->testtype = Rl;
6659ef1f84bSDavid du Colombier testenq(p);
6669ef1f84bSDavid du Colombier break;
6679ef1f84bSDavid du Colombier case Rl:
6689ef1f84bSDavid du Colombier DPRINT("\tStep %3d, Ticks %lud, pid %d, release, G %lud, C%lud\n",
6699ef1f84bSDavid du Colombier steps, ticks, p->pid, p->edf->C, G);
6709ef1f84bSDavid du Colombier if(ticks && G <= ticks){
6719ef1f84bSDavid du Colombier DPRINT("schedulable\n");
6729ef1f84bSDavid du Colombier return nil;
6739ef1f84bSDavid du Colombier }
6749ef1f84bSDavid du Colombier G += p->edf->C;
6759ef1f84bSDavid du Colombier p->edf->testtime += p->edf->D;
6769ef1f84bSDavid du Colombier p->edf->testtype = Dl;
6779ef1f84bSDavid du Colombier testenq(p);
6789ef1f84bSDavid du Colombier break;
6799ef1f84bSDavid du Colombier default:
6809ef1f84bSDavid du Colombier assert(0);
6819ef1f84bSDavid du Colombier }
6829ef1f84bSDavid du Colombier }
6839ef1f84bSDavid du Colombier DPRINT("probably not schedulable\n");
6849ef1f84bSDavid du Colombier return "probably not schedulable";
6859ef1f84bSDavid du Colombier }
686