code: 9ferno

Download patch

ref: 37775f47e6b73f64997fcc179e061d943c8721de
parent: 03be3a131ed2dcda25fed07258e5f39e5dda9fb2
author: 9ferno <gophone2015@gmail.com>
date: Thu Oct 14 15:33:46 EDT 2021

replaced taslock

--- a/os/port/portdat.h
+++ b/os/port/portdat.h
@@ -515,8 +515,14 @@
 	s32		nerrlab;
 	Label		errlab[NERR];
 	char	genbuf[128];	/* buffer used e.g. for last name element from namec */
+
+	Lock	*lockwait;
+	Lock	*lastlock;	/* debugging */
+	Lock	*lastilock;	/* debugging */
+
 	Mach*		mp;		/* machine this process last ran on */
 	Mach*		wired;
+	int	nlocks;		/* number of locks held by proc */
 	u32		movetime;	/* next time process should switch processors */
 	u32		delaysched;
 	s32			preempted;	/* process yielding in interrupt */
--- a/os/port/portfns.h
+++ b/os/port/portfns.h
@@ -76,6 +76,7 @@
 int		domount(Chan**, Mhead**);
 void		drawactive(int);
 void		drawcmap(void);
+void		dumpaproc(Proc*);
 void		dumpstack(void);
 Fgrp*		dupfgrp(Fgrp*);
 void		egrpcpy(Egrp*, Egrp*);
@@ -137,7 +138,7 @@
 void		kstrcpy(char*, char*, int);
 void		kstrdup(char**, char*);
 long		latin1(Rune*, int);
-void		lock(Lock*);
+int		lock(Lock*);
 void		logopen(Log*);
 void		logclose(Log*);
 char*		logctl(Log*, int, char**, Logflag*);
--- a/os/port/proc.c
+++ b/os/port/proc.c
@@ -505,12 +505,27 @@
 }
 
 void
+dumpaproc(Proc *p)
+{
+	char *s;
+	char tmp[14];
+
+	s = p->psstate;
+	if(s == nil)
+		s = "kproc";
+	if(p->state == Wakeme)
+		snprint(tmp, sizeof(tmp), " /%.8lux", p->r);
+	else
+		*tmp = '\0';
+	print("%p:%3ud:%14s pc %.8zux %s/%s qpc %.8zux pri %d%s\n",
+		p, p->pid, p->text, p->pc, s, statename[p->state], p->qpc, p->pri, tmp);
+}
+
+void
 procdump(void)
 {
 	int i;
-	char *s;
 	Proc *p;
-	char tmp[14];
 
 	for(i=0; i<conf.nproc; i++) {
 		p = &procalloc.arena[i];
@@ -517,15 +532,7 @@
 		if(p->state == Dead)
 			continue;
 
-		s = p->psstate;
-		if(s == nil)
-			s = "kproc";
-		if(p->state == Wakeme)
-			snprint(tmp, sizeof(tmp), " /%.8lux", p->r);
-		else
-			*tmp = '\0';
-		print("%p:%3ud:%14s pc %.8zux %s/%s qpc %.8zux pri %d%s\n",
-			p, p->pid, p->text, p->pc, s, statename[p->state], p->qpc, p->pri, tmp);
+		dumpaproc(p);
 	}
 }
 
--- a/os/port/taslock.c
+++ b/os/port/taslock.c
@@ -4,19 +4,53 @@
 #include "dat.h"
 #include "fns.h"
 #include "../port/error.h"
+#include "edf.h"
 
+long maxlockcycles;
+long maxilockcycles;
+long cumlockcycles;
+long cumilockcycles;
+uintptr maxlockpc;
+uintptr maxilockpc;
+
+struct
+{
+	ulong	locks;
+	ulong	glare;
+	ulong	inglare;
+} lockstats;
+
 static void
