1 // Mutual exclusion spin locks. 2 3 #include "types.h" 4 #include "defs.h" 5 #include "param.h" 6 #include "x86.h" 7 #include "mmu.h" 8 #include "proc.h" 9 #include "spinlock.h" 10 11 extern int use_console_lock; 12 13 void 14 initlock(struct spinlock *lock, char *name) 15 { 16 lock->name = name; 17 lock->locked = 0; 18 lock->cpu = 0xffffffff; 19 } 20 21 // Acquire the lock. 22 // Loops (spins) until the lock is acquired. 23 // Holding a lock for a long time may cause 24 // other CPUs to waste time spinning to acquire it. 25 void 26 acquire(struct spinlock *lock) 27 { 28 pushcli(); 29 if(holding(lock)) 30 panic("acquire"); 31 32 while(cmpxchg(0, 1, &lock->locked) == 1) 33 ; 34 35 // Serialize instructions: now that lock is acquired, make sure 36 // we wait for all pending writes from other processors. 37 cpuid(0, 0, 0, 0, 0); // memory barrier (see Ch 7, IA-32 manual vol 3) 38 39 // Record info about lock acquisition for debugging. 40 // The +10 is only so that we can tell the difference 41 // between forgetting to initialize lock->cpu 42 // and holding a lock on cpu 0. 43 lock->cpu = cpu() + 10; 44 getcallerpcs(&lock, lock->pcs); 45 } 46 47 // Release the lock. 48 void 49 release(struct spinlock *lock) 50 { 51 if(!holding(lock)) 52 panic("release"); 53 54 lock->pcs[0] = 0; 55 lock->cpu = 0xffffffff; 56 57 // Serialize instructions: before unlocking the lock, make sure 58 // to flush any pending memory writes from this processor. 59 cpuid(0, 0, 0, 0, 0); // memory barrier (see Ch 7, IA-32 manual vol 3) 60 61 lock->locked = 0; 62 popcli(); 63 } 64 65 // Record the current call stack in pcs[] by following the %ebp chain. 66 void 67 getcallerpcs(void *v, uint pcs[]) 68 { 69 uint *ebp; 70 int i; 71 72 ebp = (uint*)v - 2; 73 for(i = 0; i < 10; i++){ 74 if(ebp == 0 || ebp == (uint*)0xffffffff) 75 break; 76 pcs[i] = ebp[1]; // saved %eip 77 ebp = (uint*)ebp[0]; // saved %ebp 78 } 79 for(; i < 10; i++) 80 pcs[i] = 0; 81 } 82 83 // Check whether this cpu is holding the lock. 84 int 85 holding(struct spinlock *lock) 86 { 87 return lock->locked && lock->cpu == cpu() + 10; 88 } 89 90 91 92 // XXX! 93 // Better names? Better functions? 94 95 void 96 pushcli(void) 97 { 98 cli(); 99 cpus[cpu()].ncli++; 100 } 101 102 void 103 popcli(void) 104 { 105 if(read_eflags()&FL_IF) 106 panic("popcli - interruptible"); 107 if(--cpus[cpu()].ncli < 0) 108 panic("popcli"); 109 if(cpus[cpu()].ncli == 0) 110 sti(); 111 } 112 113