xref: /xv6-public/spinlock.c (revision ab08960f)
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