SylixOS armv8 原子操作
在SylixOS 中 armv8 原子操作分为32位和64位。
首先介绍32位
#define ATOMIC_OP_RETURN(op, c_op, asm_op) \
static LW_INLINE INT archAtomic##op (INT i, atomic_t *v) \
{ \
ULONG ulTemp; \
INT iResult; \
\
ARM_PREFETCH_W(&v->counter); \
\
__asm__ __volatile__( \
"1: ldxr %w0, %2 \n" \
" " #asm_op " %w0, %w0, %w3 \n" \
" stlxr %w1, %w0, %2 \n" \
" cbnz %w1, 1b \n" \
" dmb ish" \
: "=&r" (iResult), "=&r" (ulTemp), "+Q" (v->counter) \
: "Ir" (i) \
: "memory"); \
\
return (iResult); \
}
ATOMIC_OP_RETURN(Add, +=, add)
ATOMIC_OP_RETURN(Sub, -=, sub)
ATOMIC_OP_RETURN(And, &=, and)
ATOMIC_OP_RETURN(Or, |=, orr)
ATOMIC_OP_RETURN(Xor, ^=, eor)
原子操作和自旋锁增加代码基本一致,不同的是自旋锁只用到了add。 首先是ldxr命令,此命令是加载内存值到寄存器。这里说是32位数加减,和64位主要区别在于%w0 在armv8中规定x 代表寄存器64位,w代表32位寄存器。看armasm用户知道手册
对ldxr的介绍 如下图
ldxr命令保证对加载时候是原子操作。根据代码的含义是将v->counter中的值加载到iResult中。“asm_op” 根据原子操作的不同可能是add,sub,and,orr等。最后是执行stlxr命令,此命令是将数据写入到内存中。看armasm 用户指导手册对其介绍如下:
该命令也是支持32位和64位,在原子操作32位时使用的W1 ,W0
。根据代码的还难以stlxr首先将iResult写入到v->counter中。stlxr会把写入失败或者成功标志位写入到w1(ulTemp)中。cbnz命令就是判断这个标志位(ulTmep)来判断是否写入成功,如果写入失败返回到1:处重新开始执行代码。
在最后保证操作全部完成加入了 dmb ish 这个命令,dmb是arm中内存屏障的,前面的写入操作全部完成。
原子操作64位和32位完全一样,不同的是没用使用W
#define ATOMIC64_OP_RETURN(op, c_op, asm_op) \
static LW_INLINE INT64 archAtomic64##op (INT64 i, atomic64_t *v) \
{ \
ULONG ulTemp; \
INT64 i64Result; \
\
ARM_PREFETCH_W(&v->counter); \
\
__asm__ __volatile__( \
"1: ldxr %0, %2 \n" \
" " #asm_op " %0, %0, %3 \n" \
" stlxr %w1, %0, %2 \n" \
" cbnz %w1, 1b \n" \
" dmb ish" \
: "=&r" (i64Result), "=&r" (ulTemp), "+Q" (v->counter) \
: "Ir" (i) \
: "memory"); \
\
return (i64Result); \
}
ATOMIC64_OP_RETURN(Add, +=, add)
ATOMIC64_OP_RETURN(Sub, -=, sub)
ATOMIC64_OP_RETURN(And, &=, and)
ATOMIC64_OP_RETURN(Or, |=, orr)
ATOMIC64_OP_RETURN(Xor, ^=, eor)
参考文档《DUI0801C_armasm_user_guide.pdf》