code: plan9front

Download patch

ref: 6fb883b02c6fca762dcbe31450c868e4b854952c
parent: 6abe569ec8f47ba14c3dcd5d5214e7b7a020bf7a
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun Sep 25 10:48:42 EDT 2022

9/port: revert timer wheel change, breaks pi4 boot, needs more time investigating

--- a/sys/src/9/port/alarm.c
+++ b/sys/src/9/port/alarm.c
@@ -3,91 +3,109 @@
 #include	"mem.h"
 #include	"dat.h"
 #include	"fns.h"
-#include	"error.h"
 
-static Proc	*tripped;
+static Alarms	alarms;
 static Rendez	alarmr;
-static Lock	triplk;
 
-static int
-tfn(void *)
-{
-	int t;
-
-	ilock(&triplk);
-	t = (tripped != nil);
-	iunlock(&triplk);
-	return t;
-}
-
-/*
- *  called every clock tick on cpu0
- */
-static void
-tripalarm(Ureg*, Timer *t)
-{
-	ilock(&triplk);
-	t->p->palarm = tripped;
-	tripped = t->p;
-	iunlock(&triplk);
-
-	wakeup(&alarmr);
-}
-
 void
 alarmkproc(void*)
 {
-	static Note alarmnote = {
-		"alarm",
-		NUser,
-		1,
-	};
-	Proc *p, *n;
-	Timer *a;
+	Proc *rp;
+	ulong now, when;
 
 	while(waserror())
 		;
 
-	while(1){
-		ilock(&triplk);
-		p = tripped;
-		tripped = nil;
-		iunlock(&triplk);
-
-		for(; p != nil; p = n){
-			n = p->palarm;
-			a = &p->alarm;
-			if(!canqlock(&p->debug)){
-				a->tns = MS2NS(10);
-				timeradd(a);
+	for(;;){
+		now = MACHP(0)->ticks;
+		qlock(&alarms);
+		for(rp = alarms.head; rp != nil; rp = rp->palarm){
+			if((when = rp->alarm) == 0)
 				continue;
+			if((long)(now - when) < 0)
+				break;
+			if(!canqlock(&rp->debug))
+				break;
+			if(rp->alarm != 0){
+				static Note alarm = {
+					"alarm",
+					NUser,
+					1,
+				};
+				incref(&alarm);
+				pushnote(rp, &alarm);
+				rp->alarm = 0;
 			}
-			incref(&alarmnote);
-			pushnote(p, &alarmnote);
-			qunlock(&p->debug);
+			qunlock(&rp->debug);
 		}
-		sleep(&alarmr, tfn, nil);
+		alarms.head = rp;
+		qunlock(&alarms);
+
+		sleep(&alarmr, return0, 0);
 	}
 }
 
+/*
+ *  called every clock tick on cpu0
+ */
+void
+checkalarms(void)
+{
+	Proc *p;
+	ulong now, when;
+
+	p = alarms.head;
+	if(p != nil){
+		now = MACHP(0)->ticks;
+		when = p->alarm;
+		if(when == 0 || (long)(now - when) >= 0)
+			wakeup(&alarmr);
+	}
+}
+
 ulong
 procalarm(ulong time)
 {
-	uvlong old;
-	Timer *a;
+	Proc **l, *f;
+	ulong when, old;
 
-	a = &up->alarm;
-	old = a->tns;
-	timerdel(a);
+	when = MACHP(0)->ticks;
+	old = up->alarm;
+	if(old) {
+		old -= when;
+		if((long)old > 0)
+			old = tk2ms(old);
+		else
+			old = 0;
+	}
+	if(time == 0) {
+		up->alarm = 0;
+		return old;
+	}
+	when += ms2tk(time);
+	if(when == 0)
+		when = 1;
 
-	lock(a);
-	a->tns = MS2NS(time);
-	a->tf = tripalarm;
-	a->tmode = Trelative;
-	a->p = up;
-	a->ta = nil;
-	unlock(a);
-	if(time != 0)
-		timeradd(a);
-	return NS2MS(old);
+	qlock(&alarms);
+	l = &alarms.head;
+	for(f = *l; f; f = f->palarm) {
+		if(up == f){
+			*l = f->palarm;
+			break;
+		}
+		l = &f->palarm;
+	}
+	l = &alarms.head;
+	for(f = *l; f; f = f->palarm) {
+		time = f->alarm;
+		if(time != 0 && (long)(time - when) >= 0)
+			break;
+		l = &f->palarm;
+	}
+	up->palarm = f;
+	*l = up;
+	up->alarm = when;
+	qunlock(&alarms);
+
+	return old;
 }
--- a/sys/src/9/port/portclock.c
+++ b/sys/src/9/port/portclock.c
@@ -7,27 +7,10 @@
 #include "ureg.h"
 #include "tos.h"
 
-typedef struct Timers Timers;
-typedef struct Wheel Wheel;
-
-enum {
-	WSHIFT	= 5,
-	NWHEEL	= 6,
-	NSLOT	= 1<<WSHIFT,
-	SMASK	= NSLOT-1,
-	TMAX	= 1<<(WSHIFT*(NWHEEL-1)),
-};
-
-struct Wheel {
-	Timer	*slots[NSLOT];
-	int	idx;
-};
-	
-struct Timers {
+struct Timers
+{
 	Lock;
-	uvlong	tnow;
-	uvlong	tsched;
-	Wheel	wheels[NWHEEL];
+	Timer	*head;
 };
 
 static Timers timers[MAXMACH];
@@ -35,102 +18,13 @@
 ulong intrcount[MAXMACH];
 ulong fcallcount[MAXMACH];
 
-#define slot(tt, i, j)	((tt)->wheels[(i)].slots[(j) & SMASK])
-#define slotp(tt, i, j)	(&(tt)->wheels[(i)].slots[(j) & SMASK])
-
-static void
-tins(Timers *tt, Timer *t)
-{
-	Timer *n, **p;
-	uvlong dt;
-	int i;
-
-	dt = t->twhen - tt->tnow;
-	assert((vlong)dt >= 0);
-	for(i = 0; dt >= NSLOT && i < NWHEEL-1; i++)
-		dt = (dt + tt->wheels[i].idx) >> WSHIFT;
-	dt = (dt + tt->wheels[i].idx) & SMASK;
-
-	p = &tt->wheels[i].slots[dt];
-	n = *p;
-	t->tt = tt;
-	t->tnext = n;
-	t->tlink = p;
-	if(n != nil)
-		n->tlink = &t->tnext;
-	*p = t;
-}
-
-static void
-tdel(Timer *dt)
-{
-	if(dt->tt == nil)
-		return;
-	if(dt->tnext != nil)
-		dt->tnext->tlink = dt->tlink;
-	*dt->tlink = dt->tnext;
-	dt->tlink = nil;
-	dt->tnext = nil;
-	dt->tt = nil;
-}
-
-/* look for another timer at same frequency for combining */
-static uvlong
-tcombine(Timers *tt, Timer *nt, uvlong now)
-{
-	int i, j, s;
-	Timer *t;
-
-	for(i = 0; i < NWHEEL; i++){
-		s = tt->wheels[i].idx;
-		for(j = s; j < s+NSLOT; j++)
-			for(t = slot(tt, i, j); t != nil && t->tns < nt->tns; t = t->tnext)
-				if(t->tmode == Tperiodic && t->twhen > now  && t->tns == nt->tns)
-					return t->twhen;
-	}
-	return fastticks(nil);
-}
-
-/* approximate time of the next timer to schedule, or 0 if there's already one scheduled */
-static uvlong
-tnext(Timers *tt, uvlong when)
-{
-	uvlong tk, dt;
-	int i, j, s;
-	Wheel *w;
-
-	if(when > tt->tsched)
-		return 0;
-
-	dt = 1;
-	for(i = 0; i < NWHEEL; i++){
-		w = &tt->wheels[i];
-		s = w->idx+1;
-		tk = tt->tnow;
-		/* the current slot should always already be processed, and thus empty */
-		assert(slot(tt, i, w->idx) == nil);
-		for(j = s; j < s+NSLOT-1; j++){
-			tk += dt;
-			if(tk >= when || slot(tt, i, j) != nil)
-				break;
-		}
-		if(tk < when)
-			when = tk;
-		dt <<= WSHIFT;
-	}
-	tt->tsched = when;
-	return when;
-
-}
-
-/* Called with tt locked */
-static void
+static vlong
 tadd(Timers *tt, Timer *nt)
 {
+	Timer *t, **last;
+
+	/* Called with tt locked */
 	assert(nt->tt == nil);
-	nt->tt = tt;
-	nt->tnext = nil;
-	nt->tlink = nil;
 	switch(nt->tmode){
 	default:
 		panic("timer");
@@ -142,27 +36,66 @@
 		break;
 	case Tperiodic:
 		assert(nt->tns >= 100000);	/* At least 100 µs period */
-		if(0 && nt->twhen == 0)
-			nt->twhen = tcombine(tt, nt, tt->tnow);
-		else
-			nt->twhen = fastticks(nil);
+		if(nt->twhen == 0){
+			/* look for another timer at same frequency for combining */
+			for(t = tt->head; t; t = t->tnext){
+				if(t->tmode == Tperiodic && t->tns == nt->tns)
+					break;
+			}
+			if (t)
+				nt->twhen = t->twhen;
+			else
+				nt->twhen = fastticks(nil);
+		}
 		nt->twhen += ns2fastticks(nt->tns);
 		break;
 	}
-	tins(tt, nt);
+
+	for(last = &tt->head; t = *last; last = &t->tnext){
+		if(t->twhen > nt->twhen)
+			break;
+	}
+	nt->tnext = *last;
+	*last = nt;
+	nt->tt = tt;
+	if(last == &tt->head)
+		return nt->twhen;
+	return 0;
 }
 
+static uvlong
+tdel(Timer *dt)
+{
+
+	Timer *t, **last;
+	Timers *tt;
+
+	tt = dt->tt;
+	if (tt == nil)
+		return 0;
+	for(last = &tt->head; t = *last; last = &t->tnext){
+		if(t == dt){
+			assert(dt->tt);
+			dt->tt = nil;
+			*last = t->tnext;
+			break;
+		}
+	}
+	if(last == &tt->head && tt->head)
+		return tt->head->twhen;
+	return 0;
+}
+
 /* add or modify a timer */
 void
 timeradd(Timer *nt)
 {
 	Timers *tt;
-	uvlong when;
+	vlong when;
 
 	/* Must lock Timer struct before Timers struct */
 	ilock(nt);
-	tt = nt->tt;
-	if(tt != nil){
+	if(tt = nt->tt){
 		ilock(tt);
 		tdel(nt);
 		iunlock(tt);
@@ -169,8 +102,7 @@
 	}
 	tt = &timers[m->machno];
 	ilock(tt);
-	tadd(tt, nt);
-	when = tnext(tt, nt->twhen);
+	when = tadd(tt, nt);
 	if(when)
 		timerset(when);
 	iunlock(tt);
@@ -191,10 +123,9 @@
 	ilock(dt);
 	if(tt = dt->tt){
 		ilock(tt);
-		tdel(dt);
-		when = tnext(tt, dt->twhen);
+		when = tdel(dt);
 		if(when && tt == &timers[m->machno])
-			timerset(when);
+			timerset(tt->head->twhen);
 		iunlock(tt);
 	}
 	if((mp = dt->tactive) == nil || mp->machno == m->machno){
@@ -202,6 +133,7 @@
 		return;
 	}
 	iunlock(dt);
+
 	/* rare, but tf can still be active on another cpu */
 	while(dt->tactive == mp && dt->tt == nil)
 		if(up->nlocks == 0 && islo())
@@ -234,6 +166,9 @@
 	if(active.exiting)
 		exit(0);
 
+	if(m->machno == 0)
+		checkalarms();
+
 	if(up && up->state == Running){
 		if(userureg(ur)){
 			/* user profiling clock */
@@ -249,77 +184,47 @@
 void
 timerintr(Ureg *u, Tval)
 {
-	uvlong dt, when, now;
-	int i, j, s, hz;
-	Timer *t, *n;
+	Timer *t;
 	Timers *tt;
-	Wheel *w;
+	uvlong when, now;
+	int callhzclock;
 
 	intrcount[m->machno]++;
+	callhzclock = 0;
 	tt = &timers[m->machno];
 	now = fastticks(nil);
-
 	ilock(tt);
-	hz = 0;
-	dt = now - tt->tnow;
-	tt->tnow = now;
-	/*
-	 * We need to look at all the wheels.
-	 */
-	for(i = 0; i < NWHEEL; i++){
-		w = &tt->wheels[i];
-		s = w->idx;
-		w->idx = (s+dt)&SMASK;
-		for(j = s; j <= s+dt && j < s+NSLOT; j++){
-			for(t = slot(tt, i, j); t != nil; t = n){
-				assert(t->tt == tt);
-				n = t->tnext;
-				/*
-				 * The last wheel can contain timers that are
-				 * expiring both before and after now.
-				 * Cascade the future ones, and expire the current
-				 * ones.
-				 */
-				if(t->twhen > now+TMAX)
-					continue;
-				/*
-				 * Otherwise, we cascade this timer into a new slot
-				 * in a closer wheel.
-				 */
-				tdel(t);
-				if(t->twhen > now){
-					tins(tt, t);
-					continue;
-				}
-				/*
-				 * No need to ilock t here: any manipulation of t
-				 * requires tdel(t) and this must be done with a
-				 * lock to tt held.  We have tt, so the tdel will
-				 * wait until we're done
-				 */
-				t->tactive = MACHP(m->machno);
-				fcallcount[m->machno]++;
-				iunlock(tt);
-				if(t->tf)
-					t->tf(u, t);
-				else
-					hz = 1;
-				t->tactive = nil;
-				ilock(tt);
-				if(t->tmode == Tperiodic)
-					tadd(tt, t);
-			}
+	while(t = tt->head){
+		/*
+		 * No need to ilock t here: any manipulation of t
+		 * requires tdel(t) and this must be done with a
+		 * lock to tt held.  We have tt, so the tdel will
+		 * wait until we're done
+		 */
+		when = t->twhen;
+		if(when > now){
+			timerset(when);
+			iunlock(tt);
+			if(callhzclock)
+				hzclock(u);
+			return;
 		}
-		dt += s;
-		dt >>= WSHIFT;
+		tt->head = t->tnext;
+		assert(t->tt == tt);
+		t->tt = nil;
+		t->tactive = MACHP(m->machno);
+		fcallcount[m->machno]++;
+		iunlock(tt);
+		if(t->tf)
+			(*t->tf)(u, t);
+		else
+			callhzclock++;
+		t->tactive = nil;
+		ilock(tt);
+		if(t->tmode == Tperiodic)
+			tadd(tt, t);
 	}
-	when = tnext(tt, ~0);
-
-	if(when != 0)
-		timerset(when);
 	iunlock(tt);
-	if(hz)
-		hzclock(u);
 }
 
 void
@@ -359,8 +264,7 @@
 	nt->tf = (void (*)(Ureg*, Timer*))f;
 
 	ilock(&timers[0]);
-	tadd(&timers[0], nt);
-	when = tnext(&timers[0], nt->twhen);
+	when = tadd(&timers[0], nt);
 	if(when)
 		timerset(when);
 	iunlock(&timers[0]);
--- a/sys/src/9/port/portdat.h
+++ b/sys/src/9/port/portdat.h
@@ -1,3 +1,4 @@
+typedef struct Alarms	Alarms;
 typedef struct Block	Block;
 typedef struct Chan	Chan;
 typedef struct Cmdbuf	Cmdbuf;
@@ -97,6 +98,12 @@
 	int	writer;		/* number of writers */
 };
 
+struct Alarms
+{
+	QLock;
+	Proc	*head;
+};
+
 struct Sargs
 {
 	uchar	args[MAXSYSARG*BY2WD];
@@ -568,7 +575,6 @@
 	Tval	tticks;		/* tns converted to ticks */
 	Tval	twhen;		/* ns represented in fastticks */
 	Timer	*tnext;
-	Timer	**tlink;	/* a pointer to the prev nodes's next */
 };
 
 enum
@@ -714,8 +720,8 @@
 	Rendez	sleep;		/* place for syssleep/debug */
 	int	notepending;	/* note issued but not acted on */
 	int	kp;		/* true if a kernel process */
-	Proc	*palarm;	/* triggered alarm chain */
-	Timer	alarm;		/* alarm context */
+	Proc	*palarm;	/* Next alarm time */
+	ulong	alarm;		/* Time of call */
 	int	newtlb;		/* Pager has changed my pte's, I must flush */
 
 	uintptr	rendtag;	/* Tag for rendezvous */
--- a/sys/src/9/port/portfns.h
+++ b/sys/src/9/port/portfns.h
@@ -26,6 +26,7 @@
 void		chandevreset(void);
 void		chandevshutdown(void);
 void		chanfree(Chan*);
+void		checkalarms(void);
 void		checkb(Block*, char*);
 void		cinit(void);
 Chan*		cclone(Chan*);
@@ -175,7 +176,6 @@
 Cmdtab*		lookupcmd(Cmdbuf*, Cmdtab*, int);
 Page*		lookpage(Image*, uintptr);
 #define		MS2NS(n) (((vlong)(n))*1000000LL)
-#define		NS2MS(n) (((vlong)(n)+500000LL)/100000LL)
 void		machinit(void);
 void*		mallocz(ulong, int);
 void*		malloc(ulong);
--- a/sys/src/9/port/proc.c
+++ b/sys/src/9/port/proc.c
@@ -1203,7 +1203,7 @@
 	void (*pt)(Proc*, int, vlong);
 
 	up->fpstate &= ~FPillegal;
-	procalarm(0);
+	up->alarm = 0;
 	timerdel(up);
 	pt = proctrace;
 	if(pt != nil)