2 * Many similar implementations exist. See for example libwsbm
3 * or the linux kernel include/atomic.h
5 * No copyright claimed on this file.
12 /* Favor OS-provided implementations.
14 * Where no OS-provided implementation is available, fall back to
15 * locally coded assembly, compiler intrinsic or ultimately a
16 * mutex-based implementation.
19 #define PIPE_ATOMIC_OS_SOLARIS
20 #elif defined(_MSC_VER)
21 #define PIPE_ATOMIC_MSVC_INTRINSIC
22 #elif defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 401)
23 #define PIPE_ATOMIC_GCC_INTRINSIC
24 #elif (defined(__GNUC__) && defined(__i386__))
25 #define PIPE_ATOMIC_ASM_GCC_X86
26 #elif (defined(__GNUC__) && defined(__x86_64__))
27 #define PIPE_ATOMIC_ASM_GCC_X86_64
29 #error "Unsupported platform"
33 #if defined(PIPE_ATOMIC_ASM_GCC_X86_64)
34 #define PIPE_ATOMIC "GCC x86_64 assembly"
40 #define p_atomic_set(_v, _i) (*(_v) = (_i))
41 #define p_atomic_read(_v) (*(_v))
44 p_atomic_dec_zero(int32_t *v
)
48 __asm__
__volatile__("lock; decl %0; sete %1":"+m"(*v
), "=qm"(c
)
55 p_atomic_inc(int32_t *v
)
57 __asm__
__volatile__("lock; incl %0":"+m"(*v
));
61 p_atomic_dec(int32_t *v
)
63 __asm__
__volatile__("lock; decl %0":"+m"(*v
));
67 p_atomic_inc_return(int32_t *v
)
69 return __sync_add_and_fetch(v
, 1);
73 p_atomic_dec_return(int32_t *v
)
75 return __sync_sub_and_fetch(v
, 1);
79 p_atomic_cmpxchg(int32_t *v
, int32_t old
, int32_t _new
)
81 return __sync_val_compare_and_swap(v
, old
, _new
);
88 #endif /* PIPE_ATOMIC_ASM_GCC_X86_64 */
91 #if defined(PIPE_ATOMIC_ASM_GCC_X86)
93 #define PIPE_ATOMIC "GCC x86 assembly"
99 #define p_atomic_set(_v, _i) (*(_v) = (_i))
100 #define p_atomic_read(_v) (*(_v))
102 static inline boolean
103 p_atomic_dec_zero(int32_t *v
)
107 __asm__
__volatile__("lock; decl %0; sete %1":"+m"(*v
), "=qm"(c
)
114 p_atomic_inc(int32_t *v
)
116 __asm__
__volatile__("lock; incl %0":"+m"(*v
));
120 p_atomic_dec(int32_t *v
)
122 __asm__
__volatile__("lock; decl %0":"+m"(*v
));
125 static inline int32_t
126 p_atomic_inc_return(int32_t *v
)
128 return __sync_add_and_fetch(v
, 1);
131 static inline int32_t
132 p_atomic_dec_return(int32_t *v
)
134 return __sync_sub_and_fetch(v
, 1);
137 static inline int32_t
138 p_atomic_cmpxchg(int32_t *v
, int32_t old
, int32_t _new
)
140 return __sync_val_compare_and_swap(v
, old
, _new
);
151 /* Implementation using GCC-provided synchronization intrinsics
153 #if defined(PIPE_ATOMIC_GCC_INTRINSIC)
155 #define PIPE_ATOMIC "GCC Sync Intrinsics"
161 #define p_atomic_set(_v, _i) (*(_v) = (_i))
162 #define p_atomic_read(_v) (*(_v))
164 static inline boolean
165 p_atomic_dec_zero(int32_t *v
)
167 return (__sync_sub_and_fetch(v
, 1) == 0);
171 p_atomic_inc(int32_t *v
)
173 (void) __sync_add_and_fetch(v
, 1);
177 p_atomic_dec(int32_t *v
)
179 (void) __sync_sub_and_fetch(v
, 1);
182 static inline int32_t
183 p_atomic_inc_return(int32_t *v
)
185 return __sync_add_and_fetch(v
, 1);
188 static inline int32_t
189 p_atomic_dec_return(int32_t *v
)
191 return __sync_sub_and_fetch(v
, 1);
194 static inline int32_t
195 p_atomic_cmpxchg(int32_t *v
, int32_t old
, int32_t _new
)
197 return __sync_val_compare_and_swap(v
, old
, _new
);
208 /* Unlocked version for single threaded environments, such as some
209 * windows kernel modules.
211 #if defined(PIPE_ATOMIC_OS_UNLOCKED)
213 #define PIPE_ATOMIC "Unlocked"
215 #define p_atomic_set(_v, _i) (*(_v) = (_i))
216 #define p_atomic_read(_v) (*(_v))
217 #define p_atomic_dec_zero(_v) ((boolean) --(*(_v)))
218 #define p_atomic_inc(_v) ((void) (*(_v))++)
219 #define p_atomic_dec(_v) ((void) (*(_v))--)
220 #define p_atomic_inc_return(_v) ((*(_v))++)
221 #define p_atomic_dec_return(_v) ((*(_v))--)
222 #define p_atomic_cmpxchg(_v, old, _new) (*(_v) == old ? *(_v) = (_new) : *(_v))
227 #if defined(PIPE_ATOMIC_MSVC_INTRINSIC)
229 #define PIPE_ATOMIC "MSVC Intrinsics"
233 #pragma intrinsic(_InterlockedIncrement)
234 #pragma intrinsic(_InterlockedDecrement)
235 #pragma intrinsic(_InterlockedCompareExchange)
241 #define p_atomic_set(_v, _i) (*(_v) = (_i))
242 #define p_atomic_read(_v) (*(_v))
244 static inline boolean
245 p_atomic_dec_zero(int32_t *v
)
247 return _InterlockedDecrement((long *)v
) == 0;
251 p_atomic_inc(int32_t *v
)
253 _InterlockedIncrement((long *)v
);
256 static inline int32_t
257 p_atomic_inc_return(int32_t *v
)
259 return _InterlockedIncrement((long *)v
);
263 p_atomic_dec(int32_t *v
)
265 _InterlockedDecrement((long *)v
);
268 static inline int32_t
269 p_atomic_dec_return(int32_t *v
)
271 return _InterlockedDecrement((long *)v
);
274 static inline int32_t
275 p_atomic_cmpxchg(int32_t *v
, int32_t old
, int32_t _new
)
277 return _InterlockedCompareExchange((long *)v
, _new
, old
);
286 #if defined(PIPE_ATOMIC_OS_SOLARIS)
288 #define PIPE_ATOMIC "Solaris OS atomic functions"
296 #define p_atomic_set(_v, _i) (*(_v) = (_i))
297 #define p_atomic_read(_v) (*(_v))
299 static inline boolean
300 p_atomic_dec_zero(int32_t *v
)
302 uint32_t n
= atomic_dec_32_nv((uint32_t *) v
);
307 #define p_atomic_inc(_v) atomic_inc_32((uint32_t *) _v)
308 #define p_atomic_dec(_v) atomic_dec_32((uint32_t *) _v)
309 #define p_atomic_inc_return(_v) atomic_inc_32_nv((uint32_t *) _v)
310 #define p_atomic_dec_return(_v) atomic_dec_32_nv((uint32_t *) _v)
312 #define p_atomic_cmpxchg(_v, _old, _new) \
313 atomic_cas_32( (uint32_t *) _v, (uint32_t) _old, (uint32_t) _new)
323 #error "No pipe_atomic implementation selected"
328 #endif /* U_ATOMIC_H */