ven*_*s.w 11 linux x86 assembly kernel linux-kernel
这是我的自旋锁实现,但它似乎无法保护关键代码.我的实施有问题吗?
static __inline__ int xchg_asm(int* lock, int val)
{
int ret;
__asm__ __volatile__(
LOCK "movl (%1),%%eax;
xchg (%1),%2;
movl %%eax, %0" :"=m" (ret) :"d"(lock), "c"(val)
);
return ret;
}
void spin_init(spinlock_t* sl)
{
sl->val = 0;
}
void spin_lock(spinlock_t* sl)
{
int ret;
do {
ret = xchg_asm(&(sl->val), 1);
} while ( ret==0 );
}
void spin_unlock(spinlock_t* sl)
{
xchg_asm(&(sl->val), 0);
}
Run Code Online (Sandbox Code Playgroud)
Lai*_*han 11
您的代码等于:
static __inline__ int xchg_asm(int* lock, int val) {
int save_old_value_at_eax;
save_old_value_at_eax = *lock; /* with a wrong lock prefix */
xchg *lock with val and discard the original value of *lock.
return save_old_value_at_eax; /* but it not the real original value of *lock */
}
Run Code Online (Sandbox Code Playgroud)
你可以从代码中看到,save_old_value_at_eax当cpu执行xchg时,没有真正的原始值.您应该通过xchg指令获取旧/原始值,而不是在执行xchg之前保存它.("这不是真正的老/初始值"是指,如果另一个CPU占用锁后,该CPU节省的价值,但该CPU执行XCHG指令之前,这个CPU会得到错误的旧值,并认为它采取了锁定成功,因此,两个CPU同时进入CS).你拆散了一对读-修改-写指令三条指令,整个三个指令不是原子(即使你移动锁定前缀XCHG).
我猜你认为锁定前缀将锁定WHOLE三条指令,但实际上锁定前缀只能用于它附加的唯一指令(并非所有指令都可以附加)而且我们在SMP上不需要锁定前缀用于xchg .引自linux_kernel_src/arch/x86 // include/asm/cmpxchg.h
/*
* Note: no "lock" prefix even on SMP: xchg always implies lock anyway.
* Since this is generally used to protect other memory information, we
* use "asm volatile" and "memory" clobbers to prevent gcc from moving
* information around.
*/
Run Code Online (Sandbox Code Playgroud)
我的建议: