M alphapc/clock.c => alphapc/clock.c +8 -3
@@ 42,7 42,7 @@ cycletimer(void)
return MACHP(0)->fastclock;
}
-vlong
+uvlong
fastticks(uvlong* hz)
{
uvlong ticks;
@@ 55,7 55,12 @@ fastticks(uvlong* hz)
if(hz)
*hz = m->cpuhz;
- return (vlong)ticks;
+ return ticks;
+}
+
+void
+timerset(uvlong)
+{
}
void
@@ 87,7 92,7 @@ clock(Ureg *ureg)
return;
count -= 1024;
- portclock(ureg);
+ timerintr(ureg, 0);
}
ulong
M alphapc/dat.h => alphapc/dat.h +0 -12
@@ 1,5 1,4 @@
typedef struct Conf Conf;
-typedef struct Timer Timer;
typedef struct FPsave FPsave;
typedef struct ISAConf ISAConf;
typedef struct Label Label;
@@ 248,14 247,3 @@ struct DevConf
int nports; /* Number of ports */
port_t *ports; /* The ports themselves */
};
-
-/*
- * fasttick timer interrupts (Dummy for now)
- */
-struct Timer
-{
- vlong when; /* fastticks when f should be called */
- void (*f)(Ureg*, Timer*);
- void *a;
- Timer *next;
-};
M alphapc/main.c => alphapc/main.c +1 -0
@@ 91,6 91,7 @@ main(void)
procinit0();
initseg();
+ timersinit();
links();
chandevreset();
pageinit();
M bitsy/clock.c => bitsy/clock.c +1 -1
@@ 78,7 78,7 @@ clockinit(void)
* us at least once a second and we overflow once every 1165
* seconds, we won't miss an overflow.
*/
-vlong
+uvlong
fastticks(uvlong *hz)
{
static uvlong high;
M bitsy/dat.h => bitsy/dat.h +0 -13
@@ 16,7 16,6 @@ typedef struct PCMconftab PCMconftab;
typedef struct PhysUart PhysUart;
typedef struct PMMU PMMU;
typedef struct Proc Proc;
-typedef struct Timer Timer;
typedef struct Uart Uart;
typedef struct Ureg Ureg;
typedef struct Vctl Vctl;
@@ 262,15 261,3 @@ struct DevConf
ulong interrupt; /* interrupt number */
char *type; /* card type, mallocated */
};
-
-/*
- * Timer interrupts
- */
-struct Timer
-{
- uvlong when; /* fastticks when f should be called */
- ulong period; /* non-zero for recurring periodic timers */
- void (*f)(Ureg*, Timer*); /* function to call */
- void *a; /* User parameter */
- Timer *next;
-};
M mtx/clock.c => mtx/clock.c +6 -7
@@ 54,13 54,12 @@ clockintr(Ureg *ureg)
}
putdec(clkreload-v);
- if(m->flushmmu){
- if(up)
- flushmmu();
- m->flushmmu = 0;
- }
+ timerintr(ureg, 0);
+}
- portclock(ureg);
+void
+timerset(uvlong)
+{
}
void
@@ 88,7 87,7 @@ microdelay(int l)
;
}
-vlong
+uvlong
fastticks(uvlong *hz)
{
if(hz)
M mtx/dat.h => mtx/dat.h +0 -11
@@ 1,5 1,4 @@
typedef struct Conf Conf;
-typedef struct Timer Timer;
typedef struct FPsave FPsave;
typedef struct ISAConf ISAConf;
typedef struct Label Label;
@@ 192,16 191,6 @@ struct ISAConf {
int nopt;
char *opt[NISAOPT];
};
-/*
- * fasttick timer interrupts (Dummy for now)
- */
-struct Timer
-{
- vlong when; /* fastticks when f should be called */
- void (*f)(Ureg*, Timer*);
- void *a;
- Timer *next;
-};
#define MACHP(n) ((Mach *)((int)&mach0+n*BY2PG))
extern Mach mach0;
M mtx/main.c => mtx/main.c +1 -0
@@ 32,6 32,7 @@ main(void)
kbdinit();
procinit0();
initseg();
+ timersinit();
links();
chandevreset();
pageinit();
M pc/apic.c => pc/apic.c +58 -12
@@ 88,7 88,14 @@ enum { /* LapicTDCR */
};
static ulong* lapicbase;
-static int clkin;
+
+struct
+{
+ uvlong hz;
+ ulong max;
+ ulong min;
+ ulong mult; /* factor to mutiply fast ticks by to get lapicticks<<16 */
+} lapictimer;
static int
lapicr(int r)
@@ 113,32 120,36 @@ lapiconline(void)
* accepted by the APIC.
*/
microdelay((TK2MS(1)*1000/conf.nmach) * m->machno);
- lapicw(LapicTICR, clkin/HZ);
+ lapicw(LapicTICR, lapictimer.max);
lapicw(LapicTIMER, LapicCLKIN|LapicPERIODIC|(VectorPIC+IrqTIMER));
lapicw(LapicTPR, 0);
}
+/*
+ * use the i8253 clock to figure out our lapic timer rate.
+ */
static void
lapictimerinit(void)
{
- ulong lo, v;
- vlong tsc;
+ uvlong x, v, hz;
v = m->cpuhz/1000;
lapicw(LapicTDCR, LapicX1);
lapicw(LapicTIMER, ApicIMASK|LapicCLKIN|LapicONESHOT|(VectorPIC+IrqTIMER));
- if(clkin == 0){
- lapicw(LapicTICR, v);
- wrmsr(0x10, 0);
-
+ if(lapictimer.hz == 0ULL){
+ x = fastticks(&hz);
+ x += hz/10;
+ lapicw(LapicTICR, 0xffffffff);
do{
- rdtsc(&tsc);
- lo = (ulong)tsc;
- }while(lo < v);
+ v = fastticks(nil);
+ }while(v < x);
- clkin = ((v-lapicr(LapicTCCR)+500)/1000)*1000*1000;
+ lapictimer.hz = (0xffffffffUL-lapicr(LapicTCCR))*10;
+ lapictimer.max = lapictimer.hz/HZ;
+ lapictimer.min = lapictimer.hz/(100*HZ);
+ lapictimer.mult = (lapictimer.hz<<16)/hz;
}
}
@@ 331,3 342,38 @@ ioapicinit(Apic* apic, int apicno)
for(v = 0; v <= apic->mre; v++)
ioapicrdtw(apic, v, hi, lo);
}
+
+ulong lapicperiodset[32];
+
+void
+lapictimerset(uvlong next)
+{
+ ulong period;
+ int x;
+
+ x = splhi();
+ lock(&m->apictimerlock);
+ period = lapictimer.max;
+ if(next != 0){
+ period = next - fastticks(nil);
+ period *= lapictimer.mult;
+ period >>= 16;
+
+ if(period < lapictimer.min)
+ period = lapictimer.min;
+ else if(period > lapictimer.max - lapictimer.min)
+ period = lapictimer.max;
+ }
+
+ lapicw(LapicTICR, period);
+ lapicperiodset[m->machno]++;
+
+ unlock(&m->apictimerlock);
+ splx(x);
+}
+
+void
+lapicclock(Ureg *u, void*)
+{
+ timerintr(u, 0);
+}
M pc/archmp.c => pc/archmp.c +7 -13
@@ 90,17 90,11 @@ identify(void)
}
PCArch archmp = {
- "_MP_", /* id */
- identify, /* ident */
- mpshutdown, /* reset */
- 0, /* serialpower */
- 0, /* modempower */
-
- mpinit, /* intrinit */
- mpintrenable, /* intrenable */
- 0, /* intrvecno */
- 0, /* intrdisable */
-
- 0, /* clockenable */
- i8253read, /* fastclock */
+.id= "_MP_",
+.ident= identify,
+.reset= mpshutdown,
+.intrinit= mpinit,
+.intrenable= mpintrenable,
+.fastclock= i8253read,
+.timerset= lapictimerset,
};
M pc/dat.h => pc/dat.h +2 -13
@@ 1,5 1,4 @@
typedef struct Conf Conf;
-typedef struct Timer Timer;
typedef struct FPsave FPsave;
typedef struct ISAConf ISAConf;
typedef struct Label Label;
@@ 184,6 183,7 @@ struct Mach
int loopconst;
+ Lock apictimerlock;
int cpumhz;
vlong cpuhz;
int cpuidax;
@@ 191,7 191,6 @@ struct Mach
char cpuidid[16];
char* cpuidtype;
int havetsc;
- vlong lasttsc; /* last sampled value */
vlong mtrrcap;
vlong mtrrdef;
@@ 202,17 201,6 @@ struct Mach
};
/*
- * fasttick timer interrupts
- */
-struct Timer
-{
- vlong when; /* fastticks when f should be called */
- void (*f)(Ureg*, Timer*);
- void *a;
- Timer *next;
-};
-
-/*
* Fake kmap
*/
typedef void KMap;
@@ 246,6 234,7 @@ struct PCArch
void (*clockenable)(void);
uvlong (*fastclock)(uvlong*);
+ void (*timerset)(uvlong);
};
/*
M pc/devarch.c => pc/devarch.c +25 -2
@@ 508,6 508,7 @@ PCArch archgeneric = {
i8253enable, /* clockenable */
i8253read, /* read the standard timer */
+ i8253timerset,
};
typedef struct {
@@ 681,6 682,12 @@ cpuidentify(void)
rdmsr(0x01, &mct);
}
+ if(t->family >= 6){
+ cr4 = getcr4();
+ cr4 |= 0x80; /* page global enable bit */
+ putcr4(cr4);
+ }
+
cputype = t;
return t->family;
}
@@ 724,8 731,6 @@ archinit(void)
arch->intrinit = archgeneric.intrinit;
if(arch->intrenable == 0)
arch->intrenable = archgeneric.intrenable;
- if(arch->intrenable == 0)
- arch->intrenable = archgeneric.intrenable;
}
/*
@@ 758,3 763,21 @@ pcmspecialclose(int a)
if (_pcmspecialclose != nil)
_pcmspecialclose(a);
}
+
+/*
+ * return value and speed of timer set in arch->clockenable
+ */
+uvlong
+fastticks(uvlong *hz)
+{
+ return (*arch->fastclock)(hz);
+}
+
+/*
+ * set next timer interrupt
+ */
+void
+timerset(uvlong x)
+{
+ (*arch->timerset)(x);
+}
M pc/fns.h => pc/fns.h +3 -6
@@ 6,7 6,6 @@ Dirtab* addarchfile(char*, int, long(*)(Chan*,void*,long,vlong), long(*)(Chan*,v
void apicclkenable(void);
void archinit(void);
void bootargs(ulong);
-vlong checktimer(Ureg*, void*);
int cistrcmp(char*, char*);
int cistrncmp(char*, char*, int);
#define clearmmucache() /* x86 doesn't have one */
@@ 16,10 15,6 @@ void (*coherence)(void);
void cpuid(char*, int*, int*);
int cpuidentify(void);
void cpuidprint(void);
-void timeradd(Timer*);
-void timerdel(Timer*);
-void timerset(vlong);
-vlong timernext(void);
void delay(int);
int dmacount(int);
int dmadone(int);
@@ 40,7 35,6 @@ ulong getcr4(void);
char* getconf(char*);
void guesscpuhz(int);
void halt(void);
-int havetimer(void);
int i8042auxcmd(int);
void i8042auxenable(void (*)(int, int));
void i8042reset(void);
@@ 48,6 42,7 @@ void i8250console(void);
void* i8250alloc(int, int, int);
void i8253init(void);
void i8253enable(void);
+void i8253timerset(uvlong);
uvlong i8253read(uvlong*);
void i8259init(void);
int i8259isr(int);
@@ 73,6 68,8 @@ int iprint(char*, ...);
int isaconfig(char*, int, ISAConf*);
void kbdinit(void);
#define kmapinval()
+void lapicclock(Ureg*, void*);
+void lapictimerset(uvlong);
void lgdt(ushort[3]);
void lidt(ushort[3]);
void links(void);
M pc/i8253.c => pc/i8253.c +75 -99
@@ 46,38 46,29 @@ enum
Trigger=0x0, /* interrupt on terminal count */
Sstrobe=0x8, /* software triggered strobe */
- /* counter 2 controls */
- C2gate= 0x1,
- C2speak=0x2,
- C2out= 0x10,
-
/* T2ctl bits */
T2gate= (1<<0), /* enable T2 counting */
T2spkr= (1<<1), /* connect T2 out to speaker */
T2out= (1<<5), /* output of T2 */
Freq= 1193182, /* Real clock frequency */
- Tickshift= 8, /* increase tick wriggle room */
-
- Minusec=20, /* minimum cycles for a clock interrupt */
-
- FreqMul=16, /* extra accuracy in fastticks/Freq calculation; ok up to ~8ghz */
+ Tickshift=8, /* extra accuracy */
+ MaxPeriod=Freq/HZ,
+ MinPeriod=Freq/(100*HZ),
};
static struct
{
Lock;
+ ulong period; /* current clock period */
int enabled;
- int mode;
- vlong when; /* next fastticks a clock interrupt should occur */
- vlong timerwhen; /* next fastticks a cycintr happens; 0 == infinity */
- long fastperiod; /* fastticks/hz */
- long fast2freq; /* fastticks*FreqMul/Freq */
+ uvlong hz;
ushort last; /* last value of clock 1 */
uvlong ticks; /* cumulative ticks of counter 1 */
}i8253;
+
void
i8253init(void)
{
@@ 87,12 78,12 @@ i8253init(void)
ioalloc(T2ctl, 1, 0, "i8253.cntr2ctl");
/*
- * set interrupting clock for 1/HZ seconds
+ * enable a 1/HZ interrupt for providing scheduling interrupts
*/
outb(Tmode, Load0|Square);
- i8253.mode = Square;
outb(T0cntr, (Freq/HZ)); /* low byte */
outb(T0cntr, (Freq/HZ)>>8); /* high byte */
+ i8253.period = Freq/HZ;
/*
* enable a longer period counter to use as a clock
@@ 100,10 91,11 @@ i8253init(void)
outb(Tmode, Load2|Square);
outb(T2cntr, 0); /* low byte */
outb(T2cntr, 0); /* high byte */
+ i8253.period = Freq/HZ;
x = inb(T2ctl);
x |= T2gate;
outb(T2ctl, x);
-
+
/*
* Introduce a little delay to make sure the count is
* latched and the timer is counting down; with a fast
@@ 189,97 181,58 @@ guesscpuhz(int aalcycles)
m->cpumhz = (cpufreq + cpufreq/200)/1000000;
m->cpuhz = cpufreq;
}
-}
-/*
- * schedule the next interrupt
- * timerwhen is the time of the next interrupt
- */
-static void
-clockintrsched0(vlong next)
-{
- vlong now;
- long set;
-
- i8253.timerwhen = next;
- if(i8253.mode == Square && next == 0)
- return;
-
- now = fastticks(nil);
- if(next || now < i8253.when - i8253.fastperiod || now > i8253.when - ((3*i8253.fastperiod)>>2)){
- if(next > i8253.when)
- next = i8253.when;
- set = (long)(next - now) * FreqMul / i8253.fast2freq;
- set -= 3; /* three cycles for the count to take effect: outb, outb, wait */
- if(i8253.mode != Trigger){
- outb(Tmode, Load0|Trigger);
- i8253.mode = Trigger;
- set--;
- }
- if(set < Minusec)
- set = Minusec;
- outb(T0cntr, set); /* low byte */
- outb(T0cntr, set>>8); /* high byte */
- }else if(i8253.mode != Square){
- i8253.mode = Square;
- outb(Tmode, Load0|Square);
- outb(T0cntr, (Freq/HZ)); /* low byte */
- outb(T0cntr, (Freq/HZ)>>8); /* high byte */
- }
+ i8253.hz = Freq<<Tickshift;
}
-int
-havetimer(void)
-{
- return i8253.enabled;
-}
+ulong i8253periodset;
void
-clockintrsched(void)
+i8253timerset(uvlong next)
{
- vlong next;
+ ulong period;
+ ulong want;
+ ulong now;
+
+ want = next>>Tickshift;
+ now = i8253.ticks; /* assuming whomever called us just did fastticks() */
+
+ period = MaxPeriod;
+ if(next != 0){
+ period = want - now;
+ if(period < MinPeriod)
+ period = MinPeriod;
+ else if(period > (4*MaxPeriod)/5) /* strong attraction to MaxPeriod */
+ period = MaxPeriod;
+ }
- ilock(&i8253);
- if(i8253.enabled){
- next = timernext();
- if(next != i8253.timerwhen)
- clockintrsched0(next);
+ /* histeresis */
+ if(i8253.period != period){
+ ilock(&i8253);
+ /* load new value */
+ outb(Tmode, Load0|Square);
+ outb(T0cntr, period); /* low byte */
+ outb(T0cntr, period>>8); /* high byte */
+
+ /* remember period */
+ i8253.period = period;
+ i8253periodset++;
+ iunlock(&i8253);
}
- iunlock(&i8253);
}
static void
-clockintr0(Ureg* ureg, void *v)
+i8253clock(Ureg* ureg, void*)
{
- vlong now, when;
-
- /* goes with syncing in squidboy */
- if(m->havetsc)
- rdtsc(&m->lasttsc);
-
- now = fastticks(nil);
- when = i8253.when;
-
- if(now >= i8253.when){
- clockintr(ureg, v);
- do
- i8253.when += i8253.fastperiod;
- while(i8253.when < now);
- }
- if(i8253.timerwhen || i8253.mode != Square)
- clockintrsched0(checktimer(ureg, v));
+ timerintr(ureg, 0);
}
void
i8253enable(void)
{
- uvlong hz;
-
- i8253.when = fastticks(&hz);
- i8253.fastperiod = (hz + HZ/2) / HZ;
- i8253.fast2freq = (hz * FreqMul) / Freq;
i8253.enabled = 1;
- intrenable(IrqCLOCK, clockintr0, 0, BUSUNKNOWN, "clock");
+ i8253.period = Freq/HZ;
+ intrenable(IrqCLOCK, i8253clock, 0, BUSUNKNOWN, "clock");
}
/*
@@ 294,7 247,7 @@ i8253read(uvlong *hz)
uvlong ticks;
if(hz)
- *hz = Freq<<Tickshift;
+ *hz = i8253.hz;
ilock(&i8253);
outb(Tmode, Latch2);
@@ 304,7 257,7 @@ i8253read(uvlong *hz)
if(y < i8253.last)
x = i8253.last - y;
else
- x = i8253.last + (0x1000 - y);
+ x = i8253.last + (0x10000 - y);
i8253.last = y;
i8253.ticks += x>>1;
ticks = i8253.ticks;
@@ 313,11 266,34 @@ i8253read(uvlong *hz)
return ticks<<Tickshift;
}
-/*
- * return value and speed of timer set in arch->clockenable
- */
-vlong
-fastticks(uvlong *hz)
+void
+delay(int millisecs)
+{
+ millisecs *= m->loopconst;
+ if(millisecs <= 0)
+ millisecs = 1;
+ aamloop(millisecs);
+}
+
+void
+microdelay(int microsecs)
+{
+ microsecs *= m->loopconst;
+ microsecs /= 1000;
+ if(microsecs <= 0)
+ microsecs = 1;
+ aamloop(microsecs);
+}
+
+ulong
+TK2MS(ulong ticks)
{
- return (*arch->fastclock)(hz);
+ uvlong t, hz;
+
+ t = ticks;
+ hz = HZ;
+ t *= 1000L;
+ t = t/hz;
+ ticks = t;
+ return ticks;
}
M pc/main.c => pc/main.c +2 -0
@@ 30,6 30,7 @@ char *confval[MAXCONF];
int nconf;
uchar *sp; /* user stack of init proc */
+
static void
options(void)
{
@@ 93,6 94,7 @@ main(void)
mmuinit();
if(arch->intrinit)
arch->intrinit();
+ timersinit();
mathinit();
kbdinit();
if(arch->clockenable)
M pc/mem.h => pc/mem.h +1 -0
@@ 125,6 125,7 @@
#define PTEKERNEL (0<<2)
#define PTEUSER (1<<2)
#define PTESIZE (1<<7)
+#define PTEGLOBAL (1<<8)
/*
* Macros for calculating offsets within the page directory base
M pc/mp.c => pc/mp.c +2 -50
@@ 19,7 19,6 @@ static int machno2apicno[MaxAPICNO+1]; /* inverse map: machno -> APIC ID */
static Lock mprdthilock;
static int mprdthi;
static Ref mpvnoref; /* unique vector assignment */
-static Lock mpclocksynclock;
static char* buses[] = {
"CBUSI ",
@@ 43,41 42,6 @@ static char* buses[] = {
0,
};
-void
-apicclkenable(void)
-{
- Apic *apic;
-
- /* Uniprocessor local apic init for apic clock */
- apic = &mpapic[0];
- apic->type = PcmpPROCESSOR;
- apic->apicno = 0;
- apic->flags = 0;
- apic->lintr[0] = ApicIMASK;
- apic->lintr[1] = ApicIMASK;
- apic->machno = 0;
- apic->addr = (ulong*)0xfee00000;
- machno2apicno[0] = 0;
-
- /*
- * Map the local APIC.
- */
- if(mmukmap((ulong)apic->addr, 0, 1024) == 0)
- return;
-
- /*
- * These interrupts are local to the processor
- * and do not appear in the I/O APIC so it is OK
- * to set them now.
- */
- intrenable(IrqTIMER, clockintr, 0, BUSUNKNOWN, "clock");
- intrenable(IrqERROR, lapicerror, 0, BUSUNKNOWN, "lapicerror");
- intrenable(IrqSPURIOUS, lapicspurious, 0, BUSUNKNOWN, "lapicspurious");
-
- lapicinit(apic);
- lapiconline();
-}
-
static Apic*
mkprocessor(PCMPprocessor* p)
{
@@ 386,8 350,6 @@ checkmtrr(void)
static void
squidboy(Apic* apic)
{
- ulong x;
-
// iprint("Hello Squidboy\n");
machinit();
@@ 401,19 363,9 @@ squidboy(Apic* apic)
mprdthi |= (1<<apic->apicno)<<24;
unlock(&mprdthilock);
- if(m->havetsc){
- /*
- * Restrain your octopus! Don't let it go out on the sea!
- */
- ilock(&mpclocksynclock);
- x = MACHP(0)->ticks;
- while(MACHP(0)->ticks == x)
- ;
- wrmsr(0x10, MACHP(0)->lasttsc); /* synchronize fast counters */
- iunlock(&mpclocksynclock);
- }
lapicinit(apic);
lapiconline();
+ timersinit();
lock(&active);
active.machs |= 1<<m->machno;
@@ 587,7 539,7 @@ mpinit(void)
* and do not appear in the I/O APIC so it is OK
* to set them now.
*/
- intrenable(IrqTIMER, clockintr, 0, BUSUNKNOWN, "clock");
+ intrenable(IrqTIMER, lapicclock, 0, BUSUNKNOWN, "clock");
intrenable(IrqERROR, lapicerror, 0, BUSUNKNOWN, "lapicerror");
intrenable(IrqSPURIOUS, lapicspurious, 0, BUSUNKNOWN, "lapicspurious");
lapiconline();
M port/auth.c => port/auth.c +1 -1
@@ 100,7 100,7 @@ sysfauth(ulong *arg)
long
userwrite(char *a, int n)
{
- if(strcmp(a, "none") != 0)
+ if(n!=4 || strncmp(a, "none", 4)!=0)
error(Eperm);
kstrdup(&up->user, "none");
up->basepri = PriNormal;
M port/devcons.c => port/devcons.c +0 -8
@@ 384,14 384,6 @@ echo(char *buf, int n)
case 'q':
scheddump();
return;
-#ifdef RSC
-case 'Q':
-{
-extern void dumpschedlog(void);
-dumpschedlog();
-return;
-}
-#endif
case 'k':
if(!cpuserver)
killbig();
M port/devloopback.c => port/devloopback.c +0 -3
@@ 129,9 129,6 @@ loopbackattach(char *spec)
int chan;
int dev;
- if(!havetimer())
- error("can't time packets");
-
dev = 0;
if(spec != nil){
dev = atoi(spec);
M port/devrealtime.c => port/devrealtime.c +12 -18
@@ 76,7 76,7 @@ dumptask(char *p, char *e, Task *t, Ticks now)
char c;
p = seprint(p, e, "{%s, D%U, Δ%U,T%U, C%U, S%U",
- edf_statename[t->state], t->D, t->Delta, t->T, t->C, t->S);
+ edfstatename[t->state], t->D, t->Delta, t->T, t->C, t->S);
n = t->r - now;
if (n >= 0)
c = ' ';
@@ 224,16 224,12 @@ devrtinit(void)
static Chan *
devrtattach(char *param)
{
- if(havetimer() == 0)
- error("no edf on multiprocessors");
return devattach('R', param);
}
static Walkqid *
devrtwalk(Chan *c, Chan *nc, char **name, int nname)
{
- if (havetimer() == 0)
- error("no edf on multiprocessors");
return devwalk(c, nc, name, nname, nil, 0, schedgen);
}
@@ 267,8 263,6 @@ devrtopen(Chan *c, int mode)
{
Task *t;
- if (havetimer() == 0)
- error("no edf on multiprocessors");
switch ((ulong)c->qid.path){
case Qlog:
case Qnblog:
@@ 292,7 286,7 @@ devrtopen(Chan *c, int mode)
case Qclone:
if (mode == OREAD)
error(Eperm);
- edf_init();
+ edfinit();
/* open a new task */
for (t = tasks; t< tasks + Maxtasks; t++){
qlock(t);
@@ 465,7 459,7 @@ devrtread(Chan *c, void *v, long n, vlong offs)
p = buf;
e = p + sizeof(buf);
p = seprint(p, e, "task=%d", s);
- p = seprint(p, e, " state=%s", edf_statename[t->state]);
+ p = seprint(p, e, " state=%s", edfstatename[t->state]);
if (t->T)
p = seprint(p, e, " T=%T", ticks2time(t->T));
if (t->D)
@@ 634,7 628,7 @@ removetask(Task *t)
Resource *r;
qlock(t);
- edf_expel(t);
+ edfexpel(t);
for (pp = t->procs; pp < t->procs + nelem(t->procs); pp++)
if (p = *pp)
p->task = nil;
@@ 720,7 714,7 @@ devrtwrite(Chan *c, void *va, long n, vlong)
if (e=parsetime(&time, v))
error(e);
ticks = time2ticks(time);
- edf_expel(t);
+ edfexpel(t);
switch(add){
case -1:
if (ticks > t->T)
@@ 739,7 733,7 @@ devrtwrite(Chan *c, void *va, long n, vlong)
if (e=parsetime(&time, v))
error(e);
ticks = time2ticks(time);
- edf_expel(t);
+ edfexpel(t);
switch(add){
case -1:
if (ticks > t->D)
@@ 758,7 752,7 @@ devrtwrite(Chan *c, void *va, long n, vlong)
if (e=parsetime(&time, v))
error(e);
ticks = time2ticks(time);
- edf_expel(t);
+ edfexpel(t);
switch(add){
case -1:
if (ticks > t->C)
@@ 776,7 770,7 @@ devrtwrite(Chan *c, void *va, long n, vlong)
}else if (strcmp(a, "resources") == 0){
if (v == nil)
error("resources: value missing");
- edf_expel(t);
+ edfexpel(t);
if (add == 0){
for (rp = t->res; rp < t->res + nelem(t->res); rp++)
if (*rp){
@@ 801,7 795,7 @@ devrtwrite(Chan *c, void *va, long n, vlong)
if (v == nil)
error("procs: value missing");
if (add <= 0){
- edf_expel(t);
+ edfexpel(t);
}
if (add == 0){
for (pp = t->procs; pp < t->procs + nelem(t->procs); pp++)
@@ 828,11 822,11 @@ devrtwrite(Chan *c, void *va, long n, vlong)
}
}else if (strcmp(a, "admit") == 0){
/* Do the admission test */
- if (e = edf_admit(t))
+ if (e = edfadmit(t))
error(e);
}else if (strcmp(a, "expel") == 0){
/* Do the admission test */
- edf_expel(t);
+ edfexpel(t);
}else if (strcmp(a, "remove") == 0){
/* Do the admission test */
removetask(t);
@@ 854,7 848,7 @@ devrtwrite(Chan *c, void *va, long n, vlong)
t->flags |= Useblocking;
}else if (strcmp(a, "yield") == 0){
if (isedf(up) && up->task == t){
- edf_deadline(up); /* schedule next release */
+ edfdeadline(up); /* schedule next release */
sched();
}else
error("yield outside task");
M port/edf.c => port/edf.c +104 -90
@@ 12,7 12,7 @@
int edfprint = 0;
#define DPRINT if(edfprint)iprint
-char *edf_statename[] = {
+char *edfstatename[] = {
[EdfUnused] = "Unused",
[EdfExpelled] = "Expelled",
[EdfAdmitted] = "Admitted",
@@ 26,8 26,8 @@ char *edf_statename[] = {
[EdfDeadline] = "Deadline",
};
-static Timer cycdeadline; /* Time of next deadline */
-static Timer cycrelease; /* Time of next release */
+static Timer deadlinetimer[MAXMACH]; /* Time of next deadline */
+static Timer releasetimer[MAXMACH]; /* Time of next release */
static int initialized;
static uvlong fasthz;
@@ 39,7 39,7 @@ Task tasks[Maxtasks];
int ntasks;
Resource resources[Maxresources];
int nresources;
-int edf_stateupdate;
+int edfstateupdate;
enum{
Deadline, /* Invariant for schedulability test: Deadline < Release */
@@ 58,24 58,23 @@ Taskq qreleased = {{0}, nil, earlierdeadline};
/* Exhausted EDF tasks, append at end */
Taskq qextratime;
-/* Tasks admitted waiting for first release */
-Taskq qadmit;
-
/* Running/Preempted EDF tasks, head running, one stack per processor */
Taskq edfstack[MAXMACH];
void (*devrt)(Task*, Ticks, int);
-static void edf_resched(Task *t);
+static void edfresched(Task *t);
static void setdelta(void);
static void testdelta(Task *thetask);
-static char * edf_testschedulability(Task *thetask);
static void edfreleaseintr(Ureg *, Timer *cy);
static void edfdeadlineintr(Ureg*, Timer*);
+static char * edftestschedulability(Task *thetask);
void
-edf_init(void)
+edfinit(void)
{
+ int i;
+
if (initialized)
return;
ilock(&edflock);
@@ 84,12 83,14 @@ edf_init(void)
return;
}
fastticks(&fasthz);
- cycdeadline.f = edfdeadlineintr;
- cycdeadline.a = &cycdeadline;
- cycdeadline.when = 0;
- cycrelease.f = edfreleaseintr;
- cycrelease.a = &cycrelease;
- cycrelease.when = 0;
+ for (i = 0; i < conf.nmach; i++){
+ deadlinetimer[i].f = edfdeadlineintr;
+ deadlinetimer[i].a = &deadlinetimer[i];
+ deadlinetimer[i].when = 0;
+ releasetimer[i].f = edfreleaseintr;
+ releasetimer[i].a = &releasetimer[i];
+ releasetimer[i].when = 0;
+ }
initialized = 1;
iunlock(&edflock);
}
@@ 101,7 102,7 @@ isedf(Proc *p)
}
int
-edf_anyready(void)
+edfanyready(void)
{
/* If any edf tasks (with runnable procs in them) are released,
* at least one of them must be on the stack
@@ 114,7 115,7 @@ edfpush(Task *t)
{
Taskq *q;
- DPRINT("%d edfpush, %s, %d\n", m->machno, edf_statename[t->state], t->runq.n);
+ DPRINT("%d edfpush, %s, %d\n", m->machno, edfstatename[t->state], t->runq.n);
q = edfstack + m->machno;
assert(t->runq.n || (up && up->task == t));
if (q->head){
@@ 153,7 154,7 @@ edfenqueue(Taskq *q, Task *t)
{
Task *tt, **ttp;
- DPRINT("%d edfenqueue, %s, %d\n", m->machno, edf_statename[t->state], t->runq.n);
+ DPRINT("%d edfenqueue, %s, %d\n", m->machno, edfstatename[t->state], t->runq.n);
t->rnext = nil;
if (q->head == nil) {
q->head = t;
@@ 193,7 194,7 @@ edfqremove(Taskq *q, Task *t)
{
Task **tp;
- DPRINT("%d edfqremove, %s, %d\n", m->machno, edf_statename[t->state], t->runq.n);
+ DPRINT("%d edfqremove, %s, %d\n", m->machno, edfstatename[t->state], t->runq.n);
for (tp = &q->head; *tp; tp = &(*tp)->rnext){
if (*tp == t){
*tp = t->rnext;
@@ 213,17 214,16 @@ edfreleasetimer(void)
if ((t = qwaitrelease.head) == nil)
return;
DPRINT("edfreleasetimer clock\n");
- if (cycrelease.when)
- timerdel(&cycrelease);
- cycrelease.when = t->r;
- if (cycrelease.when <= now)
- cycrelease.when = now;
- timeradd(&cycrelease);
- clockintrsched();
+ if (releasetimer[m->machno].when)
+ timerdel(&releasetimer[m->machno]);
+ releasetimer[m->machno].when = t->r;
+ if (releasetimer[m->machno].when <= now)
+ releasetimer[m->machno].when = now;
+ timeradd(&releasetimer[m->machno]);
}
void
-edf_block(Proc *p)
+edfblock(Proc *p)
{
Task *t, *pt;
@@ 236,7 236,7 @@ edf_block(Proc *p)
iunlock(&edflock);
return;
}
- DPRINT("%d edf_block, %s, %d\n", m->machno, edf_statename[t->state], t->runq.n);
+ DPRINT("%d edfblock, %s, %d\n", m->machno, edfstatename[t->state], t->runq.n);
if (t->runq.n){
/* There's another runnable proc in the running task, leave task where it is */
@@ 251,12 251,12 @@ edf_block(Proc *p)
}
static void
-edfdeadline(Proc *p, SEvent why)
+deadline(Proc *p, SEvent why)
{
Task *t, *nt;
/* Task has reached its deadline, lock must be held */
- DPRINT("%d edfdeadline, %s, %d\n", m->machno, edf_statename[p->task->state], p->task->runq.n);
+ DPRINT("%d deadline, %s, %d\n", m->machno, edfstatename[p->task->state], p->task->runq.n);
SET(nt);
if (p){
nt = p->task;
@@ 266,34 266,33 @@ edfdeadline(Proc *p, SEvent why)
t = edfpop();
if(p != nil && nt != t){
- iprint("edfdeadline, %s, %d\n", edf_statename[p->task->state], p->task->runq.n);
+ iprint("deadline, %s, %d\n", edfstatename[p->task->state], p->task->runq.n);
iunlock(&edflock);
assert(0 && p == nil || nt == t);
}
- if (cycdeadline.when){
- timerdel(&cycdeadline);
- cycdeadline.when = 0;
- clockintrsched();
+ if (deadlinetimer[m->machno].when){
+ timerdel(&deadlinetimer[m->machno]);
+ deadlinetimer[m->machno].when = 0;
}
t->d = now;
t->state = EdfDeadline;
if(devrt) devrt(t, now, why);
- edf_resched(t);
+ edfresched(t);
}
void
-edf_deadline(Proc *p)
+edfdeadline(Proc *p)
{
- DPRINT("%d edf_deadline\n", m->machno);
+ DPRINT("%d edfdeadline\n", m->machno);
/* Task has reached its deadline */
ilock(&edflock);
now = fastticks(nil);
- edfdeadline(p, SYield);
+ deadline(p, SYield);
iunlock(&edflock);
}
char *
-edf_admit(Task *t)
+edfadmit(Task *t)
{
char *err;
@@ 313,18 312,18 @@ edf_admit(Task *t)
return "C > D";
qlock(&edfschedlock);
- if (err = edf_testschedulability(t)){
+ if (err = edftestschedulability(t)){
qunlock(&edfschedlock);
return err;
}
ilock(&edflock);
- DPRINT("%d edf_admit, %s, %d\n", m->machno, edf_statename[t->state], t->runq.n);
+ DPRINT("%d edfadmit, %s, %d\n", m->machno, edfstatename[t->state], t->runq.n);
now = fastticks(nil);
t->state = EdfAdmitted;
if(devrt) devrt(t, t->d, SAdmit);
if (up->task == t){
- DPRINT("%d edf_admitting self\n", m->machno);
+ DPRINT("%d edfadmitting self\n", m->machno);
/* Admitting self, fake reaching deadline */
t->r = now;
t->t = now + t->T;
@@ 337,16 336,18 @@ edf_admit(Task *t)
setdelta();
assert(t->runq.n > 0 || (up && up->task == t));
edfpush(t);
+ if (deadlinetimer[m->machno].when)
+ timerdel(&deadlinetimer[m->machno]);
+ deadlinetimer[m->machno].when = t->d;
+ timeradd(&deadlinetimer[m->machno]);
}else{
if (t->runq.n){
if (edfstack[m->machno].head == nil){
t->state = EdfAdmitted;
t->r = now;
- edf_release(t);
+ edfrelease(t);
setdelta();
- edf_resched(t);
- }else{
- edfenqueue(&qadmit, t);
+ edfresched(t);
}
}
}
@@ 356,13 357,13 @@ edf_admit(Task *t)
}
void
-edf_expel(Task *t)
+edfexpel(Task *t)
{
Task *tt;
qlock(&edfschedlock);
ilock(&edflock);
- DPRINT("%d edf_expel, %s, %d\n", m->machno, edf_statename[t->state], t->runq.n);
+ DPRINT("%d edfexpel, %s, %d\n", m->machno, edfstatename[t->state], t->runq.n);
now = fastticks(nil);
switch(t->state){
case EdfUnused:
@@ 412,9 413,8 @@ edfreleaseintr(Ureg*, Timer*)
DPRINT("%d edfreleaseintr\n", m->machno);
- timerdel(&cycrelease);
- cycrelease.when = 0;
- clockintrsched();
+ timerdel(&releasetimer[m->machno]);
+ releasetimer[m->machno].when = 0;
if(active.exiting)
return;
@@ 425,7 425,7 @@ edfreleaseintr(Ureg*, Timer*)
/* There's something waiting to be released and its time has come */
edfdequeue(&qwaitrelease);
edfreleasetimer();
- edf_release(t);
+ edfrelease(t);
}
iunlock(&edflock);
sched();
@@ 442,9 442,8 @@ edfdeadlineintr(Ureg*, Timer*)
DPRINT("%d edfdeadlineintr\n", m->machno);
- timerdel(&cycdeadline);
- cycdeadline.when = 0;
- clockintrsched();
+ timerdel(&deadlinetimer[m->machno]);
+ deadlinetimer[m->machno].when = 0;
if(active.exiting)
return;
@@ 469,11 468,11 @@ edfdeadlineintr(Ureg*, Timer*)
if (t->d <= now || t->S == 0LL){
/* Task has reached its deadline/slice, remove from queue */
- edfdeadline(up, SSlice);
+ deadline(up, SSlice);
while (t = edfstack[m->machno].head){
if (now < t->d)
break;
- edfdeadline(nil, SSlice);
+ deadline(nil, SSlice);
}
}
}
@@ 484,12 483,12 @@ edfdeadlineintr(Ureg*, Timer*)
}
void
-edf_bury(Proc *p)
+edfbury(Proc *p)
{
Task *t;
Proc **pp;
- DPRINT("%d edf_bury\n", m->machno);
+ DPRINT("%d edfbury\n", m->machno);
ilock(&edflock);
now = fastticks(nil);
if ((t = p->task) == nil){
@@ 518,12 517,12 @@ edf_bury(Proc *p)
}
void
-edf_ready(Proc *p)
+edfready(Proc *p)
{
Task *t;
ilock(&edflock);
- DPRINT("%d edf_ready, %s, %d\n", m->machno, edf_statename[p->task->state], p->task->runq.n);
+ DPRINT("%d edfready, %s, %d\n", m->machno, edfstatename[p->task->state], p->task->runq.n);
if ((t = p->task) == nil){
/* Must be a race */
iunlock(&edflock);
@@ 543,17 542,17 @@ edf_ready(Proc *p)
/* first proc to become runnable in this task */
now = fastticks(nil);
- edf_resched(t);
+ edfresched(t);
}
iunlock(&edflock);
}
static void
-edf_resched(Task *t)
+edfresched(Task *t)
{
Task *xt;
- DPRINT("%d edf_resched, %s, %d\n", m->machno, edf_statename[t->state], t->runq.n);
+ DPRINT("%d edfresched, %s, %d\n", m->machno, edfstatename[t->state], t->runq.n);
if (t->nproc == 0){
/* No member processes */
if (t->state > EdfIdle){
@@ 564,7 563,7 @@ edf_resched(Task *t)
}
if (t->runq.n == 0 && (up == nil || up->task != t)){
/* Member processes but none runnable */
- DPRINT("%d edf_resched, nothing runnable\n", m->machno);
+ DPRINT("%d edfresched, nothing runnable\n", m->machno);
if (t->state == EdfRunning)
edfpop();
@@ 589,7 588,7 @@ edf_resched(Task *t)
t->t = now + t->T;
t->r = t->t;
}
- edf_release(t);
+ edfrelease(t);
break;
case EdfAwaitrelease:
case EdfReleased:
@@ 606,17 605,17 @@ edf_resched(Task *t)
case EdfRunning:
if (t->r <= now){
if (t->t < now){
- DPRINT("%d edf_resched, rerelease\n", m->machno);
+ DPRINT("%d edfresched, rerelease\n", m->machno);
/* Period passed, rerelease */
t->r = now;
xt = edfpop();
assert(xt == t);
- edf_release(t);
+ edfrelease(t);
return;
}
if (now < t->d){
if (t->S > 0){
- DPRINT("%d edf_resched, resume\n", m->machno);
+ DPRINT("%d edfresched, resume\n", m->machno);
/* Running, not yet at deadline, leave it */
return;
}else
@@ 635,15 634,15 @@ edf_resched(Task *t)
case EdfDeadline:
if (t->r <= now){
if (t->t < now){
- DPRINT("%d edf_resched, rerelease\n", m->machno);
+ DPRINT("%d edfresched, rerelease\n", m->machno);
/* Period passed, rerelease */
t->r = now;
- edf_release(t);
+ edfrelease(t);
return;
}
if (now < t->d && (t->flags & Useblocking) == 0){
if (t->S > 0){
- DPRINT("%d edf_resched, resume\n", m->machno);
+ DPRINT("%d edfresched, resume\n", m->machno);
/* Released, not yet at deadline, release (again) */
t->state = EdfReleased;
edfenqueue(&qreleased, t);
@@ 663,9 662,9 @@ edf_resched(Task *t)
}
void
-edf_release(Task *t)
+edfrelease(Task *t)
{
- DPRINT("%d edf_release, %s, %d\n", m->machno, edf_statename[t->state], t->runq.n);
+ DPRINT("%d edfrelease, %s, %d\n", m->machno, edfstatename[t->state], t->runq.n);
assert(t->runq.n > 0 || (up && up->task == t));
t->t = t->r + t->T;
t->d = t->r + t->D;
@@ 677,14 676,15 @@ edf_release(Task *t)
}
Proc *
-edf_runproc(void)
+edfrunproc(void)
{
/* Return an edf proc to run or nil */
- Task *t, *nt;
+ Task *t, *nt, *xt;
Proc *p;
Ticks when;
static ulong nilcount;
+ int i;
/* Figure out if the current proc should be preempted*/
ilock(&edflock);
@@ 701,10 701,25 @@ edf_runproc(void)
iunlock(&edflock);
return nil;
}
- DPRINT("edf_runproc %lud\n", nilcount);
+ DPRINT("edfrunproc %lud\n", nilcount);
if (nt && (t == nil || (nt->d < t->d && nt->D < t->Delta))){
+ if (conf.nmach > 1){
+ for (i = 0; i < conf.nmach; i++){
+ if (i == m->machno)
+ continue;
+ xt = edfstack[i].head;
+ if (xt && xt->Delta <= nt->D){
+ DPRINT("%d edfrunproc: interprocessor conflict, run current\n", m->machno);
+ if (t)
+ goto runt;
+ nilcount++;
+ iunlock(&edflock);
+ return nil;
+ }
+ }
+ }
/* released task is better than current */
- DPRINT("%d edf_runproc: released\n", m->machno);
+ DPRINT("%d edfrunproc: released\n", m->machno);
edfdequeue(&qreleased);
assert(nt->runq.n >= 1);
edfpush(nt);
@@ 712,9 727,9 @@ edf_runproc(void)
t = nt;
t->scheduled = now;
}else{
- DPRINT("%d edf_runproc: current\n", m->machno);
+ DPRINT("%d edfrunproc: current\n", m->machno);
}
-
+runt:
assert (t->runq.n);
/* Get first proc off t's run queue
@@ 735,19 750,18 @@ edf_runproc(void)
when = t->d;
if (when < now){
- DPRINT("%d edf_timer: %T too late\n", m->machno, ticks2time(now-when));
+ DPRINT("%d edftimer: %T too late\n", m->machno, ticks2time(now-when));
when = now;
}
- if (cycdeadline.when){
- if(cycdeadline.when == when){
+ if (deadlinetimer[m->machno].when){
+ if(deadlinetimer[m->machno].when == when){
iunlock(&edflock);
return p;
}
- timerdel(&cycdeadline);
+ timerdel(&deadlinetimer[m->machno]);
}
- cycdeadline.when = when;
- timeradd(&cycdeadline);
- clockintrsched();
+ deadlinetimer[m->machno].when = when;
+ timeradd(&deadlinetimer[m->machno]);
iunlock(&edflock);
return p;
}
@@ 845,7 859,7 @@ testenq(Task *t)
}
static char *
-edf_testschedulability(Task *thetask)
+edftestschedulability(Task *thetask)
{
Task *t;
Ticks H, G, Cb, ticks;
M port/edf.h => port/edf.h +2 -20
@@ 97,30 97,12 @@ extern Taskq qwaitrelease;
extern Taskq qreleased;
extern Taskq qextratime;
extern Taskq edfstack[];
-extern int edf_stateupdate;
+extern int edfstateupdate;
extern void (*devrt)(Task *, Ticks, int);
-extern char * edf_statename[];
+extern char * edfstatename[];
#pragma varargck type "T" Time
#pragma varargck type "U" Ticks
-/* Interface: */
-void edf_preempt(Task*); /* Stop current task, administrate run time, leave on stack */
-void edf_deadline(Proc*); /* Remove current task from edfstack, schedule its next release */
-void edf_release(Task*); /* Release a task */
-void edf_schedule(Task *); /* Run a released task: remove from qrelease, push onto edfstack */
-char * edf_admit(Task*);
-void edf_expel(Task*);
-void edf_bury(Proc*); /* Proc dies, update Task membership */
-void edf_sched(Task*); /* Figure out what to do with task (after a state change) */
-int isedf(Proc*); /* Proc must be edf scheduled */
-void edf_stop(Proc*); /* Just event generation; should probably be done differently */
-int edf_anyready(void);
-void edf_ready(Proc*);
-Proc * edf_runproc(void);
-void edf_block(Proc*); /* Edf proc has blocked, do the admin */
-void edf_init(void);
-int edf_waitlock(Lock*);
-void edf_releaselock(Lock*);
Time ticks2time(Ticks);
Ticks time2ticks(Time);
A port/nulledf.c => port/nulledf.c +41 -0
@@ 0,0 1,41 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "../port/error.h"
+#include "../port/edf.h"
+
+int
+isedf(Proc*)
+{
+ return 0;
+}
+
+void
+edf_bury(Proc*)
+{
+}
+
+int
+edf_anyready(void)
+{
+ return 0;
+}
+
+void
+edf_ready(Proc*)
+{
+}
+
+Proc*
+edf_runproc(void)
+{
+ return nil;
+}
+
+void
+edf_block(Proc*)
+{
+}
+
M port/portclock.c => port/portclock.c +164 -31
@@ 5,40 5,93 @@
#include "fns.h"
#include "io.h"
#include "ureg.h"
-#include "../port/edf.h"
-void (*kproftimer)(ulong);
+typedef struct Timers Timers;
-typedef struct Clock0link Clock0link;
-typedef struct Clock0link {
- void (*clock)(void);
- Clock0link* link;
-} Clock0link;
+struct Timers
+{
+ Lock;
+ Timer *head;
+};
-static Clock0link *clock0link;
-static Lock clock0lock;
+static Timers timers[MAXMACH];
-void
-addclock0link(void (*clock)(void))
+ulong intrcount[MAXMACH];
+ulong fcallcount[MAXMACH];
+
+static uvlong
+tadd(Timers *tt, Timer *nt)
{
- Clock0link *lp;
+ Timer *t, **last, *pt;
+
+ pt = nil;
+ for(last = &tt->head; t = *last; last = &t->next){
+ if(t == nt){
+ *last = t->next;
+ break;
+ }
+ if (t->period == nt->period)
+ pt = t;
+ }
- if((lp = malloc(sizeof(Clock0link))) == 0){
- print("addclock0link: too many links\n");
- return;
+ if(nt->when == 0){
+ /* Try to synchronize periods to reduce # of interrupts */
+ assert(nt->period);
+ if(pt)
+ nt->when = pt->when;
+ else
+ nt->when = (uvlong)fastticks(nil) + nt->period;
}
- ilock(&clock0lock);
- lp->clock = clock;
- lp->link = clock0link;
- clock0link = lp;
- iunlock(&clock0lock);
+
+ for(last = &tt->head; t = *last; last = &t->next){
+ if(t->when > nt->when)
+ break;
+ }
+ nt->next = *last;
+ *last = nt;
+ if (last == &tt->head)
+ return nt->when;
+ else
+ return 0;
}
+/* add of modify a timer */
void
-portclock(Ureg *ur)
+timeradd(Timer *nt)
{
- Clock0link *lp;
+ Timers *tt;
+ uvlong when;
+
+ tt = &timers[m->machno];
+ ilock(tt);
+ when = tadd(tt, nt);
+ if (when)
+ timerset(when);
+ iunlock(tt);
+}
+void
+timerdel(Timer *dt)
+{
+ Timer *t, **last;
+ Timers *tt;
+
+ tt = &timers[m->machno];
+ ilock(tt);
+ for(last = &tt->head; t = *last; last = &t->next){
+ if(t == dt){
+ *last = t->next;
+ break;
+ }
+ }
+ if (last == &tt->head && tt->head)
+ timerset(tt->head->when);
+ iunlock(tt);
+}
+
+void
+hzclock(Ureg *ur)
+{
m->ticks++;
if(m->proc)
m->proc->pc = ur->pc;
@@ 47,6 100,12 @@ portclock(Ureg *ur)
return; /* interrupted ourself */
m->inclockintr = 1;
+ if(m->flushmmu){
+ if(up)
+ flushmmu();
+ m->flushmmu = 0;
+ }
+
accounttime();
kmapinval();
@@ 62,14 121,6 @@ portclock(Ureg *ur)
}
checkalarms();
- if(m->machno == 0){
- if(canlock(&clock0lock))
- for(lp = clock0link; lp; lp = lp->link){
- lp->clock();
- splhi();
- }
- unlock(&clock0lock);
- }
m->inclockintr = 0;
@@ 77,7 128,7 @@ portclock(Ureg *ur)
return;
// i.e. don't schedule an EDF process here!
- if(!isedf(up) && anyready()){
+ if(anyready() && !isedf(up)){
sched();
splhi();
}
@@ 88,3 139,85 @@ portclock(Ureg *ur)
segclock(ur->pc);
}
}
+
+void
+timerintr(Ureg *u, uvlong)
+{
+ Timer *t;
+ Timers *tt;
+ uvlong when, now;
+ int callhzclock;
+
+ intrcount[m->machno]++;
+ callhzclock = 0;
+ tt = &timers[m->machno];
+ now = (uvlong)fastticks(nil);
+ ilock(tt);
+ while(t = tt->head){
+ when = t->when;
+ if(when > now){
+ iunlock(tt);
+ timerset(when);
+ if(callhzclock)
+ hzclock(u);
+ return;
+ }
+ tt->head = t->next;
+ fcallcount[m->machno]++;
+ iunlock(tt);
+ if (t->f){
+ (*t->f)(u, t);
+ splhi();
+ } else
+ callhzclock++;
+ ilock(tt);
+ if(t->period){
+ t->when += t->period;
+ if (t->when <= now)
+ t->when = now + t->period;
+ tadd(tt, t);
+ }
+ }
+ iunlock(tt);
+}
+
+uvlong hzperiod;
+
+void
+timersinit(void)
+{
+ Timer *t;
+
+ hzperiod = ms2fastticks(1000/HZ);
+
+ t = smalloc(sizeof(*t));
+ t->period = hzperiod;
+ t->f = nil;
+ timeradd(t);
+}
+
+void
+addclock0link(void (*f)(void))
+{
+ Timer *nt;
+
+ /* Synchronize this to hztimer: reduces # of interrupts */
+ nt = malloc(sizeof(Timer));
+ nt->when = 0;
+ if (hzperiod == 0)
+ hzperiod = ms2fastticks(1000/HZ);
+ nt->period = hzperiod;
+ nt->f = (void (*)(Ureg*, Timer*))f;
+
+ ilock(&timers[0]);
+ tadd(&timers[0], nt);
+ /* no need to restart timer:
+ * this one's synchronized with hztimer which is already running
+ */
+ iunlock(&timers[0]);
+}
+
+void
+clockintrsched(void)
+{
+}
M port/portdat.h => port/portdat.h +13 -0
@@ 42,6 42,7 @@ typedef struct Segment Segment;
typedef struct Session Session;
typedef struct Task Task;
typedef struct Talarm Talarm;
+typedef struct Timer Timer;
typedef struct Uart Uart;
typedef struct Waitq Waitq;
typedef struct Walkqid Walkqid;
@@ 827,6 828,18 @@ struct Uart
Rendez r;
};
+/*
+ * fasttick timer interrupts (Dummy for now)
+ */
+struct Timer
+{
+ uvlong when; /* fastticks when f should be called */
+ void (*f)(Ureg*, Timer*);
+ void *a;
+ Timer *next;
+ ulong period;
+};
+
#define DEVDOTDOT -1
#pragma varargck argpos print 1
M port/portfns.h => port/portfns.h +21 -2
@@ 7,7 7,7 @@ void alarmkproc(void*);
Block* allocb(int);
int anyhigher(void);
int anyready(void);
-#define assert(x) if(x){}else panic("assert(x) failed")
+#define assert(x) if(x){}else _assert("assert(x) failed")
void _assert(char*);
Image* attachimage(int, Chan*, ulong, ulong);
Page* auxpage(void);
@@ 87,6 87,17 @@ void dumpstack(void);
Fgrp* dupfgrp(Fgrp*);
void duppage(Page*);
void dupswap(Page*);
+void edfdeadline(Proc*);
+void edfrelease(Task*);
+char* edfadmit(Task*);
+void edfexpel(Task*);
+void edfbury(Proc*);
+void edfsched(Task*);
+int edfanyready(void);
+void edfready(Proc*);
+Proc* edfrunproc(void);
+void edfblock(Proc*);
+void edfinit(void);
int emptystr(char*);
int encrypt(void*, void*, int);
void envcpy(Egrp*, Egrp*);
@@ 96,7 107,7 @@ void error(char*);
long execregs(ulong, ulong, ulong);
void exhausted(char*);
void exit(int);
-vlong fastticks(uvlong*);
+uvlong fastticks(uvlong*);
int fault(ulong, int);
void fdclose(int, int);
Chan* fdtochan(int, int, int, int);
@@ 129,6 140,7 @@ int incref(Ref*);
void initseg(void);
int iprint(char*, ...);
void isdir(Chan*);
+int isedf(Proc*);
int iseve(void);
int islo(void);
Segment* isoverlap(Proc*, ulong, int);
@@ 175,6 187,8 @@ long mntversion(Chan*, char*, int, int);
void mountfree(Mount*);
ulong ms2tk(ulong);
ulong msize(void*);
+ulong ms2tk(ulong);
+uvlong ms2fastticks(ulong);
void muxclose(Mnt*);
Chan* namec(char*, int, int, ulong);
#define nelem(x) (sizeof(x)/sizeof(x[0]))
@@ 313,6 327,11 @@ char* srvname(Chan*);
int swapcount(ulong);
int swapfull(void);
void swapinit(void);
+void timeradd(Timer*);
+void timerdel(Timer*);
+void timersinit(void);
+void timerintr(Ureg*, uvlong);
+void timerset(uvlong);
vlong todget(vlong*);
void todfix(void);
void todsetfreq(vlong);
M port/proc.c => port/proc.c +8 -43
@@ 4,7 4,6 @@
#include "dat.h"
#include "fns.h"
#include "../port/error.h"
-#include "../port/edf.h"
int nrdy;
Ref noteidalloc;
@@ 43,37 42,6 @@ char *statename[] =
static void pidhash(Proc*);
static void pidunhash(Proc*);
-/*DEBUGGING: scheduling event log */
-#ifdef RSC
-static ulong *lg;
-enum {Nlg = 1024*1024};
-static ulong wp, rp;
-static void
-le(int c, Proc *p)
-{
- if(lg==nil)
- lg = malloc(Nlg*sizeof(lg[0]));
- lg[wp++&(Nlg-1)] = MACHP(0)->ticks;
- lg[wp++&(Nlg-1)] = c;
- lg[wp++&(Nlg-1)] = (ulong)p;
-}
-void
-dumpschedlog(void)
-{
- int i;
-
- i=0;
- iprint("%lux=>%lux\n", rp, wp);
- while((rp&(Nlg-1))!=(wp&(Nlg-1))){
- iprint("%lux ", lg[rp++&(Nlg-1)]);
- if(++i%8==0)
- iprint("\n");
- }
- if(i%8)
- iprint("\n");
-}
-#endif
-
/*
* Always splhi()'ed.
*/
@@ 90,7 58,7 @@ schedinit(void) /* never returns */
case Moribund:
up->state = Dead;
if (isedf(up))
- edf_bury(up);
+ edfbury(up);
/*
* Holding locks from pexit:
@@ 150,7 118,7 @@ sched(void)
int
anyready(void)
{
- return nrdy || edf_anyready();
+ return nrdy || edfanyready();
}
int
@@ 180,12 148,9 @@ ready(Proc *p)
Schedq *rq;
s = splhi();
-#ifdef RSC
-le('r',p);
-#endif
if(isedf(p)){
- edf_ready(p);
+ edfready(p);
splx(s);
return;
}
@@ 239,7 204,7 @@ runproc(void)
Proc *p, *l;
ulong rt;
- if ((p = edf_runproc()) != nil)
+ if ((p = edfrunproc()) != nil)
return p;
loop:
@@ 533,7 498,7 @@ sleep(Rendez *r, int (*f)(void*), void *arg)
// Behind unlock, we may call wakeup on ourselves.
if (isedf(up))
- edf_block(up);
+ edfblock(up);
gotolabel(&m->sched);
}
@@ 743,7 708,7 @@ addbroken(Proc *p)
qunlock(&broken);
if (isedf(up))
- edf_bury(up);
+ edfbury(up);
p->state = Broken;
p->psstate = 0;
sched();
@@ 912,7 877,7 @@ pexit(char *exitstr, int freemem)
lock(&palloc);
if (isedf(up))
- edf_bury(up);
+ edfbury(up);
up->state = Moribund;
sched();
panic("pexit");
@@ 1166,7 1131,7 @@ procctl(Proc *p)
splhi();
p->state = Stopped;
if (isedf(up))
- edf_block(up);
+ edfblock(up);
sched();
p->psstate = state;
splx(s);
M port/qlock.c => port/qlock.c +3 -4
@@ 3,7 3,6 @@
#include "mem.h"
#include "dat.h"
#include "fns.h"
-#include "../port/edf.h"
struct {
ulong rlock;
@@ 41,7 40,7 @@ qlock(QLock *q)
up->qpc = getcallerpc(&q);
unlock(&q->use);
if (isedf(mp))
- edf_block(mp);
+ edfblock(mp);
sched();
}
@@ 106,7 105,7 @@ rlock(RWlock *q)
mp->state = QueueingR;
unlock(&q->use);
if (isedf(mp))
- edf_block(mp);
+ edfblock(mp);
sched();
}
@@ 164,7 163,7 @@ wlock(RWlock *q)
mp->state = QueueingW;
unlock(&q->use);
if (isedf(mp))
- edf_block(mp);
+ edfblock(mp);
sched();
}
M port/sysproc.c => port/sysproc.c +1 -2
@@ 4,7 4,6 @@
#include "dat.h"
#include "fns.h"
#include "../port/error.h"
-#include "../port/edf.h"
#include <a.out.h>
@@ 827,7 826,7 @@ sysrendezvous(ulong *arg)
up->state = Rendezvous;
unlock(up->rgrp);
if (isedf(up))
- edf_block(up);
+ edfblock(up);
sched();
M port/tod.c => port/tod.c +14 -1
@@ 28,7 28,7 @@
// frequency of the tod clock
-#define TODFREQ 1000000000LL
+#define TODFREQ 1000000000ULL
struct {
ulong cnt;
@@ 61,7 61,10 @@ todsetfreq(vlong f)
{
ilock(&tod);
tod.hz = f;
+
+ /* calculate multiplier for time conversion */
tod.multiplier = (TODFREQ<<31)/f;
+
iunlock(&tod);
}
@@ 180,3 183,13 @@ seconds(void)
i = x;
return i;
}
+
+// convert milliseconds to fast ticks
+//
+uvlong
+ms2fastticks(ulong ms)
+{
+ if(tod.hz == 0)
+ fastticks((uvlong*)&tod.hz);
+ return (tod.hz*ms)/1000ULL;
+}