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 11b74f4b57Srsc extern int use_console_lock; 128148b6eeSrtm 130e84a0ecSrtm void 145be0039cSrtm initlock(struct spinlock *lock, char *name) 155be0039cSrtm { 165be0039cSrtm lock->name = name; 175be0039cSrtm lock->locked = 0; 185be0039cSrtm lock->cpu = 0xffffffff; 195be0039cSrtm } 205be0039cSrtm 2131085bb4Srsc // Acquire the lock. 2231085bb4Srsc // Loops (spins) until the lock is acquired. 23ab4cedb5Srtm // Holding a lock for a long time may cause 24ab4cedb5Srtm // other CPUs to waste time spinning to acquire it. 2521a88fd4Skaashoek void 26679a977cSrsc acquire(struct spinlock *lock) 2721a88fd4Skaashoek { 283807c1f2Srsc pushcli(); 290e84a0ecSrtm if(holding(lock)) 300dd42537Srsc panic("acquire"); 310dd42537Srsc 32*943fd378Srsc // The xchg is atomic. 33*943fd378Srsc // It also serializes, so that reads after acquire are not 34*943fd378Srsc // reordered before it. 35*943fd378Srsc while(xchg(&lock->locked, 1) == 1) 3665bd8e13Srsc ; 37e7a5b3c5Srsc 3831085bb4Srsc // Record info about lock acquisition for debugging. 3931085bb4Srsc // The +10 is only so that we can tell the difference 4031085bb4Srsc // between forgetting to initialize lock->cpu 4131085bb4Srsc // and holding a lock on cpu 0. 420e84a0ecSrtm lock->cpu = cpu() + 10; 4331085bb4Srsc getcallerpcs(&lock, lock->pcs); 4421a88fd4Skaashoek } 4521a88fd4Skaashoek 4631085bb4Srsc // Release the lock. 4721a88fd4Skaashoek void 48679a977cSrsc release(struct spinlock *lock) 4921a88fd4Skaashoek { 500dd42537Srsc if(!holding(lock)) 510dd42537Srsc panic("release"); 520dd42537Srsc 530e84a0ecSrtm lock->pcs[0] = 0; 540e84a0ecSrtm lock->cpu = 0xffffffff; 55e7a5b3c5Srsc 56*943fd378Srsc // The xchg serializes, so that reads before release are 57*943fd378Srsc // not reordered after it. (This reordering would be allowed 58*943fd378Srsc // by the Intel manuals, but does not happen on current 59*943fd378Srsc // Intel processors. The xchg being asm volatile also keeps 60*943fd378Srsc // gcc from delaying the above assignments.) 61*943fd378Srsc xchg(&lock->locked, 0); 629fd9f804Srsc 633807c1f2Srsc popcli(); 6421a88fd4Skaashoek } 655af5f6aaSrsc 665af5f6aaSrsc // Record the current call stack in pcs[] by following the %ebp chain. 675af5f6aaSrsc void 685af5f6aaSrsc getcallerpcs(void *v, uint pcs[]) 695af5f6aaSrsc { 705af5f6aaSrsc uint *ebp; 715af5f6aaSrsc int i; 725af5f6aaSrsc 735af5f6aaSrsc ebp = (uint*)v - 2; 745af5f6aaSrsc for(i = 0; i < 10; i++){ 755af5f6aaSrsc if(ebp == 0 || ebp == (uint*)0xffffffff) 765af5f6aaSrsc break; 775af5f6aaSrsc pcs[i] = ebp[1]; // saved %eip 785af5f6aaSrsc ebp = (uint*)ebp[0]; // saved %ebp 795af5f6aaSrsc } 805af5f6aaSrsc for(; i < 10; i++) 815af5f6aaSrsc pcs[i] = 0; 825af5f6aaSrsc } 835af5f6aaSrsc 845af5f6aaSrsc // Check whether this cpu is holding the lock. 855af5f6aaSrsc int 865af5f6aaSrsc holding(struct spinlock *lock) 875af5f6aaSrsc { 885af5f6aaSrsc return lock->locked && lock->cpu == cpu() + 10; 895af5f6aaSrsc } 905af5f6aaSrsc 91c8919e65Srsc 92ab08960fSrsc // Pushcli/popcli are like cli/sti except that they are matched: 93ab08960fSrsc // it takes two popcli to undo two pushcli. Also, if interrupts 94ab08960fSrsc // are off, then pushcli, popcli leaves them off. 95c8919e65Srsc 96c8919e65Srsc void 973807c1f2Srsc pushcli(void) 98c8919e65Srsc { 99ab08960fSrsc int eflags; 100ab08960fSrsc 101ab08960fSrsc eflags = read_eflags(); 102c8919e65Srsc cli(); 103ab08960fSrsc if(cpus[cpu()].ncli++ == 0) 104ab08960fSrsc cpus[cpu()].intena = eflags & FL_IF; 105c8919e65Srsc } 106c8919e65Srsc 107c8919e65Srsc void 1083807c1f2Srsc popcli(void) 109c8919e65Srsc { 110c8919e65Srsc if(read_eflags()&FL_IF) 1113807c1f2Srsc panic("popcli - interruptible"); 1123807c1f2Srsc if(--cpus[cpu()].ncli < 0) 1133807c1f2Srsc panic("popcli"); 114ab08960fSrsc if(cpus[cpu()].ncli == 0 && cpus[cpu()].intena) 115c8919e65Srsc sti(); 116c8919e65Srsc } 117c8919e65Srsc 118