xref: /plan9-contrib/sys/src/9k/port/taslock.c (revision 5ddf0a198754ce69c27849817f497bfa5af41422)
19ef1f84bSDavid du Colombier #include "u.h"
29ef1f84bSDavid du Colombier #include "../port/lib.h"
39ef1f84bSDavid du Colombier #include "mem.h"
49ef1f84bSDavid du Colombier #include "dat.h"
59ef1f84bSDavid du Colombier #include "fns.h"
69ef1f84bSDavid du Colombier 
79ef1f84bSDavid du Colombier #include "../port/edf.h"
89ef1f84bSDavid du Colombier 
99ef1f84bSDavid du Colombier uvlong maxlockcycles;
109ef1f84bSDavid du Colombier uvlong maxilockcycles;
119ef1f84bSDavid du Colombier ulong maxlockpc;
129ef1f84bSDavid du Colombier ulong maxilockpc;
139ef1f84bSDavid du Colombier 
149ef1f84bSDavid du Colombier struct
159ef1f84bSDavid du Colombier {
169ef1f84bSDavid du Colombier 	ulong	locks;
179ef1f84bSDavid du Colombier 	ulong	glare;
189ef1f84bSDavid du Colombier 	ulong	inglare;
199ef1f84bSDavid du Colombier } lockstats;
209ef1f84bSDavid du Colombier 
219ef1f84bSDavid du Colombier static void
dumplockmem(char * tag,Lock * l)229ef1f84bSDavid du Colombier dumplockmem(char *tag, Lock *l)
239ef1f84bSDavid du Colombier {
249ef1f84bSDavid du Colombier 	uchar *cp;
259ef1f84bSDavid du Colombier 	int i;
269ef1f84bSDavid du Colombier 
279ef1f84bSDavid du Colombier 	iprint("%s: ", tag);
289ef1f84bSDavid du Colombier 	cp = (uchar*)l;
299ef1f84bSDavid du Colombier 	for(i = 0; i < 64; i++)
309ef1f84bSDavid du Colombier 		iprint("%2.2ux ", cp[i]);
319ef1f84bSDavid du Colombier 	iprint("\n");
329ef1f84bSDavid du Colombier }
339ef1f84bSDavid du Colombier 
349ef1f84bSDavid du Colombier void
lockloop(Lock * l,uintptr pc)359ef1f84bSDavid du Colombier lockloop(Lock *l, uintptr pc)
369ef1f84bSDavid du Colombier {
379ef1f84bSDavid du Colombier 	Proc *p;
389ef1f84bSDavid du Colombier 
399ef1f84bSDavid du Colombier 	p = l->p;
409ef1f84bSDavid du Colombier 	print("lock %#p loop key %#ux pc %#p held by pc %#p proc %d\n",
419ef1f84bSDavid du Colombier 		l, l->key, pc, l->pc, p ? p->pid : 0);
429ef1f84bSDavid du Colombier 	dumpaproc(up);
439ef1f84bSDavid du Colombier 	if(p != nil)
449ef1f84bSDavid du Colombier 		dumpaproc(p);
459ef1f84bSDavid du Colombier }
469ef1f84bSDavid du Colombier 
479ef1f84bSDavid du Colombier int
lock(Lock * l)489ef1f84bSDavid du Colombier lock(Lock *l)
499ef1f84bSDavid du Colombier {
509ef1f84bSDavid du Colombier 	int i;
519ef1f84bSDavid du Colombier 	uintptr pc;
529ef1f84bSDavid du Colombier 
539ef1f84bSDavid du Colombier 	pc = getcallerpc(&l);
549ef1f84bSDavid du Colombier 
559ef1f84bSDavid du Colombier 	lockstats.locks++;
569ef1f84bSDavid du Colombier 	if(up)
579ef1f84bSDavid du Colombier 		ainc(&up->nlocks);	/* prevent being scheded */
589ef1f84bSDavid du Colombier 	if(TAS(&l->key) == 0){
599ef1f84bSDavid du Colombier 		if(up)
609ef1f84bSDavid du Colombier 			up->lastlock = l;
619ef1f84bSDavid du Colombier 		l->pc = pc;
629ef1f84bSDavid du Colombier 		l->p = up;
639ef1f84bSDavid du Colombier 		l->isilock = 0;
64*5ddf0a19SDavid du Colombier 		l->m = m;
659ef1f84bSDavid du Colombier #ifdef LOCKCYCLES
669ef1f84bSDavid du Colombier 		cycles(&l->lockcycles);
679ef1f84bSDavid du Colombier #endif
689ef1f84bSDavid du Colombier 		return 0;
699ef1f84bSDavid du Colombier 	}
709ef1f84bSDavid du Colombier 	if(up)
719ef1f84bSDavid du Colombier 		adec(&up->nlocks);
729ef1f84bSDavid du Colombier 
739ef1f84bSDavid du Colombier 	lockstats.glare++;
749ef1f84bSDavid du Colombier 	for(;;){
759ef1f84bSDavid du Colombier 		lockstats.inglare++;
769ef1f84bSDavid du Colombier 		i = 0;
779ef1f84bSDavid du Colombier 		while(l->key){
789ef1f84bSDavid du Colombier 			if(sys->nonline < 2 && up && up->edf && (up->edf->flags & Admitted)){
799ef1f84bSDavid du Colombier 				/*
809ef1f84bSDavid du Colombier 				 * Priority inversion, yield on a uniprocessor; on a
819ef1f84bSDavid du Colombier 				 * multiprocessor, the other processor will unlock
829ef1f84bSDavid du Colombier 				 */
839ef1f84bSDavid du Colombier 				print("inversion %#p pc %#p proc %d held by pc %#p proc %d\n",
849ef1f84bSDavid du Colombier 					l, pc, up ? up->pid : 0, l->pc, l->p ? l->p->pid : 0);
859ef1f84bSDavid du Colombier 				up->edf->d = todget(nil);	/* yield to process with lock */
869ef1f84bSDavid du Colombier 			}
879ef1f84bSDavid du Colombier 			if(i++ > 100000000){
889ef1f84bSDavid du Colombier 				i = 0;
899ef1f84bSDavid du Colombier 				lockloop(l, pc);
909ef1f84bSDavid du Colombier 			}
919ef1f84bSDavid du Colombier 		}
929ef1f84bSDavid du Colombier 		if(up)
939ef1f84bSDavid du Colombier 			ainc(&up->nlocks);
949ef1f84bSDavid du Colombier 		if(TAS(&l->key) == 0){
959ef1f84bSDavid du Colombier 			if(up)
969ef1f84bSDavid du Colombier 				up->lastlock = l;
979ef1f84bSDavid du Colombier 			l->pc = pc;
989ef1f84bSDavid du Colombier 			l->p = up;
999ef1f84bSDavid du Colombier 			l->isilock = 0;
100*5ddf0a19SDavid du Colombier 			l->m = m;
1019ef1f84bSDavid du Colombier #ifdef LOCKCYCLES
1029ef1f84bSDavid du Colombier 			cycles(&l->lockcycles);
1039ef1f84bSDavid du Colombier #endif
1049ef1f84bSDavid du Colombier 			return 1;
1059ef1f84bSDavid du Colombier 		}
1069ef1f84bSDavid du Colombier 		if(up)
1079ef1f84bSDavid du Colombier 			adec(&up->nlocks);
1089ef1f84bSDavid du Colombier 	}
1099ef1f84bSDavid du Colombier }
1109ef1f84bSDavid du Colombier 
1119ef1f84bSDavid du Colombier void
ilock(Lock * l)1129ef1f84bSDavid du Colombier ilock(Lock *l)
1139ef1f84bSDavid du Colombier {
1149ef1f84bSDavid du Colombier 	Mreg s;
1159ef1f84bSDavid du Colombier 	uintptr pc;
1169ef1f84bSDavid du Colombier 
1179ef1f84bSDavid du Colombier 	pc = getcallerpc(&l);
1189ef1f84bSDavid du Colombier 	lockstats.locks++;
1199ef1f84bSDavid du Colombier 
1209ef1f84bSDavid du Colombier 	s = splhi();
1219ef1f84bSDavid du Colombier 	if(TAS(&l->key) != 0){
1229ef1f84bSDavid du Colombier 		lockstats.glare++;
1239ef1f84bSDavid du Colombier 		/*
1249ef1f84bSDavid du Colombier 		 * Cannot also check l->pc, l->m, or l->isilock here
1259ef1f84bSDavid du Colombier 		 * because they might just not be set yet, or
1269ef1f84bSDavid du Colombier 		 * (for pc and m) the lock might have just been unlocked.
1279ef1f84bSDavid du Colombier 		 */
1289ef1f84bSDavid du Colombier 		for(;;){
1299ef1f84bSDavid du Colombier 			lockstats.inglare++;
1309ef1f84bSDavid du Colombier 			splx(s);
1319ef1f84bSDavid du Colombier 			while(l->key)
1329ef1f84bSDavid du Colombier 				;
1339ef1f84bSDavid du Colombier 			s = splhi();
1349ef1f84bSDavid du Colombier 			if(TAS(&l->key) == 0)
1359ef1f84bSDavid du Colombier 				goto acquire;
1369ef1f84bSDavid du Colombier 		}
1379ef1f84bSDavid du Colombier 	}
1389ef1f84bSDavid du Colombier acquire:
1399ef1f84bSDavid du Colombier 	m->ilockdepth++;
1409ef1f84bSDavid du Colombier 	m->ilockpc = pc;
1419ef1f84bSDavid du Colombier 	if(up)
1429ef1f84bSDavid du Colombier 		up->lastilock = l;
1439ef1f84bSDavid du Colombier 	l->sr = s;
1449ef1f84bSDavid du Colombier 	l->pc = pc;
1459ef1f84bSDavid du Colombier 	l->p = up;
1469ef1f84bSDavid du Colombier 	l->isilock = 1;
1479ef1f84bSDavid du Colombier 	l->m = m;
1489ef1f84bSDavid du Colombier #ifdef LOCKCYCLES
1499ef1f84bSDavid du Colombier 	cycles(&l->lockcycles);
1509ef1f84bSDavid du Colombier #endif
1519ef1f84bSDavid du Colombier }
1529ef1f84bSDavid du Colombier 
1539ef1f84bSDavid du Colombier int
canlock(Lock * l)1549ef1f84bSDavid du Colombier canlock(Lock *l)
1559ef1f84bSDavid du Colombier {
1569ef1f84bSDavid du Colombier 	if(up)
1579ef1f84bSDavid du Colombier 		ainc(&up->nlocks);
1589ef1f84bSDavid du Colombier 	if(TAS(&l->key)){
1599ef1f84bSDavid du Colombier 		if(up)
1609ef1f84bSDavid du Colombier 			adec(&up->nlocks);
1619ef1f84bSDavid du Colombier 		return 0;
1629ef1f84bSDavid du Colombier 	}
1639ef1f84bSDavid du Colombier 
1649ef1f84bSDavid du Colombier 	if(up)
1659ef1f84bSDavid du Colombier 		up->lastlock = l;
1669ef1f84bSDavid du Colombier 	l->pc = getcallerpc(&l);
1679ef1f84bSDavid du Colombier 	l->p = up;
1689ef1f84bSDavid du Colombier 	l->m = m;
1699ef1f84bSDavid du Colombier 	l->isilock = 0;
1709ef1f84bSDavid du Colombier #ifdef LOCKCYCLES
1719ef1f84bSDavid du Colombier 	cycles(&l->lockcycles);
1729ef1f84bSDavid du Colombier #endif
1739ef1f84bSDavid du Colombier 	return 1;
1749ef1f84bSDavid du Colombier }
1759ef1f84bSDavid du Colombier 
1769ef1f84bSDavid du Colombier void
unlock(Lock * l)1779ef1f84bSDavid du Colombier unlock(Lock *l)
1789ef1f84bSDavid du Colombier {
1799ef1f84bSDavid du Colombier #ifdef LOCKCYCLES
1809ef1f84bSDavid du Colombier 	uvlong x;
1819ef1f84bSDavid du Colombier 	cycles(&x);
1829ef1f84bSDavid du Colombier 	l->lockcycles = x - l->lockcycles;
1839ef1f84bSDavid du Colombier 	if(l->lockcycles > maxlockcycles){
1849ef1f84bSDavid du Colombier 		maxlockcycles = l->lockcycles;
1859ef1f84bSDavid du Colombier 		maxlockpc = l->pc;
1869ef1f84bSDavid du Colombier 	}
1879ef1f84bSDavid du Colombier #endif
1889ef1f84bSDavid du Colombier 
1899ef1f84bSDavid du Colombier 	if(l->key == 0)
1909ef1f84bSDavid du Colombier 		print("unlock: not locked: pc %#p\n", getcallerpc(&l));
1919ef1f84bSDavid du Colombier 	if(l->isilock)
1929ef1f84bSDavid du Colombier 		print("unlock of ilock: pc %#p, held by %#p\n", getcallerpc(&l), l->pc);
1939ef1f84bSDavid du Colombier 	if(l->p != up)
1949ef1f84bSDavid du Colombier 		print("unlock: up changed: pc %#p, acquired at pc %#p, lock p %#p, unlock up %#p\n", getcallerpc(&l), l->pc, l->p, up);
1959ef1f84bSDavid du Colombier 	l->m = nil;
1969ef1f84bSDavid du Colombier 	l->key = 0;
1979ef1f84bSDavid du Colombier 	coherence();
1989ef1f84bSDavid du Colombier 
1999ef1f84bSDavid du Colombier 	if(up && adec(&up->nlocks) == 0 && up->delaysched && islo()){
2009ef1f84bSDavid du Colombier 		/*
2019ef1f84bSDavid du Colombier 		 * Call sched if the need arose while locks were held
2029ef1f84bSDavid du Colombier 		 * But, don't do it from interrupt routines, hence the islo() test
2039ef1f84bSDavid du Colombier 		 */
2049ef1f84bSDavid du Colombier 		sched();
2059ef1f84bSDavid du Colombier 	}
2069ef1f84bSDavid du Colombier }
2079ef1f84bSDavid du Colombier 
2089ef1f84bSDavid du Colombier void
iunlock(Lock * l)2099ef1f84bSDavid du Colombier iunlock(Lock *l)
2109ef1f84bSDavid du Colombier {
2119ef1f84bSDavid du Colombier 	Mreg s;
2129ef1f84bSDavid du Colombier 
2139ef1f84bSDavid du Colombier #ifdef LOCKCYCLES
2149ef1f84bSDavid du Colombier 	uvlong x;
2159ef1f84bSDavid du Colombier 	cycles(&x);
2169ef1f84bSDavid du Colombier 	l->lockcycles = x - l->lockcycles;
2179ef1f84bSDavid du Colombier 	if(l->lockcycles > maxilockcycles){
2189ef1f84bSDavid du Colombier 		maxilockcycles = l->lockcycles;
2199ef1f84bSDavid du Colombier 		maxilockpc = l->pc;
2209ef1f84bSDavid du Colombier 	}
2219ef1f84bSDavid du Colombier #endif
2229ef1f84bSDavid du Colombier 
2239ef1f84bSDavid du Colombier 	if(l->key == 0)
2249ef1f84bSDavid du Colombier 		print("iunlock: not locked: pc %#p\n", getcallerpc(&l));
2259ef1f84bSDavid du Colombier 	if(!l->isilock)
2269ef1f84bSDavid du Colombier 		print("iunlock of lock: pc %#p, held by %#p\n", getcallerpc(&l), l->pc);
2279ef1f84bSDavid du Colombier 	if(islo())
2289ef1f84bSDavid du Colombier 		print("iunlock while lo: pc %#p, held by %#p\n", getcallerpc(&l), l->pc);
2299ef1f84bSDavid du Colombier 	if(l->m != m){
2309ef1f84bSDavid du Colombier 		print("iunlock by cpu%d, locked by cpu%d: pc %#p, held by %#p\n",
2319ef1f84bSDavid du Colombier 			m->machno, l->m->machno, getcallerpc(&l), l->pc);
2329ef1f84bSDavid du Colombier 	}
2339ef1f84bSDavid du Colombier 
2349ef1f84bSDavid du Colombier 	s = l->sr;
2359ef1f84bSDavid du Colombier 	l->m = nil;
2369ef1f84bSDavid du Colombier 	l->key = 0;
2379ef1f84bSDavid du Colombier 	coherence();
2389ef1f84bSDavid du Colombier 	m->ilockdepth--;
2399ef1f84bSDavid du Colombier 	if(up)
2409ef1f84bSDavid du Colombier 		up->lastilock = nil;
2419ef1f84bSDavid du Colombier 	splx(s);
2429ef1f84bSDavid du Colombier }
243