Xv6 with picoc & Linkage editor
v1.0
The project delineate mutual cohesion between c library, linkage editor ( linker), interpreter and operating system by porting the same on xv6 kernel
|
00001 // Mutual exclusion spin locks. 00002 00003 #include "types.h" 00004 #include "defs.h" 00005 #include "param.h" 00006 #include "x86.h" 00007 #include "memlayout.h" 00008 #include "mmu.h" 00009 #include "proc.h" 00010 #include "spinlock.h" 00011 00012 void 00013 initlock(struct spinlock *lk, char *name) 00014 { 00015 lk->name = name; 00016 lk->locked = 0; 00017 lk->cpu = 0; 00018 } 00019 00020 // Acquire the lock. 00021 // Loops (spins) until the lock is acquired. 00022 // Holding a lock for a long time may cause 00023 // other CPUs to waste time spinning to acquire it. 00024 void 00025 acquire(struct spinlock *lk) 00026 { 00027 pushcli(); // disable interrupts to avoid deadlock. 00028 if(holding(lk)) 00029 panic("acquire"); 00030 00031 // The xchg is atomic. 00032 // It also serializes, so that reads after acquire are not 00033 // reordered before it. 00034 while(xchg(&lk->locked, 1) != 0) 00035 ; 00036 00037 // Record info about lock acquisition for debugging. 00038 lk->cpu = cpu; 00039 getcallerpcs(&lk, lk->pcs); 00040 } 00041 00042 // Release the lock. 00043 void 00044 release(struct spinlock *lk) 00045 { 00046 if(!holding(lk)) 00047 panic("release"); 00048 00049 lk->pcs[0] = 0; 00050 lk->cpu = 0; 00051 00052 // The xchg serializes, so that reads before release are 00053 // not reordered after it. The 1996 PentiumPro manual (Volume 3, 00054 // 7.2) says reads can be carried out speculatively and in 00055 // any order, which implies we need to serialize here. 00056 // But the 2007 Intel 64 Architecture Memory Ordering White 00057 // Paper says that Intel 64 and IA-32 will not move a load 00058 // after a store. So lock->locked = 0 would work here. 00059 // The xchg being asm volatile ensures gcc emits it after 00060 // the above assignments (and after the critical section). 00061 xchg(&lk->locked, 0); 00062 00063 popcli(); 00064 } 00065 00066 // Record the current call stack in pcs[] by following the %ebp chain. 00067 void 00068 getcallerpcs(void *v, uint pcs[]) 00069 { 00070 uint *ebp; 00071 int i; 00072 00073 ebp = (uint*)v - 2; 00074 for(i = 0; i < 10; i++){ 00075 if(ebp == 0 || ebp < (uint*)KERNBASE || ebp == (uint*)0xffffffff) 00076 break; 00077 pcs[i] = ebp[1]; // saved %eip 00078 ebp = (uint*)ebp[0]; // saved %ebp 00079 } 00080 for(; i < 10; i++) 00081 pcs[i] = 0; 00082 } 00083 00084 // Check whether this cpu is holding the lock. 00085 int 00086 holding(struct spinlock *lock) 00087 { 00088 return lock->locked && lock->cpu == cpu; 00089 } 00090 00091 00092 // Pushcli/popcli are like cli/sti except that they are matched: 00093 // it takes two popcli to undo two pushcli. Also, if interrupts 00094 // are off, then pushcli, popcli leaves them off. 00095 00096 void 00097 pushcli(void) 00098 { 00099 int eflags; 00100 00101 eflags = readeflags(); 00102 cli(); 00103 if(cpu->ncli++ == 0) 00104 cpu->intena = eflags & FL_IF; 00105 } 00106 00107 void 00108 popcli(void) 00109 { 00110 if(readeflags()&FL_IF) 00111 panic("popcli - interruptible"); 00112 if(--cpu->ncli < 0) 00113 panic("popcli"); 00114 if(cpu->ncli == 0 && cpu->intena) 00115 sti(); 00116 } 00117