/** * Many similar implementations exist. See for example libwsbm * or the linux kernel include/atomic.h * * No copyright claimed on this file. * */ #ifndef P_ATOMIC_H #define P_ATOMIC_H #include "p_compiler.h" #include "p_defines.h" #ifdef __cplusplus extern "C" { #endif #if (defined(PIPE_CC_GCC)) struct pipe_atomic { int32_t count; }; #define p_atomic_set(_v, _i) ((_v)->count = (_i)) #define p_atomic_read(_v) ((_v)->count) static INLINE boolean p_atomic_dec_zero(struct pipe_atomic *v) { #ifdef __i386__ unsigned char c; __asm__ __volatile__("lock; decl %0; sete %1":"+m"(v->count), "=qm"(c) ::"memory"); return c != 0; #else /* __i386__*/ return (__sync_sub_and_fetch(&v->count, 1) == 0); #endif /* __i386__*/ } static INLINE void p_atomic_inc(struct pipe_atomic *v) { #ifdef __i386__ __asm__ __volatile__("lock; incl %0":"+m"(v->count)); #else /* __i386__*/ (void) __sync_add_and_fetch(&v->count, 1); #endif /* __i386__*/ } static INLINE void p_atomic_dec(struct pipe_atomic *v) { #ifdef __i386__ __asm__ __volatile__("lock; decl %0":"+m"(v->count)); #else /* __i386__*/ (void) __sync_sub_and_fetch(&v->count, 1); #endif /* __i386__*/ } static INLINE int32_t p_atomic_cmpxchg(struct pipe_atomic *v, int32_t old, int32_t _new) { return __sync_val_compare_and_swap(&v->count, old, _new); } #elif (defined(PIPE_SUBSYSTEM_WINDOWS_DISPLAY) || defined(PIPE_SUBSYSTEM_WINDOWS_MINIPORT)) /* (defined(PIPE_CC_GCC)) */ struct pipe_atomic { int32_t count; }; #define p_atomic_set(_v, _i) ((_v)->count = (_i)) #define p_atomic_read(_v) ((_v)->count) #define p_atomic_dec_zero(_v) ((boolean) --(_v)->count) #define p_atomic_inc(_v) ((void) (_v)->count++) #define p_atomic_dec(_v) ((void) (_v)->count--) #define p_atomic_cmpxchg(_v, old, _new) ((_v)->count == old ? (_v)->count = (_new) : (_v)->count) #elif (defined(PIPE_ARCH_X86) && defined(PIPE_CC_MSVC)) /* (defined(PIPE_SUBSYSTEM_WINDOWS_DISPLAY) || defined(PIPE_SUBSYSTEM_WINDOWS_MINIPORT)) */ struct pipe_atomic { int32_t count; }; #define p_atomic_set(_v, _i) ((_v)->count = (_i)) #define p_atomic_read(_v) ((_v)->count) static INLINE boolean p_atomic_dec_zero(struct pipe_atomic *v) { int32_t *pcount = &v->count; unsigned char c; __asm { mov eax, [pcount] lock dec dword ptr [eax] sete byte ptr [c] } return c != 0; } static INLINE void p_atomic_inc(struct pipe_atomic *v) { int32_t *pcount = &v->count; __asm { mov eax, [pcount] lock inc dword ptr [eax] } } static INLINE void p_atomic_dec(struct pipe_atomic *v) { int32_t *pcount = &v->count; __asm { mov eax, [pcount] lock dec dword ptr [eax] } } static INLINE int32_t p_atomic_cmpxchg(struct pipe_atomic *v, int32_t old, int32_t _new) { int32_t *pcount = &v->count; int32_t orig; __asm { mov ecx, [pcount] mov eax, [old] mov edx, [_new] lock cmpxchg [ecx], edx mov [orig], eax } return orig; } #elif (defined(PIPE_SUBSYSTEM_WINDOWS_USER)) /* (defined(PIPE_ARCH_X86) && defined(PIPE_CC_MSVC)) */ struct pipe_atomic { long count; }; #define p_atomic_set(_v, _i) ((_v)->count = (_i)) #define p_atomic_read(_v) ((_v)->count) static INLINE boolean p_atomic_dec_zero(struct pipe_atomic *v) { return InterlockedDecrement(&v->count); } static INLINE void p_atomic_inc(struct pipe_atomic *v) { InterlockedIncrement(&v->count); } static INLINE void p_atomic_dec(struct pipe_atomic *v) { InterlockedDecrement(&v->count); } static INLINE int32_t p_atomic_cmpxchg(struct pipe_atomic *v, int32_t old, int32_t _new) { return InterlockedCompareExchange(&v->count, _new, old); } #else /* (defined(PIPE_SUBSYSTEM_WINDOWS_USER)) */ #include "pipe/p_thread.h" /** * This implementation should really not be used. * Add an assembly port instead. It may abort and * doesn't destroy used mutexes. */ struct pipe_atomic { pipe_mutex mutex; int32_t count; }; static INLINE void p_atomic_set(struct pipe_atomic *v, int32_t i) { pipe_mutex_init(v->mutex); pipe_mutex_lock(v->mutex); v->count = i; pipe_mutex_unlock(v->mutex); } static INLINE int32_t p_atomic_read(struct pipe_atomic *v) { int32_t ret; pipe_mutex_lock(v->mutex); ret = v->count; pipe_mutex_unlock(v->mutex); return ret; } static INLINE void p_atomic_inc(struct pipe_atomic *v) { pipe_mutex_lock(v->mutex); ++v->count; pipe_mutex_unlock(v->mutex); } static INLINE void p_atomic_dec(struct pipe_atomic *v) { pipe_mutex_lock(v->mutex); --v->count; pipe_mutex_unlock(v->mutex); } static INLINE boolean p_atomic_dec_zero(struct pipe_atomic *v) { boolean ret; pipe_mutex_lock(v->mutex); ret = (--v->count == 0); pipe_mutex_unlock(v->mutex); return ret; } static INLINE int32_t p_atomic_cmpxchg(struct pipe_atomic *v, int32_t old, int32_t _new) { int32_t ret; pipe_mutex_lock(v->mutex); ret = v->count; if (ret == old) v->count = _new; pipe_mutex_unlock(v->mutex); return ret; } #endif /* (defined(PIPE_CC_GCC)) */ #ifdef __cplusplus } #endif #endif /* P_ATOMIC_H */