原子操作是指指令以原子的方式操作,执行过程不会被打断。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)