aboutsummaryrefslogtreecommitdiffstats
path: root/Alc/atomic.h
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2013-10-28 12:48:13 -0700
committerChris Robinson <[email protected]>2013-10-28 12:48:13 -0700
commit8d9fb5109b55912ef2be7b8d4526eb6ec8154004 (patch)
treed8db83a2502d4ec0e14a9c912d75b26f4db754dc /Alc/atomic.h
parent20bcb68ad6439bebc35bd9bb941916ad151cb690 (diff)
Move some stuff out of alMain.h
Diffstat (limited to 'Alc/atomic.h')
-rw-r--r--Alc/atomic.h180
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 */