当前位置: 首页 > article >正文

linux atomic 原子变量操作

原子操作是指指令以原子的方式操作,执行过程不会被打断。linux内核提供了atomic_t类型的原子变量,它的实现依赖于不同的体系结构。

include/linux/types.h

typedef struct {

int counter;

} atomic_t;

#ifdef CONFIG_64BIT

typedef struct {

long counter;

} atomic64_t;

#endif

ARM使用ldrex和strex指令来保证操作的原子性

ldrex Rt,[Rn] 把Rn寄存器指向内存地址的内容加载到Rt寄存器中

strex Rd,Rt,[Rn] 把Rt寄存器的值保存到Rn寄存器指向的内存地址中,Rd保存更新的结果,0表示更新成功,1:表示失败。

下面分析ARM中原子操作实现,其中涉及到arm内嵌汇编的一些内容,大家可以先简单查阅下内嵌汇编的内容,本文这里默认大家熟悉这些内容。

#define ATOMIC_OP(op, c_op, asm_op)					\
static inline void atomic_##op(int i, atomic_t *v)			\
{									\
	unsigned long tmp;						\
	int result;							\
									\
	prefetchw(&v->counter);						\
	__asm__ __volatile__("@ atomic_" #op "\n"			\
"1:	ldrex	%0, [%3]\n"						\
"	" #asm_op "	%0, %0, %4\n"					\
"	strex	%1, %0, [%3]\n"						\
"	teq	%1, #0\n"						\
"	bne	1b"							\
	: "=&r" (result), "=&r" (tmp), "+Qo" (v->counter)		\
	: "r" (&v->counter), "Ir" (i)					\
	: "cc");							\
}	
#define ATOMIC_OP_RETURN(op, c_op, asm_op)				\
static inline int atomic_##op##_return(int i, atomic_t *v)		\
{									\
	unsigned long tmp;						\
	int result;							\
									\
	smp_mb();							\
	prefetchw(&v->counter);						\
									\
	__asm__ __volatile__("@ atomic_" #op "_return\n"		\
"1:	ldrex	%0, [%3]\n"						\
"	" #asm_op "	%0, %0, %4\n"					\
"	strex	%1, %0, [%3]\n"						\
"	teq	%1, #0\n"						\
"	bne	1b"							\
	: "=&r" (result), "=&r" (tmp), "+Qo" (v->counter)		\
	: "r" (&v->counter), "Ir" (i)					\
	: "cc");							\
									\
	smp_mb();							\
									\
	return result;							\
	/*返回原子变量v的旧值*/
}
static inline int atomic_cmpxchg(atomic_t *ptr, int old, int new)
{
	int oldval;
	unsigned long res;

	smp_mb();
	prefetchw(&ptr->counter);

	do {
		__asm__ __volatile__("@ atomic_cmpxchg\n"
		"ldrex	%1, [%3]\n"   /*存放ptr->counter值到oldval*/
		"mov	%0, #0\n"	  /*res=0*/
		"teq	%1, %4\n"     /*测试oldval(ptr->counter值)和old值是否相等*/
		"strexeq %0, %5, [%3]\n" /*如果相等则将new赋值给ptr->counter,最终将strex结果存放到res中*/
		    : "=&r" (res), "=&r" (oldval), "+Qo" (ptr->counter)
		    : "r" (&ptr->counter), "Ir" (old), "r" (new)
		    : "cc");
	} while (res); /*res!=0表示独占访问失败,继续尝试*/

	smp_mb();

	return oldval;
}
static inline int __atomic_add_unless(atomic_t *v, int a, int u)
{
	int oldval, newval;
	unsigned long tmp;

	smp_mb();
	prefetchw(&v->counter);

	__asm__ __volatile__ ("@ atomic_add_unless\n"
"1:	ldrex	%0, [%4]\n" /*将v->counter赋值给oldval*/
"	teq	%0, %5\n"	    /*测试oldval值和u是否相等*/
"	beq	2f\n"			/*相等则不做任何操作,跳转到2初*/
"	add	%1, %0, %6\n"   /*newval=oldval+a*/
"	strex	%2, %1, [%4]\n" /*v->counter=newval*/
"	teq	%2, #0\n"	/*测试独占访问是否成功,失败跳转到1处*/
"	bne	1b\n"
"2:"
	: "=&r" (oldval), "=&r" (newval), "=&r" (tmp), "+Qo" (v->counter)
	: "r" (&v->counter), "r" (u), "r" (a)
	: "cc");

	if (oldval != u)
		smp_mb();

	return oldval; /*返回旧值*/
}

#define ATOMIC_OPS(op, c_op, asm_op) \

ATOMIC_OP(op, c_op, asm_op) \

ATOMIC_OP_RETURN(op, c_op, asm_op)

/*atomic_add,atomic_add_return*/

ATOMIC_OPS(add, +=, add)

/*atomic_sub,atomic_sub_return*/

ATOMIC_OPS(sub, -=, sub)

#undef ATOMIC_OPS

#undef ATOMIC_OP_RETURN

#undef ATOMIC_OP

#define atomic_xchg(v, new) (xchg(&((v)->counter), new))

/*下面的宏定义都是依赖atomic_add,atomic_add_return,atomic_sub,atomic_sub_return的实现*/

#define atomic_inc(v) atomic_add(1, v)

#define atomic_dec(v) atomic_sub(1, v)

#define atomic_inc_and_test(v) (atomic_add_return(1, v) == 0)

#define atomic_dec_and_test(v) (atomic_sub_return(1, v) == 0)

#define atomic_inc_return(v) (atomic_add_return(1, v))

#define atomic_dec_return(v) (atomic_sub_return(1, v))

#define atomic_sub_and_test(i, v) (atomic_sub_return(i, v) == 0)

#define atomic_add_negative(i,v) (atomic_add_return(i, v) < 0)


http://www.kler.cn/news/317049.html

相关文章:

  • 【Python报错已解决】AttributeError: ‘WindowsPath‘ object has no attribute ‘rstrip‘
  • 生成式AI:ChatGPT及其在各行业的应用前景
  • git学习报告
  • 深入探索迭代器模式的原理与应用
  • 从零开始写一个建立FAT32文件系统程序
  • MFC - 复杂控件_2
  • 【安装教程】Windows环境下Apache Jena Fuseki的安装与配置
  • qt-C++笔记之作用等同的宏和关键字
  • 模拟电路工程师面试题
  • 如何解决npm下载Puppeteer卡死的问题
  • YOLOv9改进策略【注意力机制篇】| 2024 SCI TOP FCAttention 即插即用注意力模块,增强局部和全局特征信息交互
  • Java面试指南(基础篇)
  • 如何选择适合的编程工具提高工作效率
  • Android Studio 真机USB调试运行频繁掉线问题
  • Linux:进程状态和优先级
  • 如何进行「精准测试」?
  • 【C++指南】C++中nullptr的深入解析
  • SSL 最长签发时间是多久?
  • JUC高并发编程1:JUC概述
  • 基于flask常见trick——unicode进制编码绕过
  • JavaEE: 深入探索TCP网络编程的奇妙世界(六)
  • PCL 基于kd树快速删除点云中重叠的点
  • AWS EKS 中的负载均衡和 TLS 配置:全面指南
  • 【二分算法】模板总结
  • QT菜单之快捷菜单设计
  • 解决方案:spark数据进行加工转换后,进行数据存储的时候,发现数据行为空
  • STM32如何修改外部晶振频率和主频
  • 用递归函数实现汉诺塔游戏
  • 使用命令行 (Anaconda Prompt)
  • Spring Boot | 使用 `@Scheduled`: 定时任务的实现与优化