自旋锁(Spinlock)加锁过程实现(arm平台)

来源:互联网 发布:淘宝店铺需要的软件 编辑:程序博客网 时间:2024/05/16 07:16
Spinlock,中文译名为“自旋锁”。是专为防止多处理器并发而引入的一种锁.
1.Spinlock初始化
    如:spin_lock_init(&logbuf_lock),

spin_lock_init(&logbuf_lock);等价于

ogbuf_lock=(spinlock_t){.raw_lock={0},…..};

其实就是把raw_lock成员初始化为0

2.加锁

#definespin_lock(lock)                                       _spin_lock(lock)

->

void__lockfunc _spin_lock(spinlock_t *lock)

{

             preempt_disable();// 空函数

             spin_acquire(&lock->dep_map,0, 0, _RET_IP_);

             _raw_spin_lock(lock);

}

->

# define_raw_spin_lock(lock)                          __raw_spin_lock(&(lock)->raw_lock)

->

staticinline void __raw_spin_lock(raw_spinlock_t *lock)

{

             unsigned long tmp;

             __asm__ __volatile__(//__asm__用于指示编译器在此插入汇编语句,__volatile__用于告诉编译器,严禁将此处的汇编语句与其它的语句重组合优化。即:原原本本按原来的样子处理这这里的汇编

"1:        ldrex    %0,[%1]\n"//lock->lock放在 tmp里,并且设置&lock->lock这个内存地址为独占访问

"           teq       %0,#0\n" //测试lock_lock是否为0,影响标志位z

#ifdefCONFIG_CPU_32v6K

"           wfene\n"

#endif

"           strexeq             %0, %2, [%1]\n" //如果lock_lock0,并且是独占访问这个内存,就向lock->lock里写入1,并向tmp返回0,同时清除独占标记

如果lock_lock不是0,tmp返回值就是1;

"           teqeq   %0, #0\n" //测试strexeq语句的执行结果

"           bne      1b"//,如果成功(z)结束,否则,跳转到1标号继续执行

             : "=&r" (tmp)

             : "r"(&lock->lock), "r" (1)

             : "cc");

             smp_mb();

//#define smp_mb()  dmb() #define dmb() __asm__ __volatile__("" : : : "memory")再加入内存屏障

}

上述代码关键在于LDREXSTREX指令的应用。DREXSTREX指令是在V6以后才出现的,代替了V6以前的swp指令。可以让bus监控LDREXSTREX指令之间有无其它CPUDMA来存取过这个地址,若有的话STREX指令的第一个寄存器里设置为1(动作失败),若没有,指令的第一个寄存器里设置为0(动作成功)。

不仅是自旋锁用到LDREXSTREX指令,信号量的实现也是利用LDREXSTREX指令来实现的。

  spin_lock(lock)其实就是测试lock->raw_lock.lock是否为0(未加锁),如果是0则修改为1(加锁);如果不是0则一直循环测试,直到lock->raw_lock.lock变为0


原创粉丝点击