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 "p_compiler.h"
13 #include "p_defines.h"
20 /* Favor OS-provided implementations.
22 * Where no OS-provided implementation is available, fall back to
23 * locally coded assembly, compiler intrinsic or ultimately a
24 * mutex-based implementation.
26 #if (defined(PIPE_SUBSYSTEM_WINDOWS_DISPLAY) || \
27 defined(PIPE_SUBSYSTEM_WINDOWS_MINIPORT))
28 #define PIPE_ATOMIC_OS_UNLOCKED
29 #elif (defined(PIPE_CC_MSVC) && defined(PIPE_SUBSYSTEM_WINDOWS_USER))
30 #define PIPE_ATOMIC_OS_MS_INTERLOCK
31 #elif (defined(PIPE_CC_MSVC) && defined(PIPE_ARCH_X86))
32 #define PIPE_ATOMIC_ASM_MSVC_X86
33 #elif (defined(PIPE_CC_GCC) && defined(PIPE_ARCH_X86))
34 #define PIPE_ATOMIC_ASM_GCC_X86
35 #elif defined(PIPE_CC_GCC)
36 #define PIPE_ATOMIC_GCC_INTRINSIC
38 #define PIPE_ATOMIC_MUTEX
43 #if defined(PIPE_ATOMIC_ASM_GCC_X86)
45 #define PIPE_ATOMIC "GCC x86 assembly"
51 #define p_atomic_set(_v, _i) ((_v)->count = (_i))
52 #define p_atomic_read(_v) ((_v)->count)
56 p_atomic_dec_zero(struct pipe_atomic
*v
)
60 __asm__
__volatile__("lock; decl %0; sete %1":"+m"(v
->count
), "=qm"(c
)
67 p_atomic_inc(struct pipe_atomic
*v
)
69 __asm__
__volatile__("lock; incl %0":"+m"(v
->count
));
73 p_atomic_dec(struct pipe_atomic
*v
)
75 __asm__
__volatile__("lock; decl %0":"+m"(v
->count
));
79 p_atomic_cmpxchg(struct pipe_atomic
*v
, int32_t old
, int32_t _new
)
81 return __sync_val_compare_and_swap(&v
->count
, old
, _new
);
87 /* Implementation using GCC-provided synchronization intrinsics
89 #if defined(PIPE_ATOMIC_GCC_INTRINSIC)
91 #define PIPE_ATOMIC "GCC Sync Intrinsics"
97 #define p_atomic_set(_v, _i) ((_v)->count = (_i))
98 #define p_atomic_read(_v) ((_v)->count)
101 static INLINE boolean
102 p_atomic_dec_zero(struct pipe_atomic
*v
)
104 return (__sync_sub_and_fetch(&v
->count
, 1) == 0);
108 p_atomic_inc(struct pipe_atomic
*v
)
110 (void) __sync_add_and_fetch(&v
->count
, 1);
114 p_atomic_dec(struct pipe_atomic
*v
)
116 (void) __sync_sub_and_fetch(&v
->count
, 1);
119 static INLINE
int32_t
120 p_atomic_cmpxchg(struct pipe_atomic
*v
, int32_t old
, int32_t _new
)
122 return __sync_val_compare_and_swap(&v
->count
, old
, _new
);
128 /* Unlocked version for single threaded environments, such as some
129 * windows kernel modules.
131 #if defined(PIPE_ATOMIC_OS_UNLOCKED)
133 #define PIPE_ATOMIC "Unlocked"
140 #define p_atomic_set(_v, _i) ((_v)->count = (_i))
141 #define p_atomic_read(_v) ((_v)->count)
142 #define p_atomic_dec_zero(_v) ((boolean) --(_v)->count)
143 #define p_atomic_inc(_v) ((void) (_v)->count++)
144 #define p_atomic_dec(_v) ((void) (_v)->count--)
145 #define p_atomic_cmpxchg(_v, old, _new) ((_v)->count == old ? (_v)->count = (_new) : (_v)->count)
150 /* Locally coded assembly for MSVC on x86:
152 #if defined(PIPE_ATOMIC_ASM_MSVC_X86)
154 #define PIPE_ATOMIC "MSVC x86 assembly"
161 #define p_atomic_set(_v, _i) ((_v)->count = (_i))
162 #define p_atomic_read(_v) ((_v)->count)
164 static INLINE boolean
165 p_atomic_dec_zero(struct pipe_atomic
*v
)
167 int32_t *pcount
= &v
->count
;
172 lock dec dword ptr
[eax
]
180 p_atomic_inc(struct pipe_atomic
*v
)
182 int32_t *pcount
= &v
->count
;
186 lock inc dword ptr
[eax
]
191 p_atomic_dec(struct pipe_atomic
*v
)
193 int32_t *pcount
= &v
->count
;
197 lock dec dword ptr
[eax
]
201 static INLINE
int32_t
202 p_atomic_cmpxchg(struct pipe_atomic
*v
, int32_t old
, int32_t _new
)
204 int32_t *pcount
= &v
->count
;
211 lock cmpxchg
[ecx
], edx
220 #if defined(PIPE_ATOMIC_OS_MS_INTERLOCK)
222 #define PIPE_ATOMIC "MS userspace interlocks"
231 #define p_atomic_set(_v, _i) ((_v)->count = (_i))
232 #define p_atomic_read(_v) ((_v)->count)
234 static INLINE boolean
235 p_atomic_dec_zero(struct pipe_atomic
*v
)
237 return InterlockedDecrement(&v
->count
) == 0;
241 p_atomic_inc(struct pipe_atomic
*v
)
243 InterlockedIncrement(&v
->count
);
247 p_atomic_dec(struct pipe_atomic
*v
)
249 InterlockedDecrement(&v
->count
);
252 static INLINE
int32_t
253 p_atomic_cmpxchg(struct pipe_atomic
*v
, int32_t old
, int32_t _new
)
255 return InterlockedCompareExchange(&v
->count
, _new
, old
);
262 #if defined(PIPE_ATOMIC_MUTEX)
264 #define PIPE_ATOMIC "mutex-based fallback"
266 #include "pipe/p_thread.h"
269 * This implementation should really not be used.
270 * Add an assembly port instead. It may abort and
271 * doesn't destroy used mutexes.
280 p_atomic_set(struct pipe_atomic
*v
, int32_t i
)
282 pipe_mutex_init(v
->mutex
);
283 pipe_mutex_lock(v
->mutex
);
285 pipe_mutex_unlock(v
->mutex
);
288 static INLINE
int32_t
289 p_atomic_read(struct pipe_atomic
*v
)
293 pipe_mutex_lock(v
->mutex
);
295 pipe_mutex_unlock(v
->mutex
);
300 p_atomic_inc(struct pipe_atomic
*v
)
302 pipe_mutex_lock(v
->mutex
);
304 pipe_mutex_unlock(v
->mutex
);
308 p_atomic_dec(struct pipe_atomic
*v
)
310 pipe_mutex_lock(v
->mutex
);
312 pipe_mutex_unlock(v
->mutex
);
315 static INLINE boolean
316 p_atomic_dec_zero(struct pipe_atomic
*v
)
320 pipe_mutex_lock(v
->mutex
);
321 ret
= (--v
->count
== 0);
322 pipe_mutex_unlock(v
->mutex
);
326 static INLINE
int32_t
327 p_atomic_cmpxchg(struct pipe_atomic
*v
, int32_t old
, int32_t _new
)
331 pipe_mutex_lock(v
->mutex
);
335 pipe_mutex_unlock(v
->mutex
);
344 #error "No pipe_atomic implementation selected"
353 #endif /* P_ATOMIC_H */