linux的原子操作实现,首先是基本数据结构的定义
typedef struct {
int counter;
} atomic_t;
操作集
#define atomic_dec_return(v) atomic_sub_return(1, (v))
#define atomic_inc_return(v) atomic_add_return(1, (v))
#define atomic64_dec_return(v) atomic64_sub_return(1, (v))
#define atomic64_inc_return(v) atomic64_add_return(1, (v))
#define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0)
#define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0)
#define atomic_inc_and_test(v) (atomic_add_return(1, (v)) == 0)
#define atomic64_sub_and_test(i,v) (atomic64_sub_return((i), (v)) == 0)
#define atomic64_dec_and_test(v) (atomic64_sub_return(1, (v)) == 0)
#define atomic64_inc_and_test(v) (atomic64_add_return(1, (v)) == 0)
#define atomic_add(i,v) atomic_add_return((i), (v))
#define atomic_sub(i,v) atomic_sub_return((i), (v))
#define atomic_inc(v) atomic_add(1, (v))
#define atomic_dec(v) atomic_sub(1, (v))
#define atomic64_add(i,v) atomic64_add_return((i), (v))
#define atomic64_sub(i,v) atomic64_sub_return((i), (v))
#define atomic64_inc(v) atomic64_add(1, (v))
#define atomic64_dec(v) atomic64_sub(1, (v))
下面来看看,其中几个操作的实现
#define atomic_add_negative(i,v) (atomic_add_return(i, v) < 0)
#ifdef CONFIG_SMP
#error SMP not supported on pre-ARMv6 CPUs
#endif
static inline int atomic_add_return(int i, atomic_t *v)
{
unsigned long flags;
int val;
raw_local_irq_save(flags);
val = v->counter;
v->counter = val += i;
raw_local_irq_restore(flags);
return val;
}
#define atomic_add(i, v) (void) atomic_add_return(i, v)
在pre-ARMv6(不支持smp)的硬件上,原子性通过关中断来保证的
还有通过CMPXCHG系列的指令来实现原子操作(IA64)
#define atomic_add(i,v) atomic_add_return((i), (v))
#define atomic_add_return(i,v)
({
int __ia64_aar_i = (i);
(__builtin_constant_p(i)
&& ( (__ia64_aar_i == 1) || (__ia64_aar_i == 4)
|| (__ia64_aar_i == 8) || (__ia64_aar_i == 16)
|| (__ia64_aar_i == -1) || (__ia64_aar_i == -4)
|| (__ia64_aar_i == -8) || (__ia64_aar_i == -16)))
? ia64_fetch_and_add(__ia64_aar_i, &(v)->counter)
: ia64_atomic_add(__ia64_aar_i, v);
})
最终调用的是:
#define ia64_cmpxchg1_acq(ptr, new, old)
({
__u64 ia64_intri_res;
asm volatile ("mov ar.ccv=%0;;" :: "rO"(old));
asm volatile ("cmpxchg1.acq %0=[%1],%2,ar.ccv":
"=r"(ia64_intri_res) : "r"(ptr), "r"(new) : "memory");
ia64_intri_res;
})
对于支持smp的硬件,实现有所不一样,看一看x86的实现:
/*** atomic_add_negative - add and test if negative
* @i: integer value to add
* @v: pointer of type atomic_t
*
* Atomically adds @i to @v and returns true
* if the result is negative, or false when
* result is greater than or equal to zero.
*/
static inline int atomic_add_negative(int i, atomic_t *v)
{
unsigned char c;
asm volatile(LOCK_PREFIX "addl %2,%0; sets %1"
: "+m" (v->counter), "=qm" (c)
: "ir" (i) : "memory");
return c;
}
关于宏LOCK_PREFIX以及具体实现原理,可以参见http://blog.csdn.net/vividonly/article/details/6599502,写的很详细,另外这篇博客还有介绍原子位操作,赞一个