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) && defined(PIPE_ARCH_ARM))
33 #define PIPE_ATOMIC_ASM_GCC_ARM
34 #elif (defined(PIPE_CC_GCC) && defined(PIPE_ARCH_X86_64))
35 #define PIPE_ATOMIC_ASM_GCC_X86_64
36 #elif defined(PIPE_OS_AROS) && defined(PIPE_ARCH_M68K)
37 #define PIPE_ATOMIC_OS_AROS_CPU_M68K
38 #elif defined(PIPE_CC_GCC) && (PIPE_CC_GCC_VERSION >= 401)
39 #define PIPE_ATOMIC_GCC_INTRINSIC
41 #error "Unsupported platform"
45 #if defined(PIPE_ATOMIC_ASM_GCC_X86_64)
46 #define PIPE_ATOMIC "GCC x86_64 assembly"
52 #define p_atomic_set(_v, _i) (*(_v) = (_i))
53 #define p_atomic_read(_v) (*(_v))
56 p_atomic_dec_zero(int32_t *v
)
60 __asm__
__volatile__("lock; decl %0; sete %1":"+m"(*v
), "=qm"(c
)
67 p_atomic_inc(int32_t *v
)
69 __asm__
__volatile__("lock; incl %0":"+m"(*v
));
73 p_atomic_dec(int32_t *v
)
75 __asm__
__volatile__("lock; decl %0":"+m"(*v
));
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_cmpxchg(int32_t *v
, int32_t old
, int32_t _new
)
128 return __sync_val_compare_and_swap(v
, old
, _new
);
137 #if defined(PIPE_ATOMIC_ASM_GCC_ARM)
139 #define PIPE_ATOMIC "GCC ARM assembly"
145 #define p_atomic_set(_v, _i) (*(_v) = (_i))
146 #define p_atomic_read(_v) (*(_v))
148 static INLINE boolean
149 p_atomic_dec_zero(int32_t *v
)
154 __asm__
__volatile__("\n1: ldrex %0, [%3]; subs %0, %0, #1; moveq %2, #1; movne %2, #0; strex %1, %0, [%3]; teq %1, #0; bne 1b"
155 :"=&r"(result
), "=&r"(temp
), "=&r"(cc
)
162 p_atomic_inc(int32_t *v
)
166 __asm__
__volatile__("\n1: ldrex %0, [%2]; add %0, %0, #1; strex %1, %0, [%2]; teq %1, #0; bne 1b"
167 :"=&r"(result
), "=&r"(temp
)
173 p_atomic_dec(int32_t *v
)
177 __asm__
__volatile__("\n1: ldrex %0, [%2]; sub %0, %0, #1; strex %1, %0, [%2]; teq %1, #0; bne 1b"
178 :"=&r"(result
), "=&r"(temp
)
183 static INLINE
int32_t
184 p_atomic_cmpxchg(int32_t *v
, int32_t old
, int32_t _new
)
188 __asm__
__volatile__("\n1: ldrex %0,[%2]; teq %0, %3; strexeq %1, %4, [%2]; teq %1, #0; bne 1b"
189 :"=&r"(oldval
), "=&r"(temp
)
190 :"r"(v
), "Ir"(old
), "r"(_new
)
202 /* Implementation using GCC-provided synchronization intrinsics
204 #if defined(PIPE_ATOMIC_GCC_INTRINSIC)
206 #define PIPE_ATOMIC "GCC Sync Intrinsics"
212 #define p_atomic_set(_v, _i) (*(_v) = (_i))
213 #define p_atomic_read(_v) (*(_v))
215 static INLINE boolean
216 p_atomic_dec_zero(int32_t *v
)
218 return (__sync_sub_and_fetch(v
, 1) == 0);
222 p_atomic_inc(int32_t *v
)
224 (void) __sync_add_and_fetch(v
, 1);
228 p_atomic_dec(int32_t *v
)
230 (void) __sync_sub_and_fetch(v
, 1);
233 static INLINE
int32_t
234 p_atomic_cmpxchg(int32_t *v
, int32_t old
, int32_t _new
)
236 return __sync_val_compare_and_swap(v
, old
, _new
);
247 /* Unlocked version for single threaded environments, such as some
248 * windows kernel modules.
250 #if defined(PIPE_ATOMIC_OS_UNLOCKED)
252 #define PIPE_ATOMIC "Unlocked"
254 #define p_atomic_set(_v, _i) (*(_v) = (_i))
255 #define p_atomic_read(_v) (*(_v))
256 #define p_atomic_dec_zero(_v) ((boolean) --(*(_v)))
257 #define p_atomic_inc(_v) ((void) (*(_v))++)
258 #define p_atomic_dec(_v) ((void) (*(_v))--)
259 #define p_atomic_cmpxchg(_v, old, _new) (*(_v) == old ? *(_v) = (_new) : *(_v))
264 /* Locally coded assembly for MSVC on x86:
266 #if defined(PIPE_ATOMIC_ASM_MSVC_X86)
268 #define PIPE_ATOMIC "MSVC x86 assembly"
274 #define p_atomic_set(_v, _i) (*(_v) = (_i))
275 #define p_atomic_read(_v) (*(_v))
277 static INLINE boolean
278 p_atomic_dec_zero(int32_t *v
)
284 lock dec dword ptr
[eax
]
292 p_atomic_inc(int32_t *v
)
296 lock inc dword ptr
[eax
]
301 p_atomic_dec(int32_t *v
)
305 lock dec dword ptr
[eax
]
309 static INLINE
int32_t
310 p_atomic_cmpxchg(int32_t *v
, int32_t old
, int32_t _new
)
318 lock cmpxchg
[ecx
], edx
332 #if defined(PIPE_ATOMIC_MSVC_INTRINSIC)
334 #define PIPE_ATOMIC "MSVC Intrinsics"
338 #pragma intrinsic(_InterlockedIncrement)
339 #pragma intrinsic(_InterlockedDecrement)
340 #pragma intrinsic(_InterlockedCompareExchange)
346 #define p_atomic_set(_v, _i) (*(_v) = (_i))
347 #define p_atomic_read(_v) (*(_v))
349 static INLINE boolean
350 p_atomic_dec_zero(int32_t *v
)
352 return _InterlockedDecrement((long *)v
) == 0;
356 p_atomic_inc(int32_t *v
)
358 _InterlockedIncrement((long *)v
);
362 p_atomic_dec(int32_t *v
)
364 _InterlockedDecrement((long *)v
);
367 static INLINE
int32_t
368 p_atomic_cmpxchg(int32_t *v
, int32_t old
, int32_t _new
)
370 return _InterlockedCompareExchange((long *)v
, _new
, old
);
379 #if defined(PIPE_ATOMIC_OS_SOLARIS)
381 #define PIPE_ATOMIC "Solaris OS atomic functions"
389 #define p_atomic_set(_v, _i) (*(_v) = (_i))
390 #define p_atomic_read(_v) (*(_v))
392 static INLINE boolean
393 p_atomic_dec_zero(int32_t *v
)
395 uint32_t n
= atomic_dec_32_nv((uint32_t *) v
);
400 #define p_atomic_inc(_v) atomic_inc_32((uint32_t *) _v)
401 #define p_atomic_dec(_v) atomic_dec_32((uint32_t *) _v)
403 #define p_atomic_cmpxchg(_v, _old, _new) \
404 atomic_cas_32( (uint32_t *) _v, (uint32_t) _old, (uint32_t) _new)
413 #if defined(PIPE_ATOMIC_OS_AROS_CPU_M68K)
415 #define PIPE_ATOMIC "AROS OS atomic functions"
417 #include <aros/atomic.h>
423 #define p_atomic_set(_v, _i) (*(_v) = (_i))
424 #define p_atomic_read(_v) (*(_v))
426 static INLINE boolean
427 p_atomic_dec_zero(int32_t *v
)
431 /* FIXME: AROS needs an atomic decrement and return... */
433 AROS_ATOMIC_DEC(*(LONG
*)v
);
434 n
= (*v
== 0) ? TRUE
: FALSE
;
440 #define p_atomic_inc(_v) AROS_ATOMIC_INC(*(LONG *)_v)
441 #define p_atomic_dec(_v) AROS_ATOMIC_DEC(*(LONG *)_v)
443 static INLINE
int32_t
444 p_atomic_cmpxchg(int32_t *v
, int32_t o
, int32_t n
)
448 /* FIXME: AROS needs an atomic cmpxchg, using CAS.
449 * However we can't do this if:
450 * a) We are on a 68000 or
451 * b) The 'v' points to Chip RAM (no r/m/w possible)
453 * Settle for Disable()/Enable() for now.
472 #error "No pipe_atomic implementation selected"
477 #endif /* U_ATOMIC_H */