19a747e4fSDavid du Colombier /* EDF scheduling */
2e288d156SDavid du Colombier #include <u.h>
39a747e4fSDavid du Colombier #include "../port/lib.h"
49a747e4fSDavid du Colombier #include "mem.h"
59a747e4fSDavid du Colombier #include "dat.h"
69a747e4fSDavid du Colombier #include "fns.h"
79a747e4fSDavid du Colombier #include "../port/error.h"
89a747e4fSDavid du Colombier #include "../port/edf.h"
9e288d156SDavid du Colombier #include <trace.h>
109a747e4fSDavid du Colombier
119a747e4fSDavid du Colombier /* debugging */
12ea58ad6fSDavid du Colombier enum {
13ea58ad6fSDavid du Colombier Dontprint = 1,
14ea58ad6fSDavid du Colombier };
15ea58ad6fSDavid du Colombier
16ea58ad6fSDavid du Colombier #define DPRINT if(Dontprint){}else print
179a747e4fSDavid du Colombier
182cca75a1SDavid du Colombier static long now; /* Low order 32 bits of time in µs */
19e288d156SDavid du Colombier extern ulong delayedscheds;
20e288d156SDavid du Colombier extern Schedq runq[Nrq];
21e288d156SDavid du Colombier extern int nrdy;
22e288d156SDavid du Colombier extern ulong runvec;
239a747e4fSDavid du Colombier
24e288d156SDavid du Colombier /* Statistics stuff */
25e288d156SDavid du Colombier ulong nilcount;
26e288d156SDavid du Colombier ulong scheds;
27e288d156SDavid du Colombier ulong edfnrun;
289a747e4fSDavid du Colombier int misseddeadlines;
299a747e4fSDavid du Colombier
30e288d156SDavid du Colombier /* Edfschedlock protects modification of admission params */
31e288d156SDavid du Colombier int edfinited;
32e288d156SDavid du Colombier QLock edfschedlock;
33e288d156SDavid du Colombier static Lock thelock;
34e288d156SDavid du Colombier
359a747e4fSDavid du Colombier enum{
36e288d156SDavid du Colombier Dl, /* Invariant for schedulability test: Dl < Rl */
37e288d156SDavid du Colombier Rl,
389a747e4fSDavid du Colombier };
399a747e4fSDavid du Colombier
40e288d156SDavid du Colombier static char *testschedulability(Proc*);
41e288d156SDavid du Colombier static Proc *qschedulability;
429a747e4fSDavid du Colombier
43e288d156SDavid du Colombier enum {
442cca75a1SDavid du Colombier Onemicrosecond = 1,
452cca75a1SDavid du Colombier Onemillisecond = 1000,
462cca75a1SDavid du Colombier Onesecond = 1000000,
472cca75a1SDavid du Colombier OneRound = Onemillisecond/2,
48e288d156SDavid du Colombier };
499a747e4fSDavid du Colombier
503ff48bf5SDavid du Colombier static int
timeconv(Fmt * f)51e288d156SDavid du Colombier timeconv(Fmt *f)
529a747e4fSDavid du Colombier {
53e288d156SDavid du Colombier char buf[128], *sign;
54e288d156SDavid du Colombier vlong t;
559a747e4fSDavid du Colombier
56e288d156SDavid du Colombier buf[0] = 0;
57e288d156SDavid du Colombier switch(f->r) {
58e288d156SDavid du Colombier case 'U':
59e288d156SDavid du Colombier t = va_arg(f->args, uvlong);
609a747e4fSDavid du Colombier break;
61ea58ad6fSDavid du Colombier case 't': /* vlong in nanoseconds */
622cca75a1SDavid du Colombier t = va_arg(f->args, long);
63e288d156SDavid du Colombier break;
64e288d156SDavid du Colombier default:
65e288d156SDavid du Colombier return fmtstrcpy(f, "(timeconv)");
669a747e4fSDavid du Colombier }
67e288d156SDavid du Colombier if (t < 0) {
68e288d156SDavid du Colombier sign = "-";
69e288d156SDavid du Colombier t = -t;
709a747e4fSDavid du Colombier }
71e288d156SDavid du Colombier else
72e288d156SDavid du Colombier sign = "";
73e288d156SDavid du Colombier if (t > Onesecond){
74e288d156SDavid du Colombier t += OneRound;
75*4e3613abSDavid du Colombier snprint(buf, sizeof buf, "%s%d.%.3ds", sign,
76*4e3613abSDavid du Colombier (int)(t / Onesecond),
77ea58ad6fSDavid du Colombier (int)(t % Onesecond)/Onemillisecond);
782cca75a1SDavid du Colombier }else if (t > Onemillisecond)
79*4e3613abSDavid du Colombier snprint(buf, sizeof buf, "%s%d.%.3dms", sign,
80*4e3613abSDavid du Colombier (int)(t / Onemillisecond), (int)(t % Onemillisecond));
81e288d156SDavid du Colombier else
82*4e3613abSDavid du Colombier snprint(buf, sizeof buf, "%s%dµs", sign, (int)t);
83e288d156SDavid du Colombier return fmtstrcpy(f, buf);
849a747e4fSDavid du Colombier }
859a747e4fSDavid du Colombier
86ea58ad6fSDavid du Colombier long edfcycles;
872cca75a1SDavid du Colombier
88da51d93aSDavid du Colombier Edf*
edflock(Proc * p)89da51d93aSDavid du Colombier edflock(Proc *p)
909a747e4fSDavid du Colombier {
91da51d93aSDavid du Colombier Edf *e;
92da51d93aSDavid du Colombier
93da51d93aSDavid du Colombier if (p->edf == nil)
94da51d93aSDavid du Colombier return nil;
95e288d156SDavid du Colombier ilock(&thelock);
96da51d93aSDavid du Colombier if((e = p->edf) && (e->flags & Admitted)){
97ea58ad6fSDavid du Colombier thelock.pc = getcallerpc(&p);
98ea58ad6fSDavid du Colombier #ifdef EDFCYCLES
99ea58ad6fSDavid du Colombier edfcycles -= lcycles();
100ea58ad6fSDavid du Colombier #endif
101ea58ad6fSDavid du Colombier now = µs();
102da51d93aSDavid du Colombier return e;
103da51d93aSDavid du Colombier }
104da51d93aSDavid du Colombier iunlock(&thelock);
105da51d93aSDavid du Colombier return nil;
106e288d156SDavid du Colombier }
1079a747e4fSDavid du Colombier
108e288d156SDavid du Colombier void
edfunlock(void)109e288d156SDavid du Colombier edfunlock(void)
110e288d156SDavid du Colombier {
1112cca75a1SDavid du Colombier
112ea58ad6fSDavid du Colombier #ifdef EDFCYCLES
113ea58ad6fSDavid du Colombier edfcycles += lcycles();
114ea58ad6fSDavid du Colombier #endif
115e288d156SDavid du Colombier edfnrun++;
116e288d156SDavid du Colombier iunlock(&thelock);
117e288d156SDavid du Colombier }
118e288d156SDavid du Colombier
119e288d156SDavid du Colombier void
edfinit(Proc * p)120e288d156SDavid du Colombier edfinit(Proc*p)
121e288d156SDavid du Colombier {
122e288d156SDavid du Colombier if(!edfinited){
123e288d156SDavid du Colombier fmtinstall('t', timeconv);
124e288d156SDavid du Colombier edfinited++;
125e288d156SDavid du Colombier }
126ea58ad6fSDavid du Colombier now = µs();
127ea58ad6fSDavid du Colombier DPRINT("%lud edfinit %lud[%s]\n", now, p->pid, statename[p->state]);
128e288d156SDavid du Colombier p->edf = malloc(sizeof(Edf));
129e288d156SDavid du Colombier if(p->edf == nil)
130e288d156SDavid du Colombier error(Enomem);
1319a747e4fSDavid du Colombier return;
1329a747e4fSDavid du Colombier }
1339a747e4fSDavid du Colombier
1343ff48bf5SDavid du Colombier static void
deadlineintr(Ureg *,Timer * t)135e288d156SDavid du Colombier deadlineintr(Ureg*, Timer *t)
1369a747e4fSDavid du Colombier {
137e288d156SDavid du Colombier /* Proc reached deadline */
138e288d156SDavid du Colombier extern int panicking;
139e288d156SDavid du Colombier Proc *p;
140da51d93aSDavid du Colombier void (*pt)(Proc*, int, vlong);
1419a747e4fSDavid du Colombier
142e288d156SDavid du Colombier if(panicking || active.exiting)
1439a747e4fSDavid du Colombier return;
1449a747e4fSDavid du Colombier
145e288d156SDavid du Colombier p = t->ta;
146ea58ad6fSDavid du Colombier now = µs();
147ea58ad6fSDavid du Colombier DPRINT("%lud deadlineintr %lud[%s]\n", now, p->pid, statename[p->state]);
148e288d156SDavid du Colombier /* If we're interrupting something other than the proc pointed to by t->a,
149e288d156SDavid du Colombier * we've already achieved recheduling, so we need not do anything
150e288d156SDavid du Colombier * Otherwise, we must cause a reschedule, but if we call sched()
151e288d156SDavid du Colombier * here directly, the timer interrupt routine will not finish its business
152e288d156SDavid du Colombier * Instead, we cause the resched to happen when the interrupted proc
153e288d156SDavid du Colombier * returns to user space
154e288d156SDavid du Colombier */
155e288d156SDavid du Colombier if(p == up){
156ea58ad6fSDavid du Colombier if(up->trace && (pt = proctrace))
157da51d93aSDavid du Colombier pt(up, SInts, 0);
158e288d156SDavid du Colombier up->delaysched++;
159e288d156SDavid du Colombier delayedscheds++;
1609a747e4fSDavid du Colombier }
1619a747e4fSDavid du Colombier }
1629a747e4fSDavid du Colombier
1639a747e4fSDavid du Colombier static void
release(Proc * p)164e288d156SDavid du Colombier release(Proc *p)
1659a747e4fSDavid du Colombier {
166e288d156SDavid du Colombier /* Called with edflock held */
167e288d156SDavid du Colombier Edf *e;
1680701b922SDavid du Colombier void (*pt)(Proc*, int, vlong);
1692cca75a1SDavid du Colombier long n;
1702cca75a1SDavid du Colombier vlong nowns;
1719a747e4fSDavid du Colombier
172e288d156SDavid du Colombier e = p->edf;
173e288d156SDavid du Colombier e->flags &= ~Yield;
1742cca75a1SDavid du Colombier if(e->d - now < 0){
175e288d156SDavid du Colombier e->periods++;
176e288d156SDavid du Colombier e->r = now;
177e288d156SDavid du Colombier if((e->flags & Sporadic) == 0){
1782cca75a1SDavid du Colombier /*
1792cca75a1SDavid du Colombier * Non sporadic processes stay true to their period;
1802cca75a1SDavid du Colombier * calculate next release time.
1812cca75a1SDavid du Colombier * Second test limits duration of while loop.
182e288d156SDavid du Colombier */
1832cca75a1SDavid du Colombier if((n = now - e->t) > 0){
1842cca75a1SDavid du Colombier if(n < e->T)
185e288d156SDavid du Colombier e->t += e->T;
1862cca75a1SDavid du Colombier else
1872cca75a1SDavid du Colombier e->t = now + e->T - (n % e->T);
1882cca75a1SDavid du Colombier }
189e288d156SDavid du Colombier }else{
190e288d156SDavid du Colombier /* Sporadic processes may not be released earlier than
191e288d156SDavid du Colombier * one period after this release
192e288d156SDavid du Colombier */
193e288d156SDavid du Colombier e->t = e->r + e->T;
1949a747e4fSDavid du Colombier }
195e288d156SDavid du Colombier e->d = e->r + e->D;
196e288d156SDavid du Colombier e->S = e->C;
197ea58ad6fSDavid du Colombier DPRINT("%lud release %lud[%s], r=%lud, d=%lud, t=%lud, S=%lud\n",
198e288d156SDavid du Colombier now, p->pid, statename[p->state], e->r, e->d, e->t, e->S);
1990701b922SDavid du Colombier if(pt = proctrace){
2002cca75a1SDavid du Colombier nowns = todget(nil);
2012cca75a1SDavid du Colombier pt(p, SRelease, nowns);
2022cca75a1SDavid du Colombier pt(p, SDeadline, nowns + 1000LL*e->D);
2030701b922SDavid du Colombier }
204e288d156SDavid du Colombier }else{
205567483c8SDavid du Colombier DPRINT("%lud release %lud[%s], too late t=%lud, called from %#p\n",
206e288d156SDavid du Colombier now, p->pid, statename[p->state], e->t, getcallerpc(&p));
2079a747e4fSDavid du Colombier }
2089a747e4fSDavid du Colombier }
2099a747e4fSDavid du Colombier
2103ff48bf5SDavid du Colombier static void
releaseintr(Ureg *,Timer * t)211e288d156SDavid du Colombier releaseintr(Ureg*, Timer *t)
2129a747e4fSDavid du Colombier {
213e288d156SDavid du Colombier Proc *p;
214e288d156SDavid du Colombier extern int panicking;
215e288d156SDavid du Colombier Schedq *rq;
216e288d156SDavid du Colombier
217e288d156SDavid du Colombier if(panicking || active.exiting)
218e288d156SDavid du Colombier return;
219e288d156SDavid du Colombier
220e288d156SDavid du Colombier p = t->ta;
221da51d93aSDavid du Colombier if((edflock(p)) == nil)
222e288d156SDavid du Colombier return;
223ea58ad6fSDavid du Colombier DPRINT("%lud releaseintr %lud[%s]\n", now, p->pid, statename[p->state]);
224e288d156SDavid du Colombier switch(p->state){
225e288d156SDavid du Colombier default:
226e288d156SDavid du Colombier edfunlock();
227e288d156SDavid du Colombier return;
228e288d156SDavid du Colombier case Ready:
229e288d156SDavid du Colombier /* remove proc from current runq */
230e288d156SDavid du Colombier rq = &runq[p->priority];
231e288d156SDavid du Colombier if(dequeueproc(rq, p) != p){
232da51d93aSDavid du Colombier DPRINT("releaseintr: can't find proc or lock race\n");
233e288d156SDavid du Colombier release(p); /* It'll start best effort */
234e288d156SDavid du Colombier edfunlock();
235e288d156SDavid du Colombier return;
236e288d156SDavid du Colombier }
237e288d156SDavid du Colombier p->state = Waitrelease;
238e288d156SDavid du Colombier /* fall through */
239e288d156SDavid du Colombier case Waitrelease:
240e288d156SDavid du Colombier release(p);
241e288d156SDavid du Colombier edfunlock();
242ea58ad6fSDavid du Colombier if(p->state == Wakeme){
243ea58ad6fSDavid du Colombier iprint("releaseintr: wakeme\n");
244ea58ad6fSDavid du Colombier }
245e288d156SDavid du Colombier ready(p);
24628495efeSDavid du Colombier if(up){
24728495efeSDavid du Colombier up->delaysched++;
24828495efeSDavid du Colombier delayedscheds++;
24928495efeSDavid du Colombier }
250e288d156SDavid du Colombier return;
251e288d156SDavid du Colombier case Running:
252e288d156SDavid du Colombier release(p);
253e288d156SDavid du Colombier edfrun(p, 1);
254e288d156SDavid du Colombier break;
25528495efeSDavid du Colombier case Wakeme:
25628495efeSDavid du Colombier release(p);
25728495efeSDavid du Colombier edfunlock();
25828495efeSDavid du Colombier if(p->trend)
25928495efeSDavid du Colombier wakeup(p->trend);
26028495efeSDavid du Colombier p->trend = nil;
26128495efeSDavid du Colombier if(up){
26228495efeSDavid du Colombier up->delaysched++;
26328495efeSDavid du Colombier delayedscheds++;
26428495efeSDavid du Colombier }
26528495efeSDavid du Colombier return;
266e288d156SDavid du Colombier }
267e288d156SDavid du Colombier edfunlock();
2689a747e4fSDavid du Colombier }
2699a747e4fSDavid du Colombier
270e288d156SDavid du Colombier void
edfrecord(Proc * p)271e288d156SDavid du Colombier edfrecord(Proc *p)
2729a747e4fSDavid du Colombier {
2732cca75a1SDavid du Colombier long used;
274e288d156SDavid du Colombier Edf *e;
2750701b922SDavid du Colombier void (*pt)(Proc*, int, vlong);
2769a747e4fSDavid du Colombier
277da51d93aSDavid du Colombier if((e = edflock(p)) == nil)
278da51d93aSDavid du Colombier return;
279e288d156SDavid du Colombier used = now - e->s;
2802cca75a1SDavid du Colombier if(e->d - now <= 0)
281e288d156SDavid du Colombier e->edfused += used;
282e288d156SDavid du Colombier else
283e288d156SDavid du Colombier e->extraused += used;
284e288d156SDavid du Colombier if(e->S > 0){
285e288d156SDavid du Colombier if(e->S <= used){
286e288d156SDavid du Colombier if(pt = proctrace)
2872cca75a1SDavid du Colombier pt(p, SSlice, 0);
288ea58ad6fSDavid du Colombier DPRINT("%lud edfrecord slice used up\n", now);
289e288d156SDavid du Colombier e->d = now;
290e288d156SDavid du Colombier e->S = 0;
291e288d156SDavid du Colombier }else
292e288d156SDavid du Colombier e->S -= used;
293e288d156SDavid du Colombier }
294e288d156SDavid du Colombier e->s = now;
295e288d156SDavid du Colombier edfunlock();
296e288d156SDavid du Colombier }
297e288d156SDavid du Colombier
298e288d156SDavid du Colombier void
edfrun(Proc * p,int edfpri)299e288d156SDavid du Colombier edfrun(Proc *p, int edfpri)
300e288d156SDavid du Colombier {
301e288d156SDavid du Colombier Edf *e;
302da51d93aSDavid du Colombier void (*pt)(Proc*, int, vlong);
3032cca75a1SDavid du Colombier long tns;
304e288d156SDavid du Colombier
305e288d156SDavid du Colombier e = p->edf;
306e288d156SDavid du Colombier /* Called with edflock held */
307e288d156SDavid du Colombier if(edfpri){
3082cca75a1SDavid du Colombier tns = e->d - now;
3092cca75a1SDavid du Colombier if(tns <= 0 || e->S == 0){
310e288d156SDavid du Colombier /* Deadline reached or resources exhausted,
311e288d156SDavid du Colombier * deschedule forthwith
312e288d156SDavid du Colombier */
313e288d156SDavid du Colombier p->delaysched++;
314e288d156SDavid du Colombier delayedscheds++;
315e288d156SDavid du Colombier e->s = now;
316e288d156SDavid du Colombier return;
317e288d156SDavid du Colombier }
3182cca75a1SDavid du Colombier if(e->S < tns)
3192cca75a1SDavid du Colombier tns = e->S;
320ea58ad6fSDavid du Colombier if(tns < 20)
321ea58ad6fSDavid du Colombier tns = 20;
322ea58ad6fSDavid du Colombier e->tns = 1000LL * tns; /* µs to ns */
323c49c9d4eSDavid du Colombier if(e->tt == nil || e->tf != deadlineintr){
324ea58ad6fSDavid du Colombier DPRINT("%lud edfrun, deadline=%lud\n", now, tns);
325e288d156SDavid du Colombier }else{
326e288d156SDavid du Colombier DPRINT("v");
327e288d156SDavid du Colombier }
328da51d93aSDavid du Colombier if(p->trace && (pt = proctrace))
3292cca75a1SDavid du Colombier pt(p, SInte, todget(nil) + e->tns);
3302cca75a1SDavid du Colombier e->tmode = Trelative;
331c49c9d4eSDavid du Colombier e->tf = deadlineintr;
332c49c9d4eSDavid du Colombier e->ta = p;
333c49c9d4eSDavid du Colombier timeradd(e);
334e288d156SDavid du Colombier }else{
335e288d156SDavid du Colombier DPRINT("<");
336e288d156SDavid du Colombier }
337e288d156SDavid du Colombier e->s = now;
338e288d156SDavid du Colombier }
339e288d156SDavid du Colombier
340e288d156SDavid du Colombier char *
edfadmit(Proc * p)341e288d156SDavid du Colombier edfadmit(Proc *p)
342e288d156SDavid du Colombier {
343e288d156SDavid du Colombier char *err;
344e288d156SDavid du Colombier Edf *e;
345e288d156SDavid du Colombier int i;
346e288d156SDavid du Colombier Proc *r;
3470701b922SDavid du Colombier void (*pt)(Proc*, int, vlong);
3482cca75a1SDavid du Colombier long tns;
349e288d156SDavid du Colombier
350e288d156SDavid du Colombier e = p->edf;
351e288d156SDavid du Colombier if (e->flags & Admitted)
3529a747e4fSDavid du Colombier return "task state"; /* should never happen */
3539a747e4fSDavid du Colombier
3549a747e4fSDavid du Colombier /* simple sanity checks */
355e288d156SDavid du Colombier if (e->T == 0)
3569a747e4fSDavid du Colombier return "T not set";
357e288d156SDavid du Colombier if (e->C == 0)
3589a747e4fSDavid du Colombier return "C not set";
359e288d156SDavid du Colombier if (e->D > e->T)
3609a747e4fSDavid du Colombier return "D > T";
361e288d156SDavid du Colombier if (e->D == 0) /* if D is not set, set it to T */
362e288d156SDavid du Colombier e->D = e->T;
363e288d156SDavid du Colombier if (e->C > e->D)
3649a747e4fSDavid du Colombier return "C > D";
3659a747e4fSDavid du Colombier
366e288d156SDavid du Colombier qlock(&edfschedlock);
367e288d156SDavid du Colombier if (err = testschedulability(p)){
368e288d156SDavid du Colombier qunlock(&edfschedlock);
3699a747e4fSDavid du Colombier return err;
3709a747e4fSDavid du Colombier }
371e288d156SDavid du Colombier e->flags |= Admitted;
372e288d156SDavid du Colombier
373da51d93aSDavid du Colombier edflock(p);
374da51d93aSDavid du Colombier
375ea58ad6fSDavid du Colombier if(p->trace && (pt = proctrace))
3762cca75a1SDavid du Colombier pt(p, SAdmit, 0);
377e288d156SDavid du Colombier
378e288d156SDavid du Colombier /* Look for another proc with the same period to synchronize to */
379e288d156SDavid du Colombier SET(r);
380e288d156SDavid du Colombier for(i=0; i<conf.nproc; i++) {
381e288d156SDavid du Colombier r = proctab(i);
382e288d156SDavid du Colombier if(r->state == Dead || r == p)
383e288d156SDavid du Colombier continue;
384e288d156SDavid du Colombier if (r->edf == nil || (r->edf->flags & Admitted) == 0)
385e288d156SDavid du Colombier continue;
386e288d156SDavid du Colombier if (r->edf->T == e->T)
387e288d156SDavid du Colombier break;
388d9306527SDavid du Colombier }
389e288d156SDavid du Colombier if (i == conf.nproc){
390e288d156SDavid du Colombier /* Can't synchronize to another proc, release now */
391e288d156SDavid du Colombier e->t = now;
392e288d156SDavid du Colombier e->d = 0;
393e288d156SDavid du Colombier release(p);
394e288d156SDavid du Colombier if (p == up){
395ea58ad6fSDavid du Colombier DPRINT("%lud edfadmit self %lud[%s], release now: r=%lud d=%lud t=%lud\n",
396e288d156SDavid du Colombier now, p->pid, statename[p->state], e->r, e->d, e->t);
397e288d156SDavid du Colombier /* We're already running */
398e288d156SDavid du Colombier edfrun(p, 1);
3999a747e4fSDavid du Colombier }else{
400e288d156SDavid du Colombier /* We're releasing another proc */
401ea58ad6fSDavid du Colombier DPRINT("%lud edfadmit other %lud[%s], release now: r=%lud d=%lud t=%lud\n",
402e288d156SDavid du Colombier now, p->pid, statename[p->state], e->r, e->d, e->t);
403e288d156SDavid du Colombier p->ta = p;
40415174232SDavid du Colombier edfunlock();
40515174232SDavid du Colombier qunlock(&edfschedlock);
406e288d156SDavid du Colombier releaseintr(nil, p);
40715174232SDavid du Colombier return nil;
408e288d156SDavid du Colombier }
409e288d156SDavid du Colombier }else{
410e288d156SDavid du Colombier /* Release in synch to something else */
411e288d156SDavid du Colombier e->t = r->edf->t;
412e288d156SDavid du Colombier if (p == up){
413ea58ad6fSDavid du Colombier DPRINT("%lud edfadmit self %lud[%s], release at %lud\n",
414e288d156SDavid du Colombier now, p->pid, statename[p->state], e->t);
415e288d156SDavid du Colombier edfunlock();
416e288d156SDavid du Colombier qunlock(&edfschedlock);
417e288d156SDavid du Colombier return nil;
418e288d156SDavid du Colombier }else{
419ea58ad6fSDavid du Colombier DPRINT("%lud edfadmit other %lud[%s], release at %lud\n",
420e288d156SDavid du Colombier now, p->pid, statename[p->state], e->t);
421da51d93aSDavid du Colombier if(e->tt == nil){
422c49c9d4eSDavid du Colombier e->tf = releaseintr;
423c49c9d4eSDavid du Colombier e->ta = p;
4242cca75a1SDavid du Colombier tns = e->t - now;
4252cca75a1SDavid du Colombier if(tns < 20)
4262cca75a1SDavid du Colombier tns = 20;
4272cca75a1SDavid du Colombier e->tns = 1000LL * tns;
4282cca75a1SDavid du Colombier e->tmode = Trelative;
429c49c9d4eSDavid du Colombier timeradd(e);
4309a747e4fSDavid du Colombier }
4319a747e4fSDavid du Colombier }
4329a747e4fSDavid du Colombier }
433e288d156SDavid du Colombier edfunlock();
434e288d156SDavid du Colombier qunlock(&edfschedlock);
4359a747e4fSDavid du Colombier return nil;
4369a747e4fSDavid du Colombier }
4379a747e4fSDavid du Colombier
438e288d156SDavid du Colombier void
edfstop(Proc * p)439e288d156SDavid du Colombier edfstop(Proc *p)
4409a747e4fSDavid du Colombier {
441e288d156SDavid du Colombier Edf *e;
4420701b922SDavid du Colombier void (*pt)(Proc*, int, vlong);
4439a747e4fSDavid du Colombier
444da51d93aSDavid du Colombier if(e = edflock(p)){
445ea58ad6fSDavid du Colombier DPRINT("%lud edfstop %lud[%s]\n", now, p->pid, statename[p->state]);
446ea58ad6fSDavid du Colombier if(p->trace && (pt = proctrace))
4472cca75a1SDavid du Colombier pt(p, SExpel, 0);
448e288d156SDavid du Colombier e->flags &= ~Admitted;
449c49c9d4eSDavid du Colombier if(e->tt)
450c49c9d4eSDavid du Colombier timerdel(e);
451e288d156SDavid du Colombier edfunlock();
4529a747e4fSDavid du Colombier }
4539a747e4fSDavid du Colombier }
4549a747e4fSDavid du Colombier
45528495efeSDavid du Colombier static int
yfn(void *)45628495efeSDavid du Colombier yfn(void *)
45728495efeSDavid du Colombier {
458ea58ad6fSDavid du Colombier now = µs();
4592cca75a1SDavid du Colombier return up->trend == nil || now - up->edf->r >= 0;
46028495efeSDavid du Colombier }
46128495efeSDavid du Colombier
462e288d156SDavid du Colombier void
edfyield(void)463e288d156SDavid du Colombier edfyield(void)
4649a747e4fSDavid du Colombier {
465e288d156SDavid du Colombier /* sleep until next release */
466e288d156SDavid du Colombier Edf *e;
4670701b922SDavid du Colombier void (*pt)(Proc*, int, vlong);
4682cca75a1SDavid du Colombier long n;
4699a747e4fSDavid du Colombier
470da51d93aSDavid du Colombier if((e = edflock(up)) == nil)
471da51d93aSDavid du Colombier return;
472ea58ad6fSDavid du Colombier if(up->trace && (pt = proctrace))
4732cca75a1SDavid du Colombier pt(up, SYield, 0);
4742cca75a1SDavid du Colombier if((n = now - e->t) > 0){
4752cca75a1SDavid du Colombier if(n < e->T)
47628495efeSDavid du Colombier e->t += e->T;
4772cca75a1SDavid du Colombier else
4782cca75a1SDavid du Colombier e->t = now + e->T - (n % e->T);
4792cca75a1SDavid du Colombier }
48028495efeSDavid du Colombier e->r = e->t;
481e288d156SDavid du Colombier e->flags |= Yield;
482e288d156SDavid du Colombier e->d = now;
483da51d93aSDavid du Colombier if (up->tt == nil){
4842cca75a1SDavid du Colombier n = e->t - now;
4852cca75a1SDavid du Colombier if(n < 20)
4862cca75a1SDavid du Colombier n = 20;
4872cca75a1SDavid du Colombier up->tns = 1000LL * n;
48828495efeSDavid du Colombier up->tf = releaseintr;
4892cca75a1SDavid du Colombier up->tmode = Trelative;
49028495efeSDavid du Colombier up->ta = up;
49128495efeSDavid du Colombier up->trend = &up->sleep;
49228495efeSDavid du Colombier timeradd(up);
493da51d93aSDavid du Colombier }else if(up->tf != releaseintr)
494567483c8SDavid du Colombier print("edfyield: surprise! %#p\n", up->tf);
49528495efeSDavid du Colombier edfunlock();
49628495efeSDavid du Colombier sleep(&up->sleep, yfn, nil);
4979a747e4fSDavid du Colombier }
4989a747e4fSDavid du Colombier
499e288d156SDavid du Colombier int
edfready(Proc * p)5009a747e4fSDavid du Colombier edfready(Proc *p)
5019a747e4fSDavid du Colombier {
502e288d156SDavid du Colombier Edf *e;
503e288d156SDavid du Colombier Schedq *rq;
504e288d156SDavid du Colombier Proc *l, *pp;
5050701b922SDavid du Colombier void (*pt)(Proc*, int, vlong);
5062cca75a1SDavid du Colombier long n;
5079a747e4fSDavid du Colombier
508da51d93aSDavid du Colombier if((e = edflock(p)) == nil)
509da51d93aSDavid du Colombier return 0;
510ea58ad6fSDavid du Colombier
511ea58ad6fSDavid du Colombier if(p->state == Wakeme && p->r){
512ea58ad6fSDavid du Colombier iprint("edfready: wakeme\n");
513ea58ad6fSDavid du Colombier }
5142cca75a1SDavid du Colombier if(e->d - now <= 0){
515e288d156SDavid du Colombier /* past deadline, arrange for next release */
516e288d156SDavid du Colombier if((e->flags & Sporadic) == 0){
5172cca75a1SDavid du Colombier /*
5182cca75a1SDavid du Colombier * Non sporadic processes stay true to their period;
5192cca75a1SDavid du Colombier * calculate next release time.
5202cca75a1SDavid du Colombier */
5212cca75a1SDavid du Colombier if((n = now - e->t) > 0){
5222cca75a1SDavid du Colombier if(n < e->T)
523e288d156SDavid du Colombier e->t += e->T;
5242cca75a1SDavid du Colombier else
5252cca75a1SDavid du Colombier e->t = now + e->T - (n % e->T);
5269a747e4fSDavid du Colombier }
5272cca75a1SDavid du Colombier }
5282cca75a1SDavid du Colombier if(now - e->t < 0){
529e288d156SDavid du Colombier /* Next release is in the future, schedule it */
530da51d93aSDavid du Colombier if(e->tt == nil || e->tf != releaseintr){
5312cca75a1SDavid du Colombier n = e->t - now;
5322cca75a1SDavid du Colombier if(n < 20)
5332cca75a1SDavid du Colombier n = 20;
5342cca75a1SDavid du Colombier e->tns = 1000LL * n;
5352cca75a1SDavid du Colombier e->tmode = Trelative;
536c49c9d4eSDavid du Colombier e->tf = releaseintr;
537c49c9d4eSDavid du Colombier e->ta = p;
538c49c9d4eSDavid du Colombier timeradd(e);
539ea58ad6fSDavid du Colombier DPRINT("%lud edfready %lud[%s], release=%lud\n",
540e288d156SDavid du Colombier now, p->pid, statename[p->state], e->t);
541e288d156SDavid du Colombier }
5424fec87e5SDavid du Colombier if(p->state == Running && (e->flags & (Yield|Yieldonblock)) == 0 && (e->flags & Extratime)){
543e288d156SDavid du Colombier /* If we were running, we've overrun our CPU allocation
544e288d156SDavid du Colombier * or missed the deadline, continue running best-effort at low priority
545e288d156SDavid du Colombier * Otherwise we were blocked. If we don't yield on block, we continue
546e288d156SDavid du Colombier * best effort
547e288d156SDavid du Colombier */
548e288d156SDavid du Colombier DPRINT(">");
549e288d156SDavid du Colombier p->basepri = PriExtra;
550e288d156SDavid du Colombier p->fixedpri = 1;
551e288d156SDavid du Colombier edfunlock();
552e288d156SDavid du Colombier return 0; /* Stick on runq[PriExtra] */
553e288d156SDavid du Colombier }
554ea58ad6fSDavid du Colombier DPRINT("%lud edfready %lud[%s] wait release at %lud\n",
555e288d156SDavid du Colombier now, p->pid, statename[p->state], e->t);
556e288d156SDavid du Colombier p->state = Waitrelease;
557e288d156SDavid du Colombier edfunlock();
558e288d156SDavid du Colombier return 1; /* Make runnable later */
559e288d156SDavid du Colombier }
560ea58ad6fSDavid du Colombier DPRINT("%lud edfready %lud %s release now\n", now, p->pid, statename[p->state]);
561e288d156SDavid du Colombier /* release now */
562e288d156SDavid du Colombier release(p);
563e288d156SDavid du Colombier }
564da51d93aSDavid du Colombier edfunlock();
565e288d156SDavid du Colombier DPRINT("^");
566e288d156SDavid du Colombier rq = &runq[PriEdf];
567e288d156SDavid du Colombier /* insert in queue in earliest deadline order */
568e288d156SDavid du Colombier lock(runq);
569e288d156SDavid du Colombier l = nil;
570e288d156SDavid du Colombier for(pp = rq->head; pp; pp = pp->rnext){
571e288d156SDavid du Colombier if(pp->edf->d > e->d)
572e288d156SDavid du Colombier break;
573e288d156SDavid du Colombier l = pp;
574e288d156SDavid du Colombier }
575e288d156SDavid du Colombier p->rnext = pp;
576e288d156SDavid du Colombier if (l == nil)
577e288d156SDavid du Colombier rq->head = p;
578e288d156SDavid du Colombier else
579e288d156SDavid du Colombier l->rnext = p;
580e288d156SDavid du Colombier if(pp == nil)
581e288d156SDavid du Colombier rq->tail = p;
582e288d156SDavid du Colombier rq->n++;
583e288d156SDavid du Colombier nrdy++;
584e288d156SDavid du Colombier runvec |= 1 << PriEdf;
585e288d156SDavid du Colombier p->priority = PriEdf;
5869a747e4fSDavid du Colombier p->readytime = m->ticks;
5879a747e4fSDavid du Colombier p->state = Ready;
588da51d93aSDavid du Colombier unlock(runq);
589ea58ad6fSDavid du Colombier if(p->trace && (pt = proctrace))
5902cca75a1SDavid du Colombier pt(p, SReady, 0);
591e288d156SDavid du Colombier return 1;
592e288d156SDavid du Colombier }
5939a747e4fSDavid du Colombier
5949a747e4fSDavid du Colombier
5959a747e4fSDavid du Colombier static void
testenq(Proc * p)596e288d156SDavid du Colombier testenq(Proc *p)
5979a747e4fSDavid du Colombier {
598e288d156SDavid du Colombier Proc *xp, **xpp;
599e288d156SDavid du Colombier Edf *e;
6009a747e4fSDavid du Colombier
601e288d156SDavid du Colombier e = p->edf;
602e288d156SDavid du Colombier e->testnext = nil;
6039a747e4fSDavid du Colombier if (qschedulability == nil) {
604e288d156SDavid du Colombier qschedulability = p;
6059a747e4fSDavid du Colombier return;
6069a747e4fSDavid du Colombier }
607e288d156SDavid du Colombier SET(xp);
608e288d156SDavid du Colombier for (xpp = &qschedulability; *xpp; xpp = &xp->edf->testnext) {
609e288d156SDavid du Colombier xp = *xpp;
6102cca75a1SDavid du Colombier if (e->testtime - xp->edf->testtime < 0
611e288d156SDavid du Colombier || (e->testtime == xp->edf->testtime && e->testtype < xp->edf->testtype)){
612e288d156SDavid du Colombier e->testnext = xp;
613e288d156SDavid du Colombier *xpp = p;
6149a747e4fSDavid du Colombier return;
6159a747e4fSDavid du Colombier }
6169a747e4fSDavid du Colombier }
617e288d156SDavid du Colombier assert(xp->edf->testnext == nil);
618e288d156SDavid du Colombier xp->edf->testnext = p;
6199a747e4fSDavid du Colombier }
6209a747e4fSDavid du Colombier
6219a747e4fSDavid du Colombier static char *
testschedulability(Proc * theproc)622e288d156SDavid du Colombier testschedulability(Proc *theproc)
6239a747e4fSDavid du Colombier {
624e288d156SDavid du Colombier Proc *p;
6252cca75a1SDavid du Colombier long H, G, Cb, ticks;
626e288d156SDavid du Colombier int steps, i;
6279a747e4fSDavid du Colombier
6289a747e4fSDavid du Colombier /* initialize */
629e288d156SDavid du Colombier DPRINT("schedulability test %lud\n", theproc->pid);
6309a747e4fSDavid du Colombier qschedulability = nil;
631e288d156SDavid du Colombier for(i=0; i<conf.nproc; i++) {
632e288d156SDavid du Colombier p = proctab(i);
633e288d156SDavid du Colombier if(p->state == Dead)
6349a747e4fSDavid du Colombier continue;
635e288d156SDavid du Colombier if ((p->edf == nil || (p->edf->flags & Admitted) == 0) && p != theproc)
636e288d156SDavid du Colombier continue;
637e288d156SDavid du Colombier p->edf->testtype = Rl;
638e288d156SDavid du Colombier p->edf->testtime = 0;
639e288d156SDavid du Colombier DPRINT("\tInit: edfenqueue %lud\n", p->pid);
640e288d156SDavid du Colombier testenq(p);
6419a747e4fSDavid du Colombier }
6429a747e4fSDavid du Colombier H=0;
6439a747e4fSDavid du Colombier G=0;
6449a747e4fSDavid du Colombier for(steps = 0; steps < Maxsteps; steps++){
645e288d156SDavid du Colombier p = qschedulability;
646e288d156SDavid du Colombier qschedulability = p->edf->testnext;
647e288d156SDavid du Colombier ticks = p->edf->testtime;
648e288d156SDavid du Colombier switch (p->edf->testtype){
649e288d156SDavid du Colombier case Dl:
650e288d156SDavid du Colombier H += p->edf->C;
651e288d156SDavid du Colombier Cb = 0;
652ea58ad6fSDavid du Colombier DPRINT("\tStep %3d, Ticks %lud, pid %lud, deadline, H += %lud → %lud, Cb = %lud\n",
653e288d156SDavid du Colombier steps, ticks, p->pid, p->edf->C, H, Cb);
654d9306527SDavid du Colombier if (H+Cb>ticks){
655e288d156SDavid du Colombier DPRINT("not schedulable\n");
6569a747e4fSDavid du Colombier return "not schedulable";
657d9306527SDavid du Colombier }
658e288d156SDavid du Colombier p->edf->testtime += p->edf->T - p->edf->D;
659e288d156SDavid du Colombier p->edf->testtype = Rl;
660e288d156SDavid du Colombier testenq(p);
6619a747e4fSDavid du Colombier break;
662e288d156SDavid du Colombier case Rl:
663ea58ad6fSDavid du Colombier DPRINT("\tStep %3d, Ticks %lud, pid %lud, release, G %lud, C%lud\n",
664e288d156SDavid du Colombier steps, ticks, p->pid, p->edf->C, G);
665d9306527SDavid du Colombier if(ticks && G <= ticks){
666e288d156SDavid du Colombier DPRINT("schedulable\n");
6679a747e4fSDavid du Colombier return nil;
668d9306527SDavid du Colombier }
669e288d156SDavid du Colombier G += p->edf->C;
670e288d156SDavid du Colombier p->edf->testtime += p->edf->D;
671e288d156SDavid du Colombier p->edf->testtype = Dl;
672e288d156SDavid du Colombier testenq(p);
6739a747e4fSDavid du Colombier break;
6749a747e4fSDavid du Colombier default:
6759a747e4fSDavid du Colombier assert(0);
6769a747e4fSDavid du Colombier }
6779a747e4fSDavid du Colombier }
678e288d156SDavid du Colombier DPRINT("probably not schedulable\n");
6799a747e4fSDavid du Colombier return "probably not schedulable";
6809a747e4fSDavid du Colombier }
681