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 // Barrier to gcc's instruction reordering. 14 static void inline gccbarrier(void) 15 { 16 asm volatile("" : : : "memory"); 17 } 18 19 void 20 initlock(struct spinlock *lock, char *name) 21 { 22 lock->name = name; 23 lock->locked = 0; 24 lock->cpu = 0xffffffff; 25 } 26 27 // Acquire the lock. 28 // Loops (spins) until the lock is acquired. 29 // Holding a lock for a long time may cause 30 // other CPUs to waste time spinning to acquire it. 31 void 32 acquire(struct spinlock *lock) 33 { 34 pushcli(); 35 if(holding(lock)) 36 panic("acquire"); 37 38 while(cmpxchg(0, 1, &lock->locked) == 1) 39 ; 40 41 // Record info about lock acquisition for debugging. 42 // The +10 is only so that we can tell the difference 43 // between forgetting to initialize lock->cpu 44 // and holding a lock on cpu 0. 45 lock->cpu = cpu() + 10; 46 getcallerpcs(&lock, lock->pcs); 47 } 48 49 // Release the lock. 50 void 51 release(struct spinlock *lock) 52 { 53 if(!holding(lock)) 54 panic("release"); 55 56 lock->pcs[0] = 0; 57 lock->cpu = 0xffffffff; 58 59 gccbarrier(); // Keep gcc from moving lock->locked = 0 earlier. 60 lock->locked = 0; 61 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 // Pushcli/popcli are like cli/sti except that they are matched: 92 // it takes two popcli to undo two pushcli. Also, if interrupts 93 // are off, then pushcli, popcli leaves them off. 94 95 void 96 pushcli(void) 97 { 98 int eflags; 99 100 eflags = read_eflags(); 101 cli(); 102 if(cpus[cpu()].ncli++ == 0) 103 cpus[cpu()].intena = eflags & FL_IF; 104 } 105 106 void 107 popcli(void) 108 { 109 if(read_eflags()&FL_IF) 110 panic("popcli - interruptible"); 111 if(--cpus[cpu()].ncli < 0) 112 panic("popcli"); 113 if(cpus[cpu()].ncli == 0 && cpus[cpu()].intena) 114 sti(); 115 } 116 117