__raw_spin_lock在ARM处理器上的完成
/******include/asm-arm/spinlock_types.h***/
typedef struct {
volatile unsigned int lock;
} raw_spinlock_t;
#define __RAW_SPIN_LOCK_UNLOCKED { 0 }
/******include/asm-arm/spinlock.h***/
#if __LINUX_ARM_ARCH__ < 6
#error SMP not supported on pre-ARMv6 CPUs //ARMv6后,才有多核ARM处理器
#endif
……
static inline void __raw_spin_lock(raw_spinlock_t *lock)
{
unsigned long tmp;
__asm__ __volatile__(
“1: ldrex%0, [%1]\n”
//取lock->lock放在 tmp里,而且设置&lock->lock这个内存地址为独占拜访
“teq %0, #0\n”
// 测验lock_lock是否为0,影响标志位z
#ifdef CONFIG_CPU_32v6K
“wfene\n”
#endif
“strexeq %0, %2, [%1]\n”
//假如lock_lock是0,而且是独占拜访这个内存,就向lock->lock里 写入1,并向tmp回来0,一起铲除独占符号
“teqeq %0, #0\n”
//如 果lock_lock是0,而且strexeq回来了0,表明加锁成功,回来
” bne 1b”
//如 果上面的条件(1:lock->lock里不为0,2:strexeq失利)有一个契合,就在原地打转
: “=&r” (tmp) //%0:输出放在tmp里,可所以恣意存放器
: “r” (&lock->lock), “r” (1)
//%1:取&lock->lock放在恣意存放 器,%2:恣意存放器放入1
: “cc”); //状况存放器可能会改动
smp_mb();
}
上述代码关键在于LDREX和STREX指令的使用。DREX和STREX指令是在V6今后才呈现的,替代了V6曾经的 swp指令。能够让bus监控LDREX和STREX指令之间有无其它CPU和DMA来存取过这个地址,若有的话STREX指令的第一个存放器里设置为 1(动作失利),若没有,指令的第一个存放器里设置为0(动作成功)。
不仅是自旋锁用到LDREX和STREX指令,信号量的完成也是使用LDREX和STREX指令来完成的。