JOS中 "spinlock" 的实现
-- from wikipedia
XCHG instruction Swaps data between two registers or a register and memory location.
LOCK汇编指令用于封锁总线.
static inline uint32_t
xchg(volatile uint32_t *addr, uint32_t newval)
{
uint32_t result;
// The + in "+m" denotes a read-modify-write operand.
asm volatile("lock; xchgl %0, %1" :
"+m" (*addr), "=a" (result) :
"1" (newval) :
"cc");
return result;
}
每次都会返回addr指向地址处原来的值.
于是乎,在JOS中,spinlock的实现如下:
./kern/spinlock.h 这里利用结构体struct spinlock来抽象封装spinlock.
实质上,spinlock是个全局变量.这里具体的就是./kern/spinlock.h 中的全局变量结构体
extern struct spinlock kernel_lock.
// Mutual exclusion lock.
struct spinlock {
unsigned locked; // Is the lock held?
};
void __spin_initlock(struct spinlock *lk, char *name);
void spin_lock(struct spinlock *lk);
void spin_unlock(struct spinlock *lk);
#define spin_initlock(lock) __spin_initlock(lock, #lock)
extern struct spinlock kernel_lock;
static inline void
lock_kernel(void)
{
spin_lock(&kernel_lock);
}
static inline void
unlock_kernel(void)
{
spin_unlock(&kernel_lock);
// Normally we wouldn't need to do this, but QEMU only runs
// one CPU at a time and has a long time-slice. Without the
// pause, this CPU is likely to reacquire the lock before
// another CPU has even been given a chance to acquire it.
asm volatile("pause");
}
// Mutual exclusion spin locks.
// The big kernel lock
struct spinlock kernel_lock = {
#ifdef DEBUG_SPINLOCK
.name = "kernel_lock"
#endif
};
spinlock锁的初始化
void
__spin_initlock(struct spinlock *lk, char *name)
{
lk->locked = 0;
}
// Acquire the lock.
// Loops (spins) until the lock is acquired.
// Holding a lock for a long time may cause
// other CPUs to waste time spinning to acquire it.
void
spin_lock(struct spinlock *lk)
{
// The xchg is atomic.
// It also serializes, so that reads after acquire are not
// reordered before it.
while (xchg(&lk->locked, 1) != 0)
asm volatile ("pause");
}
// Release the lock.
void
spin_unlock(struct spinlock *lk)
{
// The xchg serializes, so that reads before release are
// not reordered after it. The 1996 PentiumPro manual (Volume 3,
// 7.2) says reads can be carried out speculatively and in
// any order, which implies we need to serialize here.
// But the 2007 Intel 64 Architecture Memory Ordering White
// Paper says that Intel 64 and IA-32 will not move a load
// after a store. So lock->locked = 0 would work here.
// The xchg being asm volatile ensures gcc emits it after
// the above assignments (and after the critical section).
xchg(&lk->locked, 0);
}
原理还是很简单的,只是基于汇编层次的全局变量的busy waiting.
春节, 快乐