ref: 37775f47e6b73f64997fcc179e061d943c8721de
parent: 03be3a131ed2dcda25fed07258e5f39e5dda9fb2
author: 9ferno <[email protected]>
date: Thu Oct 14 08: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);
}