xref: /xv6-public/spinlock.c (revision 943fd378)
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 
32*943fd378Srsc   // The xchg is atomic.
33*943fd378Srsc   // It also serializes, so that reads after acquire are not
34*943fd378Srsc   // reordered before it.
35*943fd378Srsc   while(xchg(&lock->locked, 1) == 1)
3665bd8e13Srsc     ;
37e7a5b3c5Srsc 
3831085bb4Srsc   // Record info about lock acquisition for debugging.
3931085bb4Srsc   // The +10 is only so that we can tell the difference
4031085bb4Srsc   // between forgetting to initialize lock->cpu
4131085bb4Srsc   // and holding a lock on cpu 0.
420e84a0ecSrtm   lock->cpu = cpu() + 10;
4331085bb4Srsc   getcallerpcs(&lock, lock->pcs);
4421a88fd4Skaashoek }
4521a88fd4Skaashoek 
4631085bb4Srsc // Release the lock.
4721a88fd4Skaashoek void
48679a977cSrsc release(struct spinlock *lock)
4921a88fd4Skaashoek {
500dd42537Srsc   if(!holding(lock))
510dd42537Srsc     panic("release");
520dd42537Srsc 
530e84a0ecSrtm   lock->pcs[0] = 0;
540e84a0ecSrtm   lock->cpu = 0xffffffff;
55e7a5b3c5Srsc 
56*943fd378Srsc   // The xchg serializes, so that reads before release are
57*943fd378Srsc   // not reordered after it.  (This reordering would be allowed
58*943fd378Srsc   // by the Intel manuals, but does not happen on current
59*943fd378Srsc   // Intel processors.  The xchg being asm volatile also keeps
60*943fd378Srsc   // gcc from delaying the above assignments.)
61*943fd378Srsc   xchg(&lock->locked, 0);
629fd9f804Srsc 
633807c1f2Srsc   popcli();
6421a88fd4Skaashoek }
655af5f6aaSrsc 
665af5f6aaSrsc // Record the current call stack in pcs[] by following the %ebp chain.
675af5f6aaSrsc void
685af5f6aaSrsc getcallerpcs(void *v, uint pcs[])
695af5f6aaSrsc {
705af5f6aaSrsc   uint *ebp;
715af5f6aaSrsc   int i;
725af5f6aaSrsc 
735af5f6aaSrsc   ebp = (uint*)v - 2;
745af5f6aaSrsc   for(i = 0; i < 10; i++){
755af5f6aaSrsc     if(ebp == 0 || ebp == (uint*)0xffffffff)
765af5f6aaSrsc       break;
775af5f6aaSrsc     pcs[i] = ebp[1];     // saved %eip
785af5f6aaSrsc     ebp = (uint*)ebp[0]; // saved %ebp
795af5f6aaSrsc   }
805af5f6aaSrsc   for(; i < 10; i++)
815af5f6aaSrsc     pcs[i] = 0;
825af5f6aaSrsc }
835af5f6aaSrsc 
845af5f6aaSrsc // Check whether this cpu is holding the lock.
855af5f6aaSrsc int
865af5f6aaSrsc holding(struct spinlock *lock)
875af5f6aaSrsc {
885af5f6aaSrsc   return lock->locked && lock->cpu == cpu() + 10;
895af5f6aaSrsc }
905af5f6aaSrsc 
91c8919e65Srsc 
92ab08960fSrsc // Pushcli/popcli are like cli/sti except that they are matched:
93ab08960fSrsc // it takes two popcli to undo two pushcli.  Also, if interrupts
94ab08960fSrsc // are off, then pushcli, popcli leaves them off.
95c8919e65Srsc 
96c8919e65Srsc void
973807c1f2Srsc pushcli(void)
98c8919e65Srsc {
99ab08960fSrsc   int eflags;
100ab08960fSrsc 
101ab08960fSrsc   eflags = read_eflags();
102c8919e65Srsc   cli();
103ab08960fSrsc   if(cpus[cpu()].ncli++ == 0)
104ab08960fSrsc     cpus[cpu()].intena = eflags & FL_IF;
105c8919e65Srsc }
106c8919e65Srsc 
107c8919e65Srsc void
1083807c1f2Srsc popcli(void)
109c8919e65Srsc {
110c8919e65Srsc   if(read_eflags()&FL_IF)
1113807c1f2Srsc     panic("popcli - interruptible");
1123807c1f2Srsc   if(--cpus[cpu()].ncli < 0)
1133807c1f2Srsc     panic("popcli");
114ab08960fSrsc   if(cpus[cpu()].ncli == 0 && cpus[cpu()].intena)
115c8919e65Srsc     sti();
116c8919e65Srsc }
117c8919e65Srsc 
118