131085bb4Srsc // Mutual exclusion spin locks. 231085bb4Srsc 321a88fd4Skaashoek #include "types.h" 421a88fd4Skaashoek #include "defs.h" 5*558ab49fSrsc #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. 2315b326b6Srsc // (Because contention is handled by spinning, 2415b326b6Srsc // must not go to sleep holding any locks.) 2521a88fd4Skaashoek void 26679a977cSrsc acquire(struct spinlock *lock) 2721a88fd4Skaashoek { 280e84a0ecSrtm if(holding(lock)) 290dd42537Srsc panic("acquire"); 300dd42537Srsc 318a8be1b8Srtm if(cpus[cpu()].nlock == 0) 32b548df15Srtm cli(); 338a8be1b8Srtm cpus[cpu()].nlock++; 348a8be1b8Srtm 3565bd8e13Srsc while(cmpxchg(0, 1, &lock->locked) == 1) 3665bd8e13Srsc ; 37e7a5b3c5Srsc 388e1d1ec9Skaashoek // Serialize instructions: now that lock is acquired, make sure 398e1d1ec9Skaashoek // we wait for all pending writes from other processors. 40ba969aa6Srsc cpuid(0, 0, 0, 0, 0); // memory barrier (see Ch 7, IA-32 manual vol 3) 4131085bb4Srsc 4231085bb4Srsc // Record info about lock acquisition for debugging. 4331085bb4Srsc // The +10 is only so that we can tell the difference 4431085bb4Srsc // between forgetting to initialize lock->cpu 4531085bb4Srsc // and holding a lock on cpu 0. 460e84a0ecSrtm lock->cpu = cpu() + 10; 4731085bb4Srsc getcallerpcs(&lock, lock->pcs); 4821a88fd4Skaashoek } 4921a88fd4Skaashoek 5031085bb4Srsc // Release the lock. 5121a88fd4Skaashoek void 52679a977cSrsc release(struct spinlock *lock) 5321a88fd4Skaashoek { 540dd42537Srsc if(!holding(lock)) 550dd42537Srsc panic("release"); 560dd42537Srsc 570e84a0ecSrtm lock->pcs[0] = 0; 580e84a0ecSrtm lock->cpu = 0xffffffff; 59e7a5b3c5Srsc 608e1d1ec9Skaashoek // Serialize instructions: before unlocking the lock, make sure 618e1d1ec9Skaashoek // to flush any pending memory writes from this processor. 62ba969aa6Srsc cpuid(0, 0, 0, 0, 0); // memory barrier (see Ch 7, IA-32 manual vol 3) 63e7a5b3c5Srsc 6465bd8e13Srsc lock->locked = 0; 65b74f4b57Srsc if(--cpus[cpu()].nlock == 0) 66b548df15Srtm sti(); 6721a88fd4Skaashoek } 685af5f6aaSrsc 695af5f6aaSrsc // Record the current call stack in pcs[] by following the %ebp chain. 705af5f6aaSrsc void 715af5f6aaSrsc getcallerpcs(void *v, uint pcs[]) 725af5f6aaSrsc { 735af5f6aaSrsc uint *ebp; 745af5f6aaSrsc int i; 755af5f6aaSrsc 765af5f6aaSrsc ebp = (uint*)v - 2; 775af5f6aaSrsc for(i = 0; i < 10; i++){ 785af5f6aaSrsc if(ebp == 0 || ebp == (uint*)0xffffffff) 795af5f6aaSrsc break; 805af5f6aaSrsc pcs[i] = ebp[1]; // saved %eip 815af5f6aaSrsc ebp = (uint*)ebp[0]; // saved %ebp 825af5f6aaSrsc } 835af5f6aaSrsc for(; i < 10; i++) 845af5f6aaSrsc pcs[i] = 0; 855af5f6aaSrsc } 865af5f6aaSrsc 875af5f6aaSrsc // Check whether this cpu is holding the lock. 885af5f6aaSrsc int 895af5f6aaSrsc holding(struct spinlock *lock) 905af5f6aaSrsc { 915af5f6aaSrsc return lock->locked && lock->cpu == cpu() + 10; 925af5f6aaSrsc } 935af5f6aaSrsc 94