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