diff options
author | Chris Robinson <[email protected]> | 2013-10-28 12:48:13 -0700 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2013-10-28 12:48:13 -0700 |
commit | 8d9fb5109b55912ef2be7b8d4526eb6ec8154004 (patch) | |
tree | d8db83a2502d4ec0e14a9c912d75b26f4db754dc /Alc/atomic.h | |
parent | 20bcb68ad6439bebc35bd9bb941916ad151cb690 (diff) |
Move some stuff out of alMain.h
Diffstat (limited to 'Alc/atomic.h')
-rw-r--r-- | Alc/atomic.h | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/Alc/atomic.h b/Alc/atomic.h new file mode 100644 index 00000000..9c249808 --- /dev/null +++ b/Alc/atomic.h @@ -0,0 +1,180 @@ +#ifndef AL_ATOMIC_H +#define AL_ATOMIC_H + + +typedef void *volatile XchgPtr; + +#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) && !defined(__QNXNTO__) +typedef unsigned int RefCount; +static inline RefCount IncrementRef(volatile RefCount *ptr) +{ return __sync_add_and_fetch(ptr, 1); } +static inline RefCount DecrementRef(volatile RefCount *ptr) +{ return __sync_sub_and_fetch(ptr, 1); } + +static inline int ExchangeInt(volatile int *ptr, int newval) +{ + return __sync_lock_test_and_set(ptr, newval); +} +static inline void *ExchangePtr(XchgPtr *ptr, void *newval) +{ + return __sync_lock_test_and_set(ptr, newval); +} +static inline ALboolean CompExchangeInt(volatile int *ptr, int oldval, int newval) +{ + return __sync_bool_compare_and_swap(ptr, oldval, newval); +} +static inline ALboolean CompExchangePtr(XchgPtr *ptr, void *oldval, void *newval) +{ + return __sync_bool_compare_and_swap(ptr, oldval, newval); +} + +#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + +static inline unsigned int xaddl(volatile unsigned int *dest, int incr) +{ + unsigned int ret; + __asm__ __volatile__("lock; xaddl %0,(%1)" + : "=r" (ret) + : "r" (dest), "0" (incr) + : "memory"); + return ret; +} + +typedef unsigned int RefCount; +static inline RefCount IncrementRef(volatile RefCount *ptr) +{ return xaddl(ptr, 1)+1; } +static inline RefCount DecrementRef(volatile RefCount *ptr) +{ return xaddl(ptr, -1)-1; } + +static inline int ExchangeInt(volatile int *dest, int newval) +{ + int ret; + __asm__ __volatile__("lock; xchgl %0,(%1)" + : "=r" (ret) + : "r" (dest), "0" (newval) + : "memory"); + return ret; +} + +static inline ALboolean CompExchangeInt(volatile int *dest, int oldval, int newval) +{ + int ret; + __asm__ __volatile__("lock; cmpxchgl %2,(%1)" + : "=a" (ret) + : "r" (dest), "r" (newval), "0" (oldval) + : "memory"); + return ret == oldval; +} + +static inline void *ExchangePtr(XchgPtr *dest, void *newval) +{ + void *ret; + __asm__ __volatile__( +#ifdef __i386__ + "lock; xchgl %0,(%1)" +#else + "lock; xchgq %0,(%1)" +#endif + : "=r" (ret) + : "r" (dest), "0" (newval) + : "memory" + ); + return ret; +} + +static inline ALboolean CompExchangePtr(XchgPtr *dest, void *oldval, void *newval) +{ + void *ret; + __asm__ __volatile__( +#ifdef __i386__ + "lock; cmpxchgl %2,(%1)" +#else + "lock; cmpxchgq %2,(%1)" +#endif + : "=a" (ret) + : "r" (dest), "r" (newval), "0" (oldval) + : "memory" + ); + return ret == oldval; +} + +#elif defined(_WIN32) + +#define WIN32_LEAN_AND_MEAN +#include <windows.h> + +typedef LONG RefCount; +static inline RefCount IncrementRef(volatile RefCount *ptr) +{ return InterlockedIncrement(ptr); } +static inline RefCount DecrementRef(volatile RefCount *ptr) +{ return InterlockedDecrement(ptr); } + +extern ALbyte LONG_size_does_not_match_int[(sizeof(LONG)==sizeof(int))?1:-1]; + +static inline int ExchangeInt(volatile int *ptr, int newval) +{ + union { + volatile int *i; + volatile LONG *l; + } u = { ptr }; + return InterlockedExchange(u.l, newval); +} +static inline void *ExchangePtr(XchgPtr *ptr, void *newval) +{ + return InterlockedExchangePointer(ptr, newval); +} +static inline ALboolean CompExchangeInt(volatile int *ptr, int oldval, int newval) +{ + union { + volatile int *i; + volatile LONG *l; + } u = { ptr }; + return InterlockedCompareExchange(u.l, newval, oldval) == oldval; +} +static inline ALboolean CompExchangePtr(XchgPtr *ptr, void *oldval, void *newval) +{ + return InterlockedCompareExchangePointer(ptr, newval, oldval) == oldval; +} + +#elif defined(__APPLE__) + +#include <libkern/OSAtomic.h> + +typedef int32_t RefCount; +static inline RefCount IncrementRef(volatile RefCount *ptr) +{ return OSAtomicIncrement32Barrier(ptr); } +static inline RefCount DecrementRef(volatile RefCount *ptr) +{ return OSAtomicDecrement32Barrier(ptr); } + +static inline int ExchangeInt(volatile int *ptr, int newval) +{ + /* Really? No regular old atomic swap? */ + int oldval; + do { + oldval = *ptr; + } while(!OSAtomicCompareAndSwap32Barrier(oldval, newval, ptr)); + return oldval; +} +static inline void *ExchangePtr(XchgPtr *ptr, void *newval) +{ + void *oldval; + do { + oldval = *ptr; + } while(!OSAtomicCompareAndSwapPtrBarrier(oldval, newval, ptr)); + return oldval; +} +static inline ALboolean CompExchangeInt(volatile int *ptr, int oldval, int newval) +{ + return OSAtomicCompareAndSwap32Barrier(oldval, newval, ptr); +} +static inline ALboolean CompExchangePtr(XchgPtr *ptr, void *oldval, void *newval) +{ + return OSAtomicCompareAndSwapPtrBarrier(oldval, newval, ptr); +} + +#else +#error "No atomic functions available on this platform!" +typedef ALuint RefCount; +#endif + +#endif /* AL_ATOMIC_H */ |