分类: LINUX
2014-06-24 09:44:46
2.6.32中
#define spin_lock_irqsave(lock, flags) \
do { \
typecheck(unsigned long, flags); \
flags = _spin_lock_irqsave(lock); \
} while (0)
最终走到流程
static inline unsigned long __spin_lock_irqsave(spinlock_t *lock)
{
unsigned long flags;
local_irq_save(flags);//保存调用之前的中断状态,然后关闭中断
preempt_disable();//禁止抢占
spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);//获取一个spinlock锁的访问权限
#ifdef CONFIG_LOCKDEP
LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock);
#else
_raw_spin_lock_flags(lock, &flags);//自旋部分
#endif
return flags;
}
自旋部分最终走到流程__ticket_spin_lock。
首先,自旋锁将整数拆为一个16位数,结构如下:
next | owner
其中的owner表示当前可以占用锁的序号,next表示想要占有锁所分配的序号,从小到大代表着一种顺序关系。next和owner的初始为0,代表 着锁处于空闲状态。
static __always_inline void __ticket_spin_lock(raw_spinlock_t *lock)
{
short inc = 0x0100;
asm volatile (
LOCK_PREFIX "xaddw %w0, %1\n" //这里锁住总线,获取当前锁的值,并将锁的next字段加1"1:\t""cmpb %h0, %b0\n\t" //比较获取的值next和owner是否相等,高位与低位是否相等,"je 2f\n\t" //相等,则加锁成功"rep ; nop\n\t" //随机延时"movb %1, %b0\n\t" //继续等待,会将锁的低位字段再赋值给保留值/* don't need lfence here, because loads are in-order */"jmp 1b\n" //向后跳转到标签1处"2:": "+Q" (inc), "+m" (lock->slock):: "memory", "cc");
}
我的疑问是,如果一直在自旋的话,顺序拿锁的方式,保证一定按加锁的顺序,获得锁,那由于中断长时间关闭,会导致NMI。
此外,在linux 实现的读写锁是读优先的,但是读者 no writer-consious, no order like spin-lock
因此,可能会让写者忙等。
static inline void __raw_write_lock(raw_rwlock_t *rw)
{
asm volatile(LOCK_PREFIX " subl %1,(%0)\n\t"
"jz 1f\n"
"call __write_lock_failed\n\t" //here is a loop
"1:\n"
::LOCK_PTR_REG (rw), "i" (RW_LOCK_BIAS) : "memory");
}
.align 4
.globl __write_lock_failed
__write_lock_failed:
" LOCK "addl $" RW_LOCK_BIAS_STR ",(%eax)
1: cmpl $" RW_LOCK_BIAS_STR ",(%eax)
jne 1b
" LOCK "subl $" RW_LOCK_BIAS_STR ",(%eax)
jnz __write_lock_failed
ret