aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2014-07-23 06:36:34 -0700
committerChris Robinson <[email protected]>2014-07-23 06:36:34 -0700
commita3dbe08c8b9df301dded52ad78f655c2753be56c (patch)
tree69e5d4fd8f3a195bfae430d9a9a5dedf660509f7
parente4b779c492e9ffbfce806ac49acae66ab264a7da (diff)
Support C11 atomics
-rw-r--r--Alc/ALc.c4
-rw-r--r--CMakeLists.txt10
-rw-r--r--OpenAL32/alError.c3
-rw-r--r--config.h.in3
-rw-r--r--include/atomic.h131
5 files changed, 94 insertions, 57 deletions
diff --git a/Alc/ALc.c b/Alc/ALc.c
index ed2ddd89..14d35f73 100644
--- a/Alc/ALc.c
+++ b/Alc/ALc.c
@@ -2181,6 +2181,7 @@ static ALCvoid FreeContext(ALCcontext *context)
static void ReleaseContext(ALCcontext *context, ALCdevice *device)
{
ALCcontext *volatile*tmp_ctx;
+ ALCcontext *origctx;
if(altss_get(LocalContext) == context)
{
@@ -2189,7 +2190,8 @@ static void ReleaseContext(ALCcontext *context, ALCdevice *device)
ALCcontext_DecRef(context);
}
- if(ATOMIC_COMPARE_EXCHANGE(ALCcontext*, GlobalContext, context, NULL) == context)
+ origctx = context;
+ if(ATOMIC_COMPARE_EXCHANGE(ALCcontext*, GlobalContext, origctx, NULL))
ALCcontext_DecRef(context);
ALCdevice_Lock(device);
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7b5ec71e..75cb5e4f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -164,6 +164,16 @@ CHECK_C_SOURCE_COMPILES(
}"
HAVE_C11_ALIGNAS)
+# Check if we have C11 _Atomic
+CHECK_C_SOURCE_COMPILES(
+"#include <stdatomic.h>
+ int _Atomic foo;
+ int main()
+ {
+ return atomic_load(&foo);
+ }"
+HAVE_C11_ATOMIC)
+
# Add definitions, compiler switches, etc.
INCLUDE_DIRECTORIES("${OpenAL_SOURCE_DIR}/include" "${OpenAL_BINARY_DIR}")
IF(CMAKE_VERSION VERSION_LESS "2.8.8")
diff --git a/OpenAL32/alError.c b/OpenAL32/alError.c
index 04700d97..6d3870fd 100644
--- a/OpenAL32/alError.c
+++ b/OpenAL32/alError.c
@@ -35,6 +35,7 @@ ALboolean TrapALError = AL_FALSE;
ALvoid alSetError(ALCcontext *Context, ALenum errorCode)
{
+ ALenum curerr = AL_NO_ERROR;
if(TrapALError)
{
#ifdef _WIN32
@@ -45,7 +46,7 @@ ALvoid alSetError(ALCcontext *Context, ALenum errorCode)
raise(SIGTRAP);
#endif
}
- ATOMIC_COMPARE_EXCHANGE(ALenum, Context->LastError, AL_NO_ERROR, errorCode);
+ (void)ATOMIC_COMPARE_EXCHANGE(ALenum, Context->LastError, curerr, errorCode);
}
AL_API ALenum AL_APIENTRY alGetError(void)
diff --git a/config.h.in b/config.h.in
index 3fdc0c7e..3bb57c81 100644
--- a/config.h.in
+++ b/config.h.in
@@ -103,6 +103,9 @@
/* Define if we have C11 _Alignas support */
#cmakedefine HAVE_C11_ALIGNAS
+/* Define if we have C11 _Atomic support */
+#cmakedefine HAVE_C11_ATOMIC
+
/* Define if we have GCC's destructor attribute */
#cmakedefine HAVE_GCC_DESTRUCTOR
diff --git a/include/atomic.h b/include/atomic.h
index a35d9be0..0780b6a0 100644
--- a/include/atomic.h
+++ b/include/atomic.h
@@ -2,6 +2,7 @@
#define AL_ATOMIC_H
#include "static_assert.h"
+#include "bool.h"
#ifdef __cplusplus
extern "C" {
@@ -9,10 +10,40 @@ extern "C" {
typedef void *volatile XchgPtr;
-typedef unsigned int uint;
+/* Atomics using C11 */
+#ifdef HAVE_C11_ATOMIC
+
+#include <stdatomic.h>
+
+inline int ExchangeInt(volatile int *ptr, int newval)
+{ return atomic_exchange(ptr, newval); }
+inline void *ExchangePtr(XchgPtr *ptr, void *newval)
+{ return atomic_exchange(ptr, newval); }
+inline int CompExchangeInt(volatile int *ptr, int oldval, int newval)
+{ atomic_compare_exchange_strong(ptr, &oldval, newval); return oldval; }
+inline void *CompExchangePtr(XchgPtr *ptr, void *oldval, void *newval)
+{ atomic_compare_exchange_strong(ptr, &oldval, newval); return oldval; }
+
+
+#define ATOMIC(T) struct { T _Atomic value; }
+
+#define ATOMIC_INIT_STATIC(_newval) {ATOMIC_VAR_INIT(_newval)}
+
+#define ATOMIC_LOAD_UNSAFE(_val) atomic_load_explicit(&(_val).value, memory_order_relaxed)
+#define ATOMIC_STORE_UNSAFE(_val, _newval) atomic_store_explicit(&(_val).value, (_newval), memory_order_relaxed)
+
+#define ATOMIC_LOAD(_val) atomic_load(&(_val).value)
+#define ATOMIC_STORE(_val, _newval) atomic_store(&(_val).value, (_newval))
+
+#define ATOMIC_ADD(T, _val, _incr) atomic_fetch_add(&(_val).value, (_incr))
+#define ATOMIC_SUB(T, _val, _decr) atomic_fetch_sub(&(_val).value, (_decr))
+
+#define ATOMIC_EXCHANGE(T, _val, _newval) atomic_exchange(&(_val).value, (_newval))
+#define ATOMIC_COMPARE_EXCHANGE(T, _val, _oldval, _newval) \
+ atomic_compare_exchange_strong(&(_val).value, &(_oldval), (_newval))
/* Atomics using GCC intrinsics */
-#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) && !defined(__QNXNTO__)
+#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) && !defined(__QNXNTO__)
inline int ExchangeInt(volatile int *ptr, int newval)
{ return __sync_lock_test_and_set(ptr, newval); }
@@ -41,24 +72,22 @@ inline void *CompExchangePtr(XchgPtr *ptr, void *oldval, void *newval)
#define ATOMIC_ADD(T, _val, _incr) __extension__({ \
static_assert(sizeof(T)==sizeof((_val).value), "Type "#T" has incorrect size!"); \
- T _r = __sync_fetch_and_add(&(_val).value, (_incr)); \
- _r; \
+ __sync_fetch_and_add(&(_val).value, (_incr)); \
})
#define ATOMIC_SUB(T, _val, _decr) __extension__({ \
static_assert(sizeof(T)==sizeof((_val).value), "Type "#T" has incorrect size!"); \
- T _r = __sync_fetch_and_sub(&(_val).value, (_decr)); \
- _r; \
+ __sync_fetch_and_sub(&(_val).value, (_decr)); \
})
#define ATOMIC_EXCHANGE(T, _val, _newval) __extension__({ \
static_assert(sizeof(T)==sizeof((_val).value), "Type "#T" has incorrect size!"); \
- T _r = __sync_lock_test_and_set(&(_val).value, (_newval)); \
- _r; \
+ __sync_lock_test_and_set(&(_val).value, (_newval)); \
})
#define ATOMIC_COMPARE_EXCHANGE(T, _val, _oldval, _newval) __extension__({ \
static_assert(sizeof(T)==sizeof((_val).value), "Type "#T" has incorrect size!"); \
- T _r = __sync_val_compare_and_swap(&(_val).value, (_oldval), (_newval)); \
- _r; \
+ __typeof(_oldval) _old = (_oldval); \
+ (_oldval) = __sync_val_compare_and_swap(&(_val).value, (_oldval), (_newval)); \
+ (_oldval) == _old; \
})
/* Atomics using x86/x86-64 GCC inline assembly */
@@ -92,44 +121,20 @@ inline void *CompExchangePtr(XchgPtr *ptr, void *oldval, void *newval)
inline int ExchangeInt(volatile int *dest, int newval)
-{
- int ret;
- WRAP_XCHG("l", ret, dest, newval);
- return ret;
-}
+{ int ret; WRAP_XCHG("l", ret, dest, newval); return ret; }
inline int CompExchangeInt(volatile int *dest, int oldval, int newval)
-{
- int ret;
- WRAP_CMPXCHG("l", ret, dest, oldval, newval);
- return ret;
-}
+{ int ret; WRAP_CMPXCHG("l", ret, dest, oldval, newval); return ret; }
#ifdef __i386__
inline void *ExchangePtr(XchgPtr *dest, void *newval)
-{
- void *ret;
- WRAP_XCHG("l", ret, dest, newval);
- return ret;
-}
+{ void *ret; WRAP_XCHG("l", ret, dest, newval); return ret; }
inline void *CompExchangePtr(XchgPtr *dest, void *oldval, void *newval)
-{
- void *ret;
- WRAP_CMPXCHG("l", ret, dest, oldval, newval);
- return ret;
-}
+{ void *ret; WRAP_CMPXCHG("l", ret, dest, oldval, newval); return ret; }
#else
inline void *ExchangePtr(XchgPtr *dest, void *newval)
-{
- void *ret;
- WRAP_XCHG("q", ret, dest, newval);
- return ret;
-}
+{ void *ret; WRAP_XCHG("q", ret, dest, newval); return ret; }
inline void *CompExchangePtr(XchgPtr *dest, void *oldval, void *newval)
-{
- void *ret;
- WRAP_CMPXCHG("q", ret, dest, oldval, newval);
- return ret;
-}
+{ void *ret; WRAP_CMPXCHG("q", ret, dest, oldval, newval); return ret; }
#endif
@@ -152,33 +157,35 @@ inline void _al_mem_barrier(void)
} while(0)
#define ATOMIC_ADD(T, _val, _incr) __extension__({ \
- T _r; \
static_assert(sizeof(T)==4, "Type "#T" has incorrect size!"); \
static_assert(sizeof(T)==sizeof((_val).value), "Type "#T" has incorrect size!"); \
+ T _r; \
WRAP_ADD(_r, &(_val).value, (_incr)); \
_r; \
})
#define ATOMIC_SUB(T, _val, _decr) __extension__({ \
- T _r; \
static_assert(sizeof(T)==4, "Type "#T" has incorrect size!"); \
static_assert(sizeof(T)==sizeof((_val).value), "Type "#T" has incorrect size!"); \
+ T _r; \
WRAP_SUB(_r, &(_val).value, (_decr)); \
_r; \
})
#define ATOMIC_EXCHANGE(T, _val, _newval) __extension__({ \
- T _r; \
+ static_assert(sizeof(T)==4 || sizeof(T)==8, "Type "#T" has incorrect size!"); \
static_assert(sizeof(T)==sizeof((_val).value), "Type "#T" has incorrect size!"); \
+ T _r; \
if(sizeof(T) == 4) WRAP_XCHG("l", _r, &(_val).value, (_newval)); \
else if(sizeof(T) == 8) WRAP_XCHG("q", _r, &(_val).value, (_newval)); \
_r; \
})
#define ATOMIC_COMPARE_EXCHANGE(T, _val, _oldval, _newval) __extension__({ \
- T _r; \
+ static_assert(sizeof(T)==4 || sizeof(T)==8, "Type "#T" has incorrect size!"); \
static_assert(sizeof(T)==sizeof((_val).value), "Type "#T" has incorrect size!"); \
- if(sizeof(T) == 4) WRAP_CMPXCHG("l", _r, &(_val).value, (_oldval), (_newval)); \
- else if(sizeof(T) == 8) WRAP_CMPXCHG("q", _r, &(_val).value, (_oldval), (_newval)); \
- _r; \
+ __typeof(_oldval) _old = (_oldval); \
+ if(sizeof(T) == 4) WRAP_CMPXCHG("l", (_oldval), &(_val).value, (_oldval), (_newval)); \
+ else if(sizeof(T) == 8) WRAP_CMPXCHG("q", (_oldval), &(_val).value, (_oldval), (_newval)); \
+ (_oldval) == _old; \
})
/* Atomics using Windows methods */
@@ -187,27 +194,40 @@ inline void _al_mem_barrier(void)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
+inline bool CompareAndSwap32(volatile LONG *dest, LONG newval, LONG *oldval)
+{
+ LONG old = *oldval;
+ *oldval = InterlockedCompareExchange(dest, newval, *oldval);
+ return old == *oldval;
+}
+inline bool CompareAndSwap64(volatile LONGLONG *dest, LONGLONG newval, LONGLONG *oldval)
+{
+ LONGLONG old = *oldval;
+ *oldval = InterlockedCompareExchange64(dest, newval, *oldval);
+ return old == *oldval;
+}
+
#define RAW_CAST(T1, T2, _val) (((union{T2 from; T1 to;}){.from=(_val)}).to)
#define WRAP_ADD(T1, T2, _func, _ptr, _incr) RAW_CAST(T2,T1,_func(RAW_CAST(T1 volatile*,T2 volatile*,(_ptr)), RAW_CAST(T1,T2,(_incr))))
#define WRAP_SUB(T1, T2, _func, _ptr, _decr) RAW_CAST(T2,T1,_func(RAW_CAST(T1 volatile*,T2 volatile*,(_ptr)), -RAW_CAST(T1,T2,(_decr))))
#define WRAP_XCHG(T1, T2, _func, _ptr, _newval) RAW_CAST(T2,T1,_func(RAW_CAST(T1 volatile*,T2 volatile*,(_ptr)), RAW_CAST(T1,T2,(_newval))))
-#define WRAP_CMPXCHG(T1, T2, _func, _ptr, _oldval, _newval) RAW_CAST(T2,T1,_func(RAW_CAST(T1 volatile*,T2 volatile*,(_ptr)), RAW_CAST(T1,T2,(_oldval)), RAW_CAST(T1,T2,(_newval))))
+#define WRAP_CMPXCHG(T1, T2, _func, _ptr, _newval, _oldval) _func(RAW_CAST(T1 volatile*,T2 volatile*,(_ptr)), RAW_CAST(T1,T2,(_newval)), RAW_CAST(T1*,T2*,(_oldval)))
inline int ExchangeInt(volatile int *ptr, int newval)
{ return WRAP_XCHG(LONG,int,InterlockedExchange,ptr,newval); }
inline int CompExchangeInt(volatile int *ptr, int oldval, int newval)
-{ return WRAP_CMPXCHG(LONG,int,InterlockedCompareExchange,ptr,newval, oldval); }
+{ WRAP_CMPXCHG(LONG,int,CompareAndSwap32,ptr,newval,&oldval); return oldval; }
#ifdef _WIN64
inline void *ExchangePtr(XchgPtr *ptr, void *newval)
{ return WRAP_XCHG(LONGLONG,void*,InterlockedExchange64,ptr,newval); }
inline void *CompExchangePtr(XchgPtr *ptr, void *oldval, void *newval)
-{ return WRAP_CMPXCHG(LONGLONG,void*,InterlockedCompareExchange64,ptr,newval,oldval); }
+{ WRAP_CMPXCHG(LONGLONG,void*,CompareAndSwap64,ptr,newval,&oldval); return oldval; }
#else
inline void *ExchangePtr(XchgPtr *ptr, void *newval)
{ return WRAP_XCHG(LONG,void*,InterlockedExchange,ptr,newval); }
inline void *CompExchangePtr(XchgPtr *ptr, void *oldval, void *newval)
-{ return WRAP_CMPXCHG(LONG,void*,InterlockedCompareExchange,ptr,newval,oldval); }
+{ WRAP_CMPXCHG(LONG,void*,CompareAndSwap32,ptr,newval,&oldval); return oldval; }
#endif
@@ -242,15 +262,16 @@ int _al_invalid_atomic_size(); /* not defined */
(sizeof(T)==8) ? WRAP_XCHG(LONGLONG, T, InterlockedExchange64, &(_val).value, (_newval)) : \
(T)_al_invalid_atomic_size())
#define ATOMIC_COMPARE_EXCHANGE(T, _val, _oldval, _newval) \
- ((sizeof(T)==4) ? WRAP_CMPXCHG(LONG, T, InterlockedCompareExchange, &(_val).value, (_newval), (_oldval)) : \
- (sizeof(T)==8) ? WRAP_CMPXCHG(LONGLONG, T, InterlockedCompareExchange64, &(_val).value, (_newval), (_oldval)) : \
- (T)_al_invalid_atomic_size())
+ ((sizeof(T)==4) ? WRAP_CMPXCHG(LONG, T, CompareAndSwap32, &(_val).value, (_newval), &(_oldval)) : \
+ (sizeof(T)==8) ? WRAP_CMPXCHG(LONGLONG, T, CompareAndSwap64, &(_val).value, (_newval), &(_oldval)) : \
+ (bool)_al_invalid_atomic_size())
#else
#error "No atomic functions available on this platform!"
#endif
+typedef unsigned int uint;
typedef ATOMIC(uint) RefCount;
inline void InitRef(RefCount *ptr, uint value)
@@ -264,7 +285,7 @@ inline uint DecrementRef(RefCount *ptr)
inline uint ExchangeRef(RefCount *ptr, uint newval)
{ return ATOMIC_EXCHANGE(uint, *ptr, newval); }
inline uint CompExchangeRef(RefCount *ptr, uint oldval, uint newval)
-{ return ATOMIC_COMPARE_EXCHANGE(uint, *ptr, oldval, newval); }
+{ (void)ATOMIC_COMPARE_EXCHANGE(uint, *ptr, oldval, newval); return oldval; }
#ifdef __cplusplus
}