131085bb4Srsc // Mutual exclusion spin locks. 231085bb4Srsc 321a88fd4Skaashoek #include "types.h" 421a88fd4Skaashoek #include "defs.h" 521a88fd4Skaashoek #include "x86.h" 67837c71bSkaashoek #include "mmu.h" 74e8f237bSrtm #include "param.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 // Record the current call stack in pcs[] by following the %ebp chain. 225be0039cSrtm void 230e84a0ecSrtm getcallerpcs(void *v, uint pcs[]) 2465bd8e13Srsc { 250e84a0ecSrtm uint *ebp = (uint*)v - 2; 260e84a0ecSrtm int i; 270cfc7290Srsc for(i = 0; i < 10; i++){ 280cfc7290Srsc if(ebp == 0 || ebp == (uint*)0xffffffff) 290cfc7290Srsc break; 300cfc7290Srsc pcs[i] = ebp[1]; // saved %eip 310cfc7290Srsc ebp = (uint*)ebp[0]; // saved %ebp 320e84a0ecSrtm } 330e84a0ecSrtm for(; i < 10; i++) 340e84a0ecSrtm pcs[i] = 0; 355ce9751cSrsc } 365ce9751cSrsc 3731085bb4Srsc // Acquire the lock. 3831085bb4Srsc // Loops (spins) until the lock is acquired. 3931085bb4Srsc // (Because contention is handled by spinning, must not 4031085bb4Srsc // go to sleep holding any locks.) 4121a88fd4Skaashoek void 42679a977cSrsc acquire(struct spinlock *lock) 4321a88fd4Skaashoek { 440e84a0ecSrtm if(holding(lock)) 450dd42537Srsc panic("acquire"); 460dd42537Srsc 478a8be1b8Srtm if(cpus[cpu()].nlock == 0) 48b548df15Srtm cli(); 498a8be1b8Srtm cpus[cpu()].nlock++; 508a8be1b8Srtm 5165bd8e13Srsc while(cmpxchg(0, 1, &lock->locked) == 1) 5265bd8e13Srsc ; 53*e7a5b3c5Srsc 54*e7a5b3c5Srsc // Now that lock is acquired, make sure 55*e7a5b3c5Srsc // we wait for all pending writes from other 56*e7a5b3c5Srsc // processors. 5765bd8e13Srsc cpuid(0, 0, 0, 0, 0); // memory barrier 5831085bb4Srsc 5931085bb4Srsc // Record info about lock acquisition for debugging. 6031085bb4Srsc // The +10 is only so that we can tell the difference 6131085bb4Srsc // between forgetting to initialize lock->cpu 6231085bb4Srsc // and holding a lock on cpu 0. 630e84a0ecSrtm lock->cpu = cpu() + 10; 6431085bb4Srsc getcallerpcs(&lock, lock->pcs); 6521a88fd4Skaashoek } 6621a88fd4Skaashoek 6731085bb4Srsc // Release the lock. 6821a88fd4Skaashoek void 69679a977cSrsc release(struct spinlock *lock) 7021a88fd4Skaashoek { 710dd42537Srsc if(!holding(lock)) 720dd42537Srsc panic("release"); 730dd42537Srsc 740e84a0ecSrtm lock->pcs[0] = 0; 750e84a0ecSrtm lock->cpu = 0xffffffff; 76*e7a5b3c5Srsc 77*e7a5b3c5Srsc // Before unlocking the lock, make sure to flush 78*e7a5b3c5Srsc // any pending memory writes from this processor. 7965bd8e13Srsc cpuid(0, 0, 0, 0, 0); // memory barrier 80*e7a5b3c5Srsc 8165bd8e13Srsc lock->locked = 0; 82b74f4b57Srsc if(--cpus[cpu()].nlock == 0) 83b548df15Srtm sti(); 8421a88fd4Skaashoek } 8546bbd72fSrtm 8631085bb4Srsc // Check whether this cpu is holding the lock. 870dd42537Srsc int 880dd42537Srsc holding(struct spinlock *lock) 890dd42537Srsc { 900e84a0ecSrtm return lock->locked && lock->cpu == cpu() + 10; 910dd42537Srsc } 92