当前位置:首页 > 嵌入式 > 嵌入式软件

作者:刘洪涛,华清远见嵌入式学院讲师。

本文主要以2.6.22.6内核分析Linux中spinlock在ARM及X86平台上的实现(不同版本的内核实现形式会有一些差异,但原理大致相同)。此处默认大家已经熟悉了spinlock的使用,重点解释容易引起迷惑的体系结构相关的实现部分。

一、spin_lock(lock)的实现

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

#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)

//如果配置了SMP或配置自旋锁调试功能

# include <linux/spinlock_api_smp.h>

#else //如果是单处理器且不配置自旋锁调试功能

# include <linux/spinlock_api_up.h>

#endif

……

#define spin_lock(lock) _spin_lock(lock)

1、如果是单处理器

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

#define _spin_lock(lock) __LOCK(lock)

#define __LOCK(lock) \

do { preempt_disable(); __acquire(lock); (void)(lock); } while (0)

(1)preempt_disable():禁止抢占

(2)__acquire(lock):在include/linux/compiler.h中有定义

#ifdef __CHECKER__

……

# define __acquire(x) __context__(x,1)

# define __release(x) __context__(x,-1)

#else

……

# define __acquires(x)

# define __releases(x)

这是一对用于sparse对代码检测的相互关联的函数定义,第一句表示要增加变量x的计数,增加量为1,第二句则正好相反,这个是用来函数编译的过程中。如果在代码中出现了不平衡的状况,那么在Sparse的检测中就会报警。如果要使用Sparse检测功能就需要安装sparse工具(参考相关安装方法),然后编译内核

#make zImage C=1 (C=1,只检测新编译的文件,C=2是查所有文件)

Sparse会定义__CHECKER__,如果你没有使用sparse工具,__acquire(lock)则定义为空

(3)(void)(lock):通过插入一个变量本身的求值表达式,使编译器不再报警,如:“variable "lock" is defined but never used”。这种求值不会影响运行时的速度。

2、如果配置了SMP

/****include/linux/spinlock_api_smp.h中****/

void __lockfunc _spin_lock(spinlock_t *lock) __acquires(lock);

/***kernel/spinlock.c***/

void __lockfunc _spin_lock(spinlock_t *lock)

{

preempt_disable();

//关闭抢占

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

//自旋锁调试用,在没有定义自旋锁调试的时候是空函数

_raw_spin_lock(lock);

}

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

#ifdef CONFIG_DEBUG_SPINLOCK

extern void _raw_spin_lock(spinlock_t *lock);//在lib/spinlock_debug.c中实现

#else //smp情况

# define _raw_spin_lock(lock) __raw_spin_lock(&(lock)->raw_lock)

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

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

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

typedef struct {

unsigned int slock;

} raw_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("\n1:\t"

LOCK_PREFIX " ; decb %0\n\t"

// lock->slock减1

"jns 3f\n"

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

"2:\t"

"rep;nop\n\t"

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

"cmpb $0,%0\n\t"

"jle 2b\n\t"

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

"jmp 1b\n"

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

"3:\n\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]\n" // 向lock->lock里写0,解锁

#ifdef CONFIG_CPU_32v6K

" mcr p15, 0, %1, c7, c10, 4\n" /* 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。

“本文由华清远见http://www.embedu.org/index.htm提供”



华清远见

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

9月2日消息,不造车的华为或将催生出更大的独角兽公司,随着阿维塔和赛力斯的入局,华为引望愈发显得引人瞩目。

关键字: 阿维塔 塞力斯 华为

加利福尼亚州圣克拉拉县2024年8月30日 /美通社/ -- 数字化转型技术解决方案公司Trianz今天宣布,该公司与Amazon Web Services (AWS)签订了...

关键字: AWS AN BSP 数字化

伦敦2024年8月29日 /美通社/ -- 英国汽车技术公司SODA.Auto推出其旗舰产品SODA V,这是全球首款涵盖汽车工程师从创意到认证的所有需求的工具,可用于创建软件定义汽车。 SODA V工具的开发耗时1.5...

关键字: 汽车 人工智能 智能驱动 BSP

北京2024年8月28日 /美通社/ -- 越来越多用户希望企业业务能7×24不间断运行,同时企业却面临越来越多业务中断的风险,如企业系统复杂性的增加,频繁的功能更新和发布等。如何确保业务连续性,提升韧性,成...

关键字: 亚马逊 解密 控制平面 BSP

8月30日消息,据媒体报道,腾讯和网易近期正在缩减他们对日本游戏市场的投资。

关键字: 腾讯 编码器 CPU

8月28日消息,今天上午,2024中国国际大数据产业博览会开幕式在贵阳举行,华为董事、质量流程IT总裁陶景文发表了演讲。

关键字: 华为 12nm EDA 半导体

8月28日消息,在2024中国国际大数据产业博览会上,华为常务董事、华为云CEO张平安发表演讲称,数字世界的话语权最终是由生态的繁荣决定的。

关键字: 华为 12nm 手机 卫星通信

要点: 有效应对环境变化,经营业绩稳中有升 落实提质增效举措,毛利润率延续升势 战略布局成效显著,战新业务引领增长 以科技创新为引领,提升企业核心竞争力 坚持高质量发展策略,塑强核心竞争优势...

关键字: 通信 BSP 电信运营商 数字经济

北京2024年8月27日 /美通社/ -- 8月21日,由中央广播电视总台与中国电影电视技术学会联合牵头组建的NVI技术创新联盟在BIRTV2024超高清全产业链发展研讨会上宣布正式成立。 活动现场 NVI技术创新联...

关键字: VI 传输协议 音频 BSP

北京2024年8月27日 /美通社/ -- 在8月23日举办的2024年长三角生态绿色一体化发展示范区联合招商会上,软通动力信息技术(集团)股份有限公司(以下简称"软通动力")与长三角投资(上海)有限...

关键字: BSP 信息技术
关闭
关闭