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

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



你可能感兴趣的:(linux嵌入式开发)