微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > 分析Linux中Spinlock在ARM及X86平台上的实现

分析Linux中Spinlock在ARM及X86平台上的实现

时间:12-08 来源:互联网 点击:

_spinlock_t;

  #define __RAW_SPIN_LOCK_UNLOCKED { 1 }

  /******include/asm-i386/spinlock.h***/

  static inline void __raw_spin_lock(raw_spinlock_t *lock)

  {

  asm volatile("1:\t"

  LOCK_PREFIX " ; decb %0\t"

  // lock->slock减1

  "jns 3f"

  //如果不为负.跳转到3f.3f后面没有任何指令,即为退出

  "2:\t"

  "rep;nop\t"

  //重复执行nop.nop是x86的小延迟函数

  "cmpb $0,%0\t"

  "jle 2b\t"

  //如果lock->slock不大于0,跳转到标号2,即继续重复执行nop

  "jmp 1b"

  //如果lock->slock大于0,跳转到标号1,重新判断锁的slock成员

  "3:\t"

  : "+m" (lock->slock) : : "memory");

  }

  在多处理器环境中 LOCK_PREFIX 实际被定义为 “lock”前缀。x86 处理器使用“lock”前缀的方式提供了在指令执行期间对总线加锁的手段。芯片上有一条引线 LOCK,如果在一条汇编指令(ADD, ADC, AND, BTC, BTR, BTS, CMPXCHG, CMPXCH8B, DEC, INC, NEG, NOT, OR, SBB, SUB, XOR, XADD, XCHG)前加上“lock” 前缀,经过汇编后的机器代码就使得处理器执行该指令时把引线 LOCK 的电位拉低,从而把总线锁住,这样其它处理器或使用DMA的外设暂时无法通过同一总线访问内存。

  jns 汇编指令检查 EFLAGS 寄存器的 SF(符号)位,如果为 0,说明 slock 原来的值为 1,则线程获得锁,然后跳到标签 3 的位置结束本次函数调用。如果 SF 位为 1,说明 slock 原来的值为 0 或负数,锁已被占用。那么线程转到标签 2 处不断测试 slock 与 0 的大小关系,假如 slock 小于或等于 0,跳转到标签 2 的位置继续忙等待;假如 slock 大于 0,说明锁已被释放,则跳转到标签 1 的位置重新申请锁。

  二、spin_unlock(lock)的实现

  /***include/linux/spinlock.h***/

  #if defined(CONFIG_DEBUG_SPINLOCK) || defined(CONFIG_PREEMPT) || \

  !defined(CONFIG_SMP)

  # define spin_unlock(lock) _spin_unlock(lock)

  ……

  #else

  # define spin_unlock(lock) \

  do {__raw_spin_unlock((lock)->raw_lock); __release(lock); } while (0)

  1、 如果是单处理器

  /****include/linux/spinlock_api_up.h****/

  #define _spin_unlock(lock) __UNLOCK(lock)

  #define __UNLOCK(lock) \

  do { preempt_enable(); __release(lock); (void)(lock); } while (0)

  完成前文的获取锁的逆过程

  2、如果配置了SMP

  # define spin_unlock(lock) \

  do {__raw_spin_unlock((lock)->raw_lock); __release(lock); } while (0)

  3、__raw_spin_unlock在ARM处理器上的实现

  /******include/asm-arm/spinlock.h***/

  static inline void __raw_spin_unlock(raw_spinlock_t *lock)

  {

  smp_mb();

  __asm__ __volatile__(

  " str %1, [%0]" // 向lock->lock里写0,解锁

  #ifdef CONFIG_CPU_32v6K

  " mcr p15, 0, %1, c7, c10, 4" /* DSB */

  " sev"

  #endif

  :

  : "r" (lock->lock), "r" (0) //%0取lock->lock放在任意寄存器,%1:任意寄存器放入0

  : "cc");

  }

  __raw_spin_unlock只是简单的给lock->lock里写0。

  4、__raw_spin_unlock在X86处理器上的实现

  /***include/asm-i386/spinlock.h***/

  static inline void __raw_spin_unlock(raw_spinlock_t *lock)

  {

  asm volatile("movb $1,%0" : "+m" (lock->slock) :: "memory");

  }

  __raw_spin_unlock 函数仅仅执行一条汇编指令:将lock-> slock 置为 1。

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top