xref: /plan9/sys/src/9/port/edf.c (revision 4e3613ab15c331a9ada113286cc0f2a35bc0373d)
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