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(_MSC_VER) && (defined(__i386__) || defined(_M_IX86))
23 #define PIPE_ATOMIC_ASM_MSVC_X86
24 #elif defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 401)
25 #define PIPE_ATOMIC_GCC_INTRINSIC
26 #elif (defined(__GNUC__) && defined(__i386__))
27 #define PIPE_ATOMIC_ASM_GCC_X86
28 #elif (defined(__GNUC__) && defined(__x86_64__))
29 #define PIPE_ATOMIC_ASM_GCC_X86_64
31 #error "Unsupported platform"
35 #if defined(PIPE_ATOMIC_ASM_GCC_X86_64)
36 #define PIPE_ATOMIC "GCC x86_64 assembly"
42 #define p_atomic_set(_v, _i) (*(_v) = (_i))
43 #define p_atomic_read(_v) (*(_v))
46 p_atomic_dec_zero(int32_t *v
)
50 __asm__
__volatile__("lock; decl %0; sete %1":"+m"(*v
), "=qm"(c
)
57 p_atomic_inc(int32_t *v
)
59 __asm__
__volatile__("lock; incl %0":"+m"(*v
));
63 p_atomic_dec(int32_t *v
)
65 __asm__
__volatile__("lock; decl %0":"+m"(*v
));
69 p_atomic_inc_return(int32_t *v
)
71 return __sync_add_and_fetch(v
, 1);
75 p_atomic_dec_return(int32_t *v
)
77 return __sync_sub_and_fetch(v
, 1);
81 p_atomic_cmpxchg(int32_t *v
, int32_t old
, int32_t _new
)
83 return __sync_val_compare_and_swap(v
, old
, _new
);
90 #endif /* PIPE_ATOMIC_ASM_GCC_X86_64 */
93 #if defined(PIPE_ATOMIC_ASM_GCC_X86)
95 #define PIPE_ATOMIC "GCC x86 assembly"
101 #define p_atomic_set(_v, _i) (*(_v) = (_i))
102 #define p_atomic_read(_v) (*(_v))
104 static inline boolean
105 p_atomic_dec_zero(int32_t *v
)
109 __asm__
__volatile__("lock; decl %0; sete %1":"+m"(*v
), "=qm"(c
)
116 p_atomic_inc(int32_t *v
)
118 __asm__
__volatile__("lock; incl %0":"+m"(*v
));
122 p_atomic_dec(int32_t *v
)
124 __asm__
__volatile__("lock; decl %0":"+m"(*v
));
127 static inline int32_t
128 p_atomic_inc_return(int32_t *v
)
130 return __sync_add_and_fetch(v
, 1);
133 static inline int32_t
134 p_atomic_dec_return(int32_t *v
)
136 return __sync_sub_and_fetch(v
, 1);
139 static inline int32_t
140 p_atomic_cmpxchg(int32_t *v
, int32_t old
, int32_t _new
)
142 return __sync_val_compare_and_swap(v
, old
, _new
);
153 /* Implementation using GCC-provided synchronization intrinsics
155 #if defined(PIPE_ATOMIC_GCC_INTRINSIC)
157 #define PIPE_ATOMIC "GCC Sync Intrinsics"
163 #define p_atomic_set(_v, _i) (*(_v) = (_i))
164 #define p_atomic_read(_v) (*(_v))
166 static inline boolean
167 p_atomic_dec_zero(int32_t *v
)
169 return (__sync_sub_and_fetch(v
, 1) == 0);
173 p_atomic_inc(int32_t *v
)
175 (void) __sync_add_and_fetch(v
, 1);
179 p_atomic_dec(int32_t *v
)
181 (void) __sync_sub_and_fetch(v
, 1);
184 static inline int32_t
185 p_atomic_inc_return(int32_t *v
)
187 return __sync_add_and_fetch(v
, 1);
190 static inline int32_t
191 p_atomic_dec_return(int32_t *v
)
193 return __sync_sub_and_fetch(v
, 1);
196 static inline int32_t
197 p_atomic_cmpxchg(int32_t *v
, int32_t old
, int32_t _new
)
199 return __sync_val_compare_and_swap(v
, old
, _new
);
210 /* Unlocked version for single threaded environments, such as some
211 * windows kernel modules.
213 #if defined(PIPE_ATOMIC_OS_UNLOCKED)
215 #define PIPE_ATOMIC "Unlocked"
217 #define p_atomic_set(_v, _i) (*(_v) = (_i))
218 #define p_atomic_read(_v) (*(_v))
219 #define p_atomic_dec_zero(_v) ((boolean) --(*(_v)))
220 #define p_atomic_inc(_v) ((void) (*(_v))++)
221 #define p_atomic_dec(_v) ((void) (*(_v))--)
222 #define p_atomic_inc_return(_v) ((*(_v))++)
223 #define p_atomic_dec_return(_v) ((*(_v))--)
224 #define p_atomic_cmpxchg(_v, old, _new) (*(_v) == old ? *(_v) = (_new) : *(_v))
229 /* Locally coded assembly for MSVC on x86:
231 #if defined(PIPE_ATOMIC_ASM_MSVC_X86)
233 #define PIPE_ATOMIC "MSVC x86 assembly"
239 #define p_atomic_set(_v, _i) (*(_v) = (_i))
240 #define p_atomic_read(_v) (*(_v))
242 static inline boolean
243 p_atomic_dec_zero(int32_t *v
)
249 lock dec dword ptr
[eax
]
257 p_atomic_inc(int32_t *v
)
261 lock inc dword ptr
[eax
]
266 p_atomic_dec(int32_t *v
)
270 lock dec dword ptr
[eax
]
274 static inline int32_t
275 p_atomic_cmpxchg(int32_t *v
, int32_t old
, int32_t _new
)
283 lock cmpxchg
[ecx
], edx
297 #if defined(PIPE_ATOMIC_MSVC_INTRINSIC)
299 #define PIPE_ATOMIC "MSVC Intrinsics"
303 #pragma intrinsic(_InterlockedIncrement)
304 #pragma intrinsic(_InterlockedDecrement)
305 #pragma intrinsic(_InterlockedCompareExchange)
311 #define p_atomic_set(_v, _i) (*(_v) = (_i))
312 #define p_atomic_read(_v) (*(_v))
314 static inline boolean
315 p_atomic_dec_zero(int32_t *v
)
317 return _InterlockedDecrement((long *)v
) == 0;
321 p_atomic_inc(int32_t *v
)
323 _InterlockedIncrement((long *)v
);
326 static inline int32_t
327 p_atomic_inc_return(int32_t *v
)
329 return _InterlockedIncrement((long *)v
);
333 p_atomic_dec(int32_t *v
)
335 _InterlockedDecrement((long *)v
);
338 static inline int32_t
339 p_atomic_dec_return(int32_t *v
)
341 return _InterlockedDecrement((long *)v
);
344 static inline int32_t
345 p_atomic_cmpxchg(int32_t *v
, int32_t old
, int32_t _new
)
347 return _InterlockedCompareExchange((long *)v
, _new
, old
);
356 #if defined(PIPE_ATOMIC_OS_SOLARIS)
358 #define PIPE_ATOMIC "Solaris OS atomic functions"
366 #define p_atomic_set(_v, _i) (*(_v) = (_i))
367 #define p_atomic_read(_v) (*(_v))
369 static inline boolean
370 p_atomic_dec_zero(int32_t *v
)
372 uint32_t n
= atomic_dec_32_nv((uint32_t *) v
);
377 #define p_atomic_inc(_v) atomic_inc_32((uint32_t *) _v)
378 #define p_atomic_dec(_v) atomic_dec_32((uint32_t *) _v)
379 #define p_atomic_inc_return(_v) atomic_inc_32_nv((uint32_t *) _v)
380 #define p_atomic_dec_return(_v) atomic_dec_32_nv((uint32_t *) _v)
382 #define p_atomic_cmpxchg(_v, _old, _new) \
383 atomic_cas_32( (uint32_t *) _v, (uint32_t) _old, (uint32_t) _new)
393 #error "No pipe_atomic implementation selected"
398 #endif /* U_ATOMIC_H */