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 #include "pipe/p_compiler.h"
13 #include "pipe/p_defines.h"
15 /* Favor OS-provided implementations.
17 * Where no OS-provided implementation is available, fall back to
18 * locally coded assembly, compiler intrinsic or ultimately a
19 * mutex-based implementation.
21 #if (defined(PIPE_SUBSYSTEM_WINDOWS_DISPLAY) || \
22 defined(PIPE_SUBSYSTEM_WINDOWS_MINIPORT))
23 #define PIPE_ATOMIC_OS_UNLOCKED
24 #elif defined(PIPE_OS_SOLARIS)
25 #define PIPE_ATOMIC_OS_SOLARIS
26 #elif defined(PIPE_CC_MSVC)
27 #define PIPE_ATOMIC_MSVC_INTRINSIC
28 #elif (defined(PIPE_CC_MSVC) && defined(PIPE_ARCH_X86))
29 #define PIPE_ATOMIC_ASM_MSVC_X86
30 #elif (defined(PIPE_CC_GCC) && defined(PIPE_ARCH_X86))
31 #define PIPE_ATOMIC_ASM_GCC_X86
32 #elif defined(PIPE_CC_GCC) && (PIPE_CC_GCC_VERSION >= 401)
33 #define PIPE_ATOMIC_GCC_INTRINSIC
35 #error "Unsupported platform"
40 #if defined(PIPE_ATOMIC_ASM_GCC_X86)
42 #define PIPE_ATOMIC "GCC x86 assembly"
48 #define p_atomic_set(_v, _i) (*(_v) = (_i))
49 #define p_atomic_read(_v) (*(_v))
52 p_atomic_dec_zero(int32_t *v
)
56 __asm__
__volatile__("lock; decl %0; sete %1":"+m"(*v
), "=qm"(c
)
63 p_atomic_inc(int32_t *v
)
65 __asm__
__volatile__("lock; incl %0":"+m"(*v
));
69 p_atomic_dec(int32_t *v
)
71 __asm__
__volatile__("lock; decl %0":"+m"(*v
));
75 p_atomic_cmpxchg(int32_t *v
, int32_t old
, int32_t _new
)
77 return __sync_val_compare_and_swap(v
, old
, _new
);
88 /* Implementation using GCC-provided synchronization intrinsics
90 #if defined(PIPE_ATOMIC_GCC_INTRINSIC)
92 #define PIPE_ATOMIC "GCC Sync Intrinsics"
98 #define p_atomic_set(_v, _i) (*(_v) = (_i))
99 #define p_atomic_read(_v) (*(_v))
101 static INLINE boolean
102 p_atomic_dec_zero(int32_t *v
)
104 return (__sync_sub_and_fetch(v
, 1) == 0);
108 p_atomic_inc(int32_t *v
)
110 (void) __sync_add_and_fetch(v
, 1);
114 p_atomic_dec(int32_t *v
)
116 (void) __sync_sub_and_fetch(v
, 1);
119 static INLINE
int32_t
120 p_atomic_cmpxchg(int32_t *v
, int32_t old
, int32_t _new
)
122 return __sync_val_compare_and_swap(v
, old
, _new
);
133 /* Unlocked version for single threaded environments, such as some
134 * windows kernel modules.
136 #if defined(PIPE_ATOMIC_OS_UNLOCKED)
138 #define PIPE_ATOMIC "Unlocked"
140 #define p_atomic_set(_v, _i) (*(_v) = (_i))
141 #define p_atomic_read(_v) (*(_v))
142 #define p_atomic_dec_zero(_v) ((boolean) --(*(_v)))
143 #define p_atomic_inc(_v) ((void) (*(_v))++)
144 #define p_atomic_dec(_v) ((void) (*(_v))--)
145 #define p_atomic_cmpxchg(_v, old, _new) (*(_v) == old ? *(_v) = (_new) : *(_v))
150 /* Locally coded assembly for MSVC on x86:
152 #if defined(PIPE_ATOMIC_ASM_MSVC_X86)
154 #define PIPE_ATOMIC "MSVC x86 assembly"
160 #define p_atomic_set(_v, _i) (*(_v) = (_i))
161 #define p_atomic_read(_v) (*(_v))
163 static INLINE boolean
164 p_atomic_dec_zero(int32_t *v
)
170 lock dec dword ptr
[eax
]
178 p_atomic_inc(int32_t *v
)
182 lock inc dword ptr
[eax
]
187 p_atomic_dec(int32_t *v
)
191 lock dec dword ptr
[eax
]
195 static INLINE
int32_t
196 p_atomic_cmpxchg(int32_t *v
, int32_t old
, int32_t _new
)
204 lock cmpxchg
[ecx
], edx
218 #if defined(PIPE_ATOMIC_MSVC_INTRINSIC)
220 #define PIPE_ATOMIC "MSVC Intrinsics"
224 #pragma intrinsic(_InterlockedIncrement)
225 #pragma intrinsic(_InterlockedDecrement)
226 #pragma intrinsic(_InterlockedCompareExchange)
232 #define p_atomic_set(_v, _i) (*(_v) = (_i))
233 #define p_atomic_read(_v) (*(_v))
235 static INLINE boolean
236 p_atomic_dec_zero(int32_t *v
)
238 return _InterlockedDecrement((long *)v
) == 0;
242 p_atomic_inc(int32_t *v
)
244 _InterlockedIncrement((long *)v
);
248 p_atomic_dec(int32_t *v
)
250 _InterlockedDecrement((long *)v
);
253 static INLINE
int32_t
254 p_atomic_cmpxchg(int32_t *v
, int32_t old
, int32_t _new
)
256 return _InterlockedCompareExchange((long *)v
, _new
, old
);
265 #if defined(PIPE_ATOMIC_OS_SOLARIS)
267 #define PIPE_ATOMIC "Solaris OS atomic functions"
275 #define p_atomic_set(_v, _i) (*(_v) = (_i))
276 #define p_atomic_read(_v) (*(_v))
278 static INLINE boolean
279 p_atomic_dec_zero(int32_t *v
)
281 uint32_t n
= atomic_dec_32_nv((uint32_t *) v
);
286 #define p_atomic_inc(_v) atomic_inc_32((uint32_t *) _v)
287 #define p_atomic_dec(_v) atomic_dec_32((uint32_t *) _v)
289 #define p_atomic_cmpxchg(_v, _old, _new) \
290 atomic_cas_32( (uint32_t *) _v, (uint32_t) _old, (uint32_t) _new)
300 #error "No pipe_atomic implementation selected"
305 #endif /* U_ATOMIC_H */