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