131085bb4Srsc // Mutual exclusion spin locks. 231085bb4Srsc 321a88fd4Skaashoek #include "types.h" 421a88fd4Skaashoek #include "defs.h" 5558ab49fSrsc #include "param.h" 621a88fd4Skaashoek #include "x86.h" 77837c71bSkaashoek #include "mmu.h" 84e8f237bSrtm #include "proc.h" 94e8f237bSrtm #include "spinlock.h" 1021a88fd4Skaashoek 110e84a0ecSrtm void 12*b121486cSRuss Cox initlock(struct spinlock *lk, char *name) 135be0039cSrtm { 14*b121486cSRuss Cox lk->name = name; 15*b121486cSRuss Cox lk->locked = 0; 16*b121486cSRuss Cox lk->cpu = 0xffffffff; 175be0039cSrtm } 185be0039cSrtm 1931085bb4Srsc // Acquire the lock. 2031085bb4Srsc // Loops (spins) until the lock is acquired. 21ab4cedb5Srtm // Holding a lock for a long time may cause 22ab4cedb5Srtm // other CPUs to waste time spinning to acquire it. 2321a88fd4Skaashoek void 24*b121486cSRuss Cox acquire(struct spinlock *lk) 2521a88fd4Skaashoek { 263807c1f2Srsc pushcli(); 27*b121486cSRuss Cox if(holding(lk)) 280dd42537Srsc panic("acquire"); 290dd42537Srsc 30943fd378Srsc // The xchg is atomic. 31943fd378Srsc // It also serializes, so that reads after acquire are not 32943fd378Srsc // reordered before it. 33*b121486cSRuss Cox while(xchg(&lk->locked, 1) != 0) 3465bd8e13Srsc ; 35e7a5b3c5Srsc 3631085bb4Srsc // Record info about lock acquisition for debugging. 3731085bb4Srsc // The +10 is only so that we can tell the difference 3831085bb4Srsc // between forgetting to initialize lock->cpu 3931085bb4Srsc // and holding a lock on cpu 0. 40*b121486cSRuss Cox lk->cpu = cpu() + 10; 41*b121486cSRuss Cox getcallerpcs(&lk, lk->pcs); 4221a88fd4Skaashoek } 4321a88fd4Skaashoek 4431085bb4Srsc // Release the lock. 4521a88fd4Skaashoek void 46*b121486cSRuss Cox release(struct spinlock *lk) 4721a88fd4Skaashoek { 48*b121486cSRuss Cox if(!holding(lk)) 490dd42537Srsc panic("release"); 500dd42537Srsc 51*b121486cSRuss Cox lk->pcs[0] = 0; 52*b121486cSRuss Cox lk->cpu = 0xffffffff; 53e7a5b3c5Srsc 54943fd378Srsc // The xchg serializes, so that reads before release are 55be38c841Srtm // not reordered after it. The 1996 PentiumPro manual (Volume 3, 56be38c841Srtm // 7.2) says reads can be carried out speculatively and in 57be38c841Srtm // any order, which implies we need to serialize here. 58be38c841Srtm // But the 2007 Intel 64 Architecture Memory Ordering White 59be38c841Srtm // Paper says that Intel 64 and IA-32 will not move a load 60be38c841Srtm // after a store. So lock->locked = 0 would work here. 61be38c841Srtm // The xchg being asm volatile ensures gcc emits it after 62be38c841Srtm // the above assignments (and after the critical section). 63*b121486cSRuss Cox xchg(&lk->locked, 0); 649fd9f804Srsc 653807c1f2Srsc popcli(); 6621a88fd4Skaashoek } 675af5f6aaSrsc 685af5f6aaSrsc // Record the current call stack in pcs[] by following the %ebp chain. 695af5f6aaSrsc void 705af5f6aaSrsc getcallerpcs(void *v, uint pcs[]) 715af5f6aaSrsc { 725af5f6aaSrsc uint *ebp; 735af5f6aaSrsc int i; 745af5f6aaSrsc 755af5f6aaSrsc ebp = (uint*)v - 2; 765af5f6aaSrsc for(i = 0; i < 10; i++){ 775af5f6aaSrsc if(ebp == 0 || ebp == (uint*)0xffffffff) 785af5f6aaSrsc break; 795af5f6aaSrsc pcs[i] = ebp[1]; // saved %eip 805af5f6aaSrsc ebp = (uint*)ebp[0]; // saved %ebp 815af5f6aaSrsc } 825af5f6aaSrsc for(; i < 10; i++) 835af5f6aaSrsc pcs[i] = 0; 845af5f6aaSrsc } 855af5f6aaSrsc 865af5f6aaSrsc // Check whether this cpu is holding the lock. 875af5f6aaSrsc int 885af5f6aaSrsc holding(struct spinlock *lock) 895af5f6aaSrsc { 905af5f6aaSrsc return lock->locked && lock->cpu == cpu() + 10; 915af5f6aaSrsc } 925af5f6aaSrsc 93c8919e65Srsc 94ab08960fSrsc // Pushcli/popcli are like cli/sti except that they are matched: 95ab08960fSrsc // it takes two popcli to undo two pushcli. Also, if interrupts 96ab08960fSrsc // are off, then pushcli, popcli leaves them off. 97c8919e65Srsc 98c8919e65Srsc void 993807c1f2Srsc pushcli(void) 100c8919e65Srsc { 101ab08960fSrsc int eflags; 102ab08960fSrsc 10321575761Srsc eflags = readeflags(); 104c8919e65Srsc cli(); 10519333efbSrsc if(c->ncli++ == 0) 10619333efbSrsc c->intena = eflags & FL_IF; 107c8919e65Srsc } 108c8919e65Srsc 109c8919e65Srsc void 1103807c1f2Srsc popcli(void) 111c8919e65Srsc { 11221575761Srsc if(readeflags()&FL_IF) 1133807c1f2Srsc panic("popcli - interruptible"); 11419333efbSrsc if(--c->ncli < 0) 1153807c1f2Srsc panic("popcli"); 11619333efbSrsc if(c->ncli == 0 && c->intena) 117c8919e65Srsc sti(); 118c8919e65Srsc } 119c8919e65Srsc 120