~kris/9p

9hist

0ed7376734c237eeed1c7d91d094c06ebbd2a9cb — David du Colombier 24 years ago 1dfe5a5
Plan 9 from Bell Labs 2002-04-10
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;
}