+dumplockmem(char *tag, Lock *l)
+{
+	uchar *cp;
+	int i;
+
+	iprint("%s: ", tag);
+	cp = (uchar*)l;
+	for(i = 0; i < 64; i++)
+		iprint("%2.2ux ", cp[i]);
+	iprint("\n");
+}
+
+void
 lockloop(Lock *l, uintptr pc)
 {
 	extern int panicking;
+	Proc *p;
 
 	if(panicking)
 		return;
-	panic("lock loop 0x%p key 0x%ux pc 0x%zux held by pc 0x%zux\n", l, l->key, pc, l->pc);
-	panic("lockloop");
+
+	p = l->p;
+	print("lock %#p loop key %#ux pc %#p held by pc %#p proc %ud\n",
+		l, l->key, pc, l->pc, p ? p->pid : 0);
+	dumpaproc(up);
+	if(p != nil)
+		dumpaproc(p);
 }
 
-void
+int
 lock(Lock *l)
 {
 	int i;
@@ -23,88 +57,124 @@
 	uintptr pc;
 
 	pc = getcallerpc(&l);
-	if(up == 0) {
-		if (_tas((int*)&l->key) != 0) {
-			for(i=0; ; i++) {
-				if(_tas((int*)&l->key) == 0)
-					break;
-				if (i >= 1000000) {
-					lockloop(l, pc);
-					break;
-				}
-			}
-		}
+
+	lockstats.locks++;
+	if(up)
+		up->nlocks++;	/* prevent being scheded */
+	if(tas(&l->key) == 0){
+		if(up)
+			up->lastlock = l;
 		l->pc = pc;
 		l->p = up;
 		l->m = MACHP(m->machno);
 		l->isilock = 0;
-		return;
+#ifdef LOCKCYCLES
+		l->lockcycles = -lcycles();
+#endif
+		return 0;
 	}
+	if(up)
+		up->nlocks--;
 
-	for(i=0; ; i++) {
-		if(_tas((int*)&l->key) == 0)
-			break;
-		if (i >= 1000) {
-			lockloop(l, pc);
-			break;
+	lockstats.glare++;
+	for(;;){
+		lockstats.inglare++;
+		i = 0;
+		while(l->key){
+			if(conf.nmach < 2 && up && up->edf && (up->edf->flags & Admitted)){
+				/*
+				 * Priority inversion, yield on a uniprocessor; on a
+				 * multiprocessor, the other processor will unlock
+				 */
+				print("inversion %#p pc %#p proc %lud held by pc %#p proc %lud\n",
+					l, pc, up != nil ? up->pid : 0, l->pc, l->p != nil ? ((Proc*)l->p)->pid : 0);
+				up->edf->d = todget(nil);	/* yield to process with lock */
+			}
+			if(i++ > 100000000){
+				i = 0;
+				lockloop(l, pc);
+			}
 		}
-		if(conf.nmach == 1 && up->state == Running && islo()) {
-			up->pc = pc;
-			sched();
+		if(up)
+			up->nlocks++;
+		if(tas(&l->key) == 0){
+			if(up)
+				up->lastlock = l;
+			l->pc = pc;
+			l->p = up;
+			l->m = MACHP(m->machno);
+			l->isilock = 0;
+#ifdef LOCKCYCLES
+			l->lockcycles = -lcycles();
+#endif
+			return 1;
 		}
+		if(up)
+			up->nlocks--;
 	}
-	l->pri = up->pri;
-	up->pri = PriLock;
-	l->pc = pc;
-	l->p = up;
-	l->m = MACHP(m->machno);
-	l->isilock = 0;
 }
 
 void
 ilock(Lock *l)
 {
-	uintptr x, pc;
-	int i;
+	ulong x;
+	uintptr pc;
 
 	pc = getcallerpc(&l);
+	lockstats.locks++;
+
 	x = splhi();
-	for(;;) {
-		if(_tas((int*)&l->key) == 0) {
-			l->sr = x;
-			l->pc = pc;
-			l->p = up;
-			l->m = MACHP(m->machno);
-			l->isilock = 1;
-			return;
+	if(tas(&l->key) != 0){
+		lockstats.glare++;
+		/*
+		 * Cannot also check l->pc, l->m, or l->isilock here
+		 * because they might just not be set yet, or
+		 * (for pc and m) the lock might have just been unlocked.
+		 */
+		for(;;){
+			lockstats.inglare++;
+			splx(x);
+			while(l->key)
+				;
+			x = splhi();
+			if(tas(&l->key) == 0)
+				goto acquire;
 		}
-		if(conf.nmach < 2)
-			panic("ilock: no way out: pc 0x%zux: lock 0x%lux held by pc 0x%zux", pc, l, l->pc);
-		for(i=0; ; i++) {
-			if(l->key == 0)
-				break;
-			clockcheck();
-			if (i > 100000) {
-				lockloop(l, pc);
-				break;
-			}
-		}
 	}
+acquire:
+	m->ilockdepth++;
+	if(up)
+		up->lastilock = l;
+	l->sr = x;
+	l->pc = pc;
+	l->p = up;
+	l->m = MACHP(m->machno);
+	l->isilock = 1;
+#ifdef LOCKCYCLES
+	l->lockcycles = -lcycles();
+#endif
 }
 
 int
 canlock(Lock *l)
 {
-	if(_tas((int*)&l->key))
+	if(up)
+		up->nlocks++;
+	if(tas(&l->key)){
+		if(up)
+			up->nlocks--;
 		return 0;
-	if(up){
-		l->pri = up->pri;
-		up->pri = PriLock;
 	}
+
+	if(up)
+		up->lastlock = l;
 	l->pc = getcallerpc(&l);
 	l->p = up;
 	l->m = MACHP(m->machno);
 	l->isilock = 0;
+#ifdef LOCKCYCLES
+	l->lockcycles = -lcycles();
+#endif
 	return 1;
 }
 
@@ -111,43 +181,70 @@
 void
 unlock(Lock *l)
 {
-	int p;
-
+#ifdef LOCKCYCLES
+	l->lockcycles += lcycles();
+	cumlockcycles += l->lockcycles;
+	if(l->lockcycles > maxlockcycles){
+		maxlockcycles = l->lockcycles;
+		maxlockpc = l->pc;
+	}
+#endif
 	if(l->key == 0)
-		print("unlock: not locked: pc %zux\n", getcallerpc(&l));
+		print("unlock(%#p): not locked: pc %#p\n",
+			l, getcallerpc(&l));
 	if(l->isilock)
 		print("unlock(%#p) of ilock: pc %#p, held by %#p\n",
 			l, getcallerpc(&l), l->pc);
-	if(l->p != up)
+	if(l->p != up){
 		print("unlock(%#p): up changed: pc %#p, acquired at pc %#p, lock p %#p, unlock up %#p\n",
 			l, getcallerpc(&l), l->pc, l->p, up);
-	p = l->pri;
+		dumpaproc(l->p);
+		dumpaproc(up);
+	}
 	l->m = nil;
 	coherence();
 	l->key = 0;
-	l->pc = 0;
-	if(up && islo()){
+
+	if(up && --up->nlocks == 0 && up->delaysched && islo()){
 		/*
 		 * Call sched if the need arose while locks were held
 		 * But, don't do it from interrupt routines, hence the islo() test
 		 */
-		up->pri = p;
-		if(up->state == Running && anyhigher())
-			sched();
+		sched();
 	}
 }
 
+uintptr ilockpcs[0x100] = { [0xff] = 1 };
+static int n;
+
 void
 iunlock(Lock *l)
 {
-	u32 sr;
+	ulong sr;
 
+#ifdef LOCKCYCLES
+	l->lockcycles += lcycles();
+	cumilockcycles += l->lockcycles;
+	if(l->lockcycles > maxilockcycles){
+		maxilockcycles = l->lockcycles;
+		maxilockpc = l->pc;
+	}
+	if(l->lockcycles > 2400)
+		ilockpcs[n++ & 0xff]  = l->pc;
+#endif
 	if(l->key == 0)
-		print("iunlock: not locked: pc %zux\n", getcallerpc(&l));
+		print("iunlock(%#p): not locked: pc %#p\n", l, getcallerpc(&l));
+	if(!l->isilock)
+		print("iunlock(%#p) of lock: pc %#p, held by %#p\n", l, getcallerpc(&l), l->pc);
+	if(islo())
+		print("iunlock(%#p) while lo: pc %#p, held by %#p\n", l, getcallerpc(&l), l->pc);
+
 	sr = l->sr;
 	l->m = nil;
 	coherence();
-	l->pc = 0;
 	l->key = 0;
+	m->ilockdepth--;
+	if(up)
+		up->lastilock = nil;
 	splx(sr);
 }