Chinaunix首页 | 论坛 | 博客
  • 博客访问: 211124
  • 博文数量: 24
  • 博客积分: 493
  • 博客等级: 下士
  • 技术积分: 245
  • 用 户 组: 普通用户
  • 注册时间: 2011-02-28 09:26
个人简介

WangFerry

文章分类

全部博文(24)

文章存档

2012年(8)

2011年(16)

分类:

2011-02-28 09:43:08

__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指令来实现的。

阅读(1936) | 评论(0) | 转发(0) |
0

上一篇:没有了

下一篇:notepad++ 右键关联

给主人留下些什么吧!~~