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
spinlock.c
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 
 All Data Structures