3 #include "../port/lib.h"
7 #include "../port/error.h"
8 #include "../port/edf.h"
16 #define DPRINT if(Dontprint){}else print
18 static long now; /* Low order 32 bits of time in µs */
19 extern ulong delayedscheds;
20 extern Schedq runq[Nrq];
24 /* Statistics stuff */
30 /* Edfschedlock protects modification of admission params */
36 Dl, /* Invariant for schedulability test: Dl < Rl */
40 static char *testschedulability(Proc*);
41 static Proc *qschedulability;
45 Onemillisecond = 1000,
47 OneRound = Onemillisecond/2,
59 t = va_arg(f->args, uvlong);
61 case 't': /* vlong in nanoseconds */
62 t = va_arg(f->args, long);
65 return fmtstrcpy(f, "(timeconv)");
75 sprint(buf, "%s%d.%.3ds", sign, (int)(t / Onesecond),
76 (int)(t % Onesecond)/Onemillisecond);
77 }else if (t > Onemillisecond)
78 sprint(buf, "%s%d.%.3dms", sign, (int)(t / Onemillisecond),
79 (int)(t % Onemillisecond));
81 sprint(buf, "%s%dµs", sign, (int)t);
82 return fmtstrcpy(f, buf);
95 if((e = p->edf) && (e->flags & Admitted)){
96 thelock.pc = getcallerpc(&p);
98 edfcycles -= lcycles();
112 edfcycles += lcycles();
122 fmtinstall('t', timeconv);
126 DPRINT("%lud edfinit %lud[%s]\n", now, p->pid, statename[p->state]);
127 p->edf = malloc(sizeof(Edf));
134 deadlineintr(Ureg*, Timer *t)
136 /* Proc reached deadline */
137 extern int panicking;
139 void (*pt)(Proc*, int, vlong);
141 if(panicking || active.exiting)
146 DPRINT("%lud deadlineintr %lud[%s]\n", now, p->pid, statename[p->state]);
147 /* If we're interrupting something other than the proc pointed to by t->a,
148 * we've already achieved recheduling, so we need not do anything
149 * Otherwise, we must cause a reschedule, but if we call sched()
150 * here directly, the timer interrupt routine will not finish its business
151 * Instead, we cause the resched to happen when the interrupted proc
152 * returns to user space
155 if(up->trace && (pt = proctrace))
165 /* Called with edflock held */
167 void (*pt)(Proc*, int, vlong);
176 if((e->flags & Sporadic) == 0){
178 * Non sporadic processes stay true to their period;
179 * calculate next release time.
180 * Second test limits duration of while loop.
182 if((n = now - e->t) > 0){
186 e->t = now + e->T - (n % e->T);
189 /* Sporadic processes may not be released earlier than
190 * one period after this release
196 DPRINT("%lud release %lud[%s], r=%lud, d=%lud, t=%lud, S=%lud\n",
197 now, p->pid, statename[p->state], e->r, e->d, e->t, e->S);
200 pt(p, SRelease, nowns);
201 pt(p, SDeadline, nowns + 1000LL*e->D);
204 DPRINT("%lud release %lud[%s], too late t=%lud, called from %#p\n",
205 now, p->pid, statename[p->state], e->t, getcallerpc(&p));
210 releaseintr(Ureg*, Timer *t)
213 extern int panicking;
216 if(panicking || active.exiting)
220 if((edflock(p)) == nil)
222 DPRINT("%lud releaseintr %lud[%s]\n", now, p->pid, statename[p->state]);
228 /* remove proc from current runq */
229 rq = &runq[p->priority];
230 if(dequeueproc(rq, p) != p){
231 DPRINT("releaseintr: can't find proc or lock race\n");
232 release(p); /* It'll start best effort */
236 p->state = Waitrelease;
241 if(p->state == Wakeme){
242 iprint("releaseintr: wakeme\n");
274 void (*pt)(Proc*, int, vlong);
276 if((e = edflock(p)) == nil)
282 e->extraused += used;
287 DPRINT("%lud edfrecord slice used up\n", now);
298 edfrun(Proc *p, int edfpri)
301 void (*pt)(Proc*, int, vlong);
305 /* Called with edflock held */
308 if(tns <= 0 || e->S == 0){
309 /* Deadline reached or resources exhausted,
310 * deschedule forthwith
321 e->tns = 1000LL * tns; /* µs to ns */
322 if(e->tt == nil || e->tf != deadlineintr){
323 DPRINT("%lud edfrun, deadline=%lud\n", now, tns);
327 if(p->trace && (pt = proctrace))
328 pt(p, SInte, todget(nil) + e->tns);
329 e->tmode = Trelative;
330 e->tf = deadlineintr;
346 void (*pt)(Proc*, int, vlong);
350 if (e->flags & Admitted)
351 return "task state"; /* should never happen */
353 /* simple sanity checks */
360 if (e->D == 0) /* if D is not set, set it to T */
365 qlock(&edfschedlock);
366 if (err = testschedulability(p)){
367 qunlock(&edfschedlock);
370 e->flags |= Admitted;
374 if(p->trace && (pt = proctrace))
377 /* Look for another proc with the same period to synchronize to */
379 for(i=0; i<conf.nproc; i++) {
381 if(r->state == Dead || r == p)
383 if (r->edf == nil || (r->edf->flags & Admitted) == 0)
385 if (r->edf->T == e->T)
388 if (i == conf.nproc){
389 /* Can't synchronize to another proc, release now */
394 DPRINT("%lud edfadmit self %lud[%s], release now: r=%lud d=%lud t=%lud\n",
395 now, p->pid, statename[p->state], e->r, e->d, e->t);
396 /* We're already running */
399 /* We're releasing another proc */
400 DPRINT("%lud edfadmit other %lud[%s], release now: r=%lud d=%lud t=%lud\n",
401 now, p->pid, statename[p->state], e->r, e->d, e->t);
404 qunlock(&edfschedlock);
409 /* Release in synch to something else */
412 DPRINT("%lud edfadmit self %lud[%s], release at %lud\n",
413 now, p->pid, statename[p->state], e->t);
415 qunlock(&edfschedlock);
418 DPRINT("%lud edfadmit other %lud[%s], release at %lud\n",
419 now, p->pid, statename[p->state], e->t);
426 e->tns = 1000LL * tns;
427 e->tmode = Trelative;
433 qunlock(&edfschedlock);
441 void (*pt)(Proc*, int, vlong);
444 DPRINT("%lud edfstop %lud[%s]\n", now, p->pid, statename[p->state]);
445 if(p->trace && (pt = proctrace))
447 e->flags &= ~Admitted;
458 return up->trend == nil || now - up->edf->r >= 0;
464 /* sleep until next release */
466 void (*pt)(Proc*, int, vlong);
469 if((e = edflock(up)) == nil)
471 if(up->trace && (pt = proctrace))
473 if((n = now - e->t) > 0){
477 e->t = now + e->T - (n % e->T);
486 up->tns = 1000LL * n;
487 up->tf = releaseintr;
488 up->tmode = Trelative;
490 up->trend = &up->sleep;
492 }else if(up->tf != releaseintr)
493 print("edfyield: surprise! %#p\n", up->tf);
495 sleep(&up->sleep, yfn, nil);
504 void (*pt)(Proc*, int, vlong);
507 if((e = edflock(p)) == nil)
510 if(p->state == Wakeme && p->r){
511 iprint("edfready: wakeme\n");
514 /* past deadline, arrange for next release */
515 if((e->flags & Sporadic) == 0){
517 * Non sporadic processes stay true to their period;
518 * calculate next release time.
520 if((n = now - e->t) > 0){
524 e->t = now + e->T - (n % e->T);
528 /* Next release is in the future, schedule it */
529 if(e->tt == nil || e->tf != releaseintr){
534 e->tmode = Trelative;
538 DPRINT("%lud edfready %lud[%s], release=%lud\n",
539 now, p->pid, statename[p->state], e->t);
541 if(p->state == Running && (e->flags & (Yield|Yieldonblock)) == 0 && (e->flags & Extratime)){
542 /* If we were running, we've overrun our CPU allocation
543 * or missed the deadline, continue running best-effort at low priority
544 * Otherwise we were blocked. If we don't yield on block, we continue
548 p->basepri = PriExtra;
551 return 0; /* Stick on runq[PriExtra] */
553 DPRINT("%lud edfready %lud[%s] wait release at %lud\n",
554 now, p->pid, statename[p->state], e->t);
555 p->state = Waitrelease;
557 return 1; /* Make runnable later */
559 DPRINT("%lud edfready %lud %s release now\n", now, p->pid, statename[p->state]);
566 /* insert in queue in earliest deadline order */
569 for(pp = rq->head; pp; pp = pp->rnext){
570 if(pp->edf->d > e->d)
583 runvec |= 1 << PriEdf;
584 p->priority = PriEdf;
585 p->readytime = m->ticks;
588 if(p->trace && (pt = proctrace))
602 if (qschedulability == nil) {
607 for (xpp = &qschedulability; *xpp; xpp = &xp->edf->testnext) {
609 if (e->testtime - xp->edf->testtime < 0
610 || (e->testtime == xp->edf->testtime && e->testtype < xp->edf->testtype)){
616 assert(xp->edf->testnext == nil);
617 xp->edf->testnext = p;
621 testschedulability(Proc *theproc)
624 long H, G, Cb, ticks;
628 DPRINT("schedulability test %lud\n", theproc->pid);
629 qschedulability = nil;
630 for(i=0; i<conf.nproc; i++) {
634 if ((p->edf == nil || (p->edf->flags & Admitted) == 0) && p != theproc)
636 p->edf->testtype = Rl;
637 p->edf->testtime = 0;
638 DPRINT("\tInit: edfenqueue %lud\n", p->pid);
643 for(steps = 0; steps < Maxsteps; steps++){
645 qschedulability = p->edf->testnext;
646 ticks = p->edf->testtime;
647 switch (p->edf->testtype){
651 DPRINT("\tStep %3d, Ticks %lud, pid %lud, deadline, H += %lud → %lud, Cb = %lud\n",
652 steps, ticks, p->pid, p->edf->C, H, Cb);
654 DPRINT("not schedulable\n");
655 return "not schedulable";
657 p->edf->testtime += p->edf->T - p->edf->D;
658 p->edf->testtype = Rl;
662 DPRINT("\tStep %3d, Ticks %lud, pid %lud, release, G %lud, C%lud\n",
663 steps, ticks, p->pid, p->edf->C, G);
664 if(ticks && G <= ticks){
665 DPRINT("schedulable\n");
669 p->edf->testtime += p->edf->D;
670 p->edf->testtype = Dl;
677 DPRINT("probably not schedulable\n");
678 return "probably not schedulable";