ref.h compiles in C++

Check for GCC version >=4.7 [covers GCC or, theoretically, Intel C Compiler] or __has_builtin(__atomic_add_fetch) [covers Clang]. If either of these are found, prefer the GCC atomic builtins instead of the C11 builtins.

Also: Gates Microsoft atomics on _MSC_VER, not _WIN32. This may help improve compatibility with mingw but has not been tested.
This commit is contained in:
mcc 2019-07-10 17:02:30 -04:00 committed by Bjorn
parent f208a5e067
commit 99f8122f23
1 changed files with 28 additions and 8 deletions

View File

@ -3,26 +3,46 @@
#pragma once
#if defined(LOVR_ENABLE_THREAD) && defined(_WIN32)
#ifndef LOVR_ENABLE_THREAD
// Thread module is off, don't use atomics
typedef uint32_t Ref;
static inline uint32_t ref_inc(Ref* ref) { return ++*ref; }
static inline uint32_t ref_dec(Ref* ref) { return --*ref; }
#elif defined(_MSC_VER)
// MSVC atomics
#include <intrin.h>
typedef uint32_t Ref;
static inline uint32_t ref_inc(Ref* ref) { return _InterlockedIncrement(ref); }
static inline uint32_t ref_dec(Ref* ref) { return _InterlockedDecrement(ref); }
#elif defined(LOVR_ENABLE_THREAD)
#elif (defined(__GNUC_MINOR__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))) \
|| (defined(__has_builtin) && __has_builtin(__atomic_add_fetch) && __has_builtin(__atomic_sub_fetch))
// GCC/Clang atomics
typedef uint32_t Ref;
static inline uint32_t ref_inc(Ref* ref) { return __atomic_add_fetch(ref, 1, __ATOMIC_SEQ_CST); }
static inline uint32_t ref_dec(Ref* ref) { return __atomic_add_fetch(ref, 1, __ATOMIC_SEQ_CST); }
#else
// No known compiler-specific atomics-- fall back to C11 atomics
// stdatomic.h doesn't work in c++ (except on Android, where it is fine)
#if !defined(__ANDROID__) && defined(__cplusplus)
#error "The header core/ref.h cannot currently be included from C++ when threading is enabled with this compiler. Either remove your ref.h include from any C++ files, or rebuild LOVR with -DLOVR_ENABLE_THREAD=OFF"
#endif
#include <stdatomic.h>
typedef _Atomic(uint32_t) Ref;
static inline uint32_t ref_inc(Ref* ref) { return atomic_fetch_add(ref, 1) + 1; }
static inline uint32_t ref_dec(Ref* ref) { return atomic_fetch_sub(ref, 1) - 1; }
#else
typedef uint32_t Ref;
static inline uint32_t ref_inc(Ref* ref) { return ++*ref; }
static inline uint32_t ref_dec(Ref* ref) { return --*ref; }
#endif
void* _lovrAlloc(size_t size);