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 3265bd8e13Srsc while(cmpxchg(0, 1, &lock->locked) == 1) 3365bd8e13Srsc ; 34e7a5b3c5Srsc 358e1d1ec9Skaashoek // Serialize instructions: now that lock is acquired, make sure 368e1d1ec9Skaashoek // we wait for all pending writes from other processors. 37ba969aa6Srsc cpuid(0, 0, 0, 0, 0); // memory barrier (see Ch 7, IA-32 manual vol 3) 3831085bb4Srsc 3931085bb4Srsc // Record info about lock acquisition for debugging. 4031085bb4Srsc // The +10 is only so that we can tell the difference 4131085bb4Srsc // between forgetting to initialize lock->cpu 4231085bb4Srsc // and holding a lock on cpu 0. 430e84a0ecSrtm lock->cpu = cpu() + 10; 4431085bb4Srsc getcallerpcs(&lock, lock->pcs); 4521a88fd4Skaashoek } 4621a88fd4Skaashoek 4731085bb4Srsc // Release the lock. 4821a88fd4Skaashoek void 49679a977cSrsc release(struct spinlock *lock) 5021a88fd4Skaashoek { 510dd42537Srsc if(!holding(lock)) 520dd42537Srsc panic("release"); 530dd42537Srsc 540e84a0ecSrtm lock->pcs[0] = 0; 550e84a0ecSrtm lock->cpu = 0xffffffff; 56e7a5b3c5Srsc 578e1d1ec9Skaashoek // Serialize instructions: before unlocking the lock, make sure 588e1d1ec9Skaashoek // to flush any pending memory writes from this processor. 59ba969aa6Srsc cpuid(0, 0, 0, 0, 0); // memory barrier (see Ch 7, IA-32 manual vol 3) 60e7a5b3c5Srsc 6165bd8e13Srsc lock->locked = 0; 623807c1f2Srsc popcli(); 6321a88fd4Skaashoek } 645af5f6aaSrsc 655af5f6aaSrsc // Record the current call stack in pcs[] by following the %ebp chain. 665af5f6aaSrsc void 675af5f6aaSrsc getcallerpcs(void *v, uint pcs[]) 685af5f6aaSrsc { 695af5f6aaSrsc uint *ebp; 705af5f6aaSrsc int i; 715af5f6aaSrsc 725af5f6aaSrsc ebp = (uint*)v - 2; 735af5f6aaSrsc for(i = 0; i < 10; i++){ 745af5f6aaSrsc if(ebp == 0 || ebp == (uint*)0xffffffff) 755af5f6aaSrsc break; 765af5f6aaSrsc pcs[i] = ebp[1]; // saved %eip 775af5f6aaSrsc ebp = (uint*)ebp[0]; // saved %ebp 785af5f6aaSrsc } 795af5f6aaSrsc for(; i < 10; i++) 805af5f6aaSrsc pcs[i] = 0; 815af5f6aaSrsc } 825af5f6aaSrsc 835af5f6aaSrsc // Check whether this cpu is holding the lock. 845af5f6aaSrsc int 855af5f6aaSrsc holding(struct spinlock *lock) 865af5f6aaSrsc { 875af5f6aaSrsc return lock->locked && lock->cpu == cpu() + 10; 885af5f6aaSrsc } 895af5f6aaSrsc 90c8919e65Srsc 91*ab08960fSrsc // Pushcli/popcli are like cli/sti except that they are matched: 92*ab08960fSrsc // it takes two popcli to undo two pushcli. Also, if interrupts 93*ab08960fSrsc // are off, then pushcli, popcli leaves them off. 94c8919e65Srsc 95c8919e65Srsc void 963807c1f2Srsc pushcli(void) 97c8919e65Srsc { 98*ab08960fSrsc int eflags; 99*ab08960fSrsc 100*ab08960fSrsc eflags = read_eflags(); 101c8919e65Srsc cli(); 102*ab08960fSrsc if(cpus[cpu()].ncli++ == 0) 103*ab08960fSrsc cpus[cpu()].intena = eflags & FL_IF; 104c8919e65Srsc } 105c8919e65Srsc 106c8919e65Srsc void 1073807c1f2Srsc popcli(void) 108c8919e65Srsc { 109c8919e65Srsc if(read_eflags()&FL_IF) 1103807c1f2Srsc panic("popcli - interruptible"); 1113807c1f2Srsc if(--cpus[cpu()].ncli < 0) 1123807c1f2Srsc panic("popcli"); 113*ab08960fSrsc if(cpus[cpu()].ncli == 0 && cpus[cpu()].intena) 114c8919e65Srsc sti(); 115c8919e65Srsc } 116c8919e65Srsc 117