aboutsummaryrefslogtreecommitdiffstats
path: root/include/atomic.h
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2014-06-10 05:30:02 +0200
committerSven Gothel <[email protected]>2014-06-10 05:30:02 +0200
commitf95bf4457fbc31112fa82dacbc1b7e094b9fd1cf (patch)
tree965ba5b8e6fc8e6bfe7a981c1dfb1179bb9adcde /include/atomic.h
parent7297c3214a4c648aaee81a9877da15b88f798197 (diff)
parentc07fb7b45c1e345dbaa439882250de5b2213026f (diff)
Merge branch 'UPSTREAM' into UPSTREAM_MERGE
Diffstat (limited to 'include/atomic.h')
-rw-r--r--include/atomic.h208
1 files changed, 208 insertions, 0 deletions
diff --git a/include/atomic.h b/include/atomic.h
new file mode 100644
index 00000000..4adb7a94
--- /dev/null
+++ b/include/atomic.h
@@ -0,0 +1,208 @@
+#ifndef AL_ATOMIC_H
+#define AL_ATOMIC_H
+
+#include "static_assert.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void *volatile XchgPtr;
+
+typedef unsigned int uint;
+typedef union {
+ uint value;
+} RefCount;
+
+#define STATIC_REFCOUNT_INIT(V) {(V)}
+
+#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) && !defined(__QNXNTO__)
+
+inline void InitRef(volatile RefCount *ptr, uint value)
+{ ptr->value = value; }
+inline uint ReadRef(volatile RefCount *ptr)
+{ __sync_synchronize(); return ptr->value; }
+inline uint IncrementRef(volatile RefCount *ptr)
+{ return __sync_add_and_fetch(&ptr->value, 1); }
+inline uint DecrementRef(volatile RefCount *ptr)
+{ return __sync_sub_and_fetch(&ptr->value, 1); }
+inline uint ExchangeRef(volatile RefCount *ptr, uint newval)
+{ return __sync_lock_test_and_set(&ptr->value, newval); }
+inline uint CompExchangeRef(volatile RefCount *ptr, uint oldval, uint newval)
+{ return __sync_val_compare_and_swap(&ptr->value, oldval, newval); }
+
+inline int ExchangeInt(volatile int *ptr, int newval)
+{ return __sync_lock_test_and_set(ptr, newval); }
+inline void *ExchangePtr(XchgPtr *ptr, void *newval)
+{ return __sync_lock_test_and_set(ptr, newval); }
+inline int CompExchangeInt(volatile int *ptr, int oldval, int newval)
+{ return __sync_val_compare_and_swap(ptr, oldval, newval); }
+inline void *CompExchangePtr(XchgPtr *ptr, void *oldval, void *newval)
+{ return __sync_val_compare_and_swap(ptr, oldval, newval); }
+
+#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+
+inline uint xaddl(volatile uint *dest, int incr)
+{
+ unsigned int ret;
+ __asm__ __volatile__("lock; xaddl %0,(%1)"
+ : "=r" (ret)
+ : "r" (dest), "0" (incr)
+ : "memory");
+ return ret;
+}
+
+inline void InitRef(volatile RefCount *ptr, uint value)
+{ ptr->value = value; }
+inline uint ReadRef(volatile RefCount *ptr)
+{ __asm__ __volatile__("" ::: "memory"); return ptr->value; }
+inline uint IncrementRef(volatile RefCount *ptr)
+{ return xaddl(&ptr->value, 1)+1; }
+inline uint DecrementRef(volatile RefCount *ptr)
+{ return xaddl(&ptr->value, -1)-1; }
+inline uint ExchangeRef(volatile RefCount *ptr, uint newval)
+{
+ int ret;
+ __asm__ __volatile__("lock; xchgl %0,(%1)"
+ : "=r" (ret)
+ : "r" (&ptr->value), "0" (newval)
+ : "memory");
+ return ret;
+}
+inline uint CompExchangeRef(volatile RefCount *ptr, uint oldval, uint newval)
+{
+ int ret;
+ __asm__ __volatile__("lock; cmpxchgl %2,(%1)"
+ : "=a" (ret)
+ : "r" (&ptr->value), "r" (newval), "0" (oldval)
+ : "memory");
+ return ret;
+}
+
+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;
+}
+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;
+}
+inline int 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;
+}
+inline void *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;
+}
+
+#elif defined(_WIN32)
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+static_assert(sizeof(LONG)==sizeof(uint), "sizeof LONG does not match sizeof uint");
+
+inline void InitRef(volatile RefCount *ptr, uint value)
+{ ptr->value = value; }
+inline uint ReadRef(volatile RefCount *ptr)
+{ _ReadBarrier(); return ptr->value; }
+inline uint IncrementRef(volatile RefCount *ptr)
+{
+ union {
+ volatile uint *u;
+ volatile LONG *l;
+ } u = { &ptr->value };
+ return InterlockedIncrement(u.l);
+}
+inline uint DecrementRef(volatile RefCount *ptr)
+{
+ union {
+ volatile uint *u;
+ volatile LONG *l;
+ } u = { &ptr->value };
+ return InterlockedDecrement(u.l);
+}
+inline uint ExchangeRef(volatile RefCount *ptr, uint newval)
+{
+ union {
+ volatile uint *i;
+ volatile LONG *l;
+ } u = { &ptr->value };
+ return InterlockedExchange(u.l, newval);
+}
+inline uint CompExchangeRef(volatile RefCount *ptr, uint oldval, uint newval)
+{
+ union {
+ volatile uint *i;
+ volatile LONG *l;
+ } u = { &ptr->value };
+ return InterlockedCompareExchange(u.l, newval, oldval);
+}
+
+inline int ExchangeInt(volatile int *ptr, int newval)
+{
+ union {
+ volatile int *i;
+ volatile LONG *l;
+ } u = { ptr };
+ return InterlockedExchange(u.l, newval);
+}
+inline void *ExchangePtr(XchgPtr *ptr, void *newval)
+{
+ return InterlockedExchangePointer(ptr, newval);
+}
+inline int CompExchangeInt(volatile int *ptr, int oldval, int newval)
+{
+ union {
+ volatile int *i;
+ volatile LONG *l;
+ } u = { ptr };
+ return InterlockedCompareExchange(u.l, newval, oldval);
+}
+inline void *CompExchangePtr(XchgPtr *ptr, void *oldval, void *newval)
+{
+ return InterlockedCompareExchangePointer(ptr, newval, oldval);
+}
+
+#else
+#error "No atomic functions available on this platform!"
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AL_ATOMIC_H */