Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Atomic operations. #985

Merged
merged 12 commits into from
Nov 21, 2022
108 changes: 108 additions & 0 deletions include/hx/StdLibs.h
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,114 @@ bool _hx_atomic_exchange_if(::cpp::Pointer<cpp::AtomicInt> inPtr, int test, int
int _hx_atomic_inc(::cpp::Pointer<cpp::AtomicInt> inPtr );
int _hx_atomic_dec(::cpp::Pointer<cpp::AtomicInt> inPtr );

// Assumptions made:
// Everyone uses GCC, Clang or MSVC
// People are not using 8 year old versions of GCC.

#if defined(__GNUC__) || defined(__clang__)
#define HX_GCC_ATOMICS
#elif defined(_MSC_VER)
#define HX_MSVC_ATOMICS
#include <intrin.h>
#else // Nearly everyone uses GCC, Clang or MSVC, right?
#error "Neither GCC, clang or MSVC is being used. Please contribute the relevant atomic instrinsics for your compiler."
Apprentice-Alchemist marked this conversation as resolved.
Show resolved Hide resolved
#endif

inline int _hx_atomic_add(volatile int *a, int b) {
#if defined(HX_GCC_ATOMICS)
return __atomic_fetch_add(a, b, __ATOMIC_SEQ_CST);
#elif defined(HX_MSVC_ATOMICS)
return _InterlockedExchangeAdd((long volatile *)a, b);
#endif
}

inline int _hx_atomic_sub(volatile int *a, int b) {
#if defined(HX_GCC_ATOMICS)
return __atomic_fetch_sub(a, b, __ATOMIC_SEQ_CST);
#elif defined(HX_MSVC_ATOMICS)
return _InterlockedExchangeAdd((long volatile *)a, -b);
#endif
}

inline int _hx_atomic_and(volatile int *a, int b) {
#if defined(HX_GCC_ATOMICS)
return __atomic_fetch_and(a, b, __ATOMIC_SEQ_CST);
#elif defined(HX_MSVC_ATOMICS)
return _InterlockedAnd((long volatile *)a, b);
#endif
}

inline int _hx_atomic_or(volatile int *a, int b) {
#if defined(HX_GCC_ATOMICS)
return __atomic_fetch_or(a, b, __ATOMIC_SEQ_CST);
#elif defined(HX_MSVC_ATOMICS)
return _InterlockedOr((long volatile *)a, b);
#endif
}

inline int _hx_atomic_xor(int *a, int b) {
#if defined(HX_GCC_ATOMICS)
return __atomic_fetch_xor(a, b, __ATOMIC_SEQ_CST);
#elif defined(HX_MSVC_ATOMICS)
return _InterlockedXor((long volatile *)a, b);
#endif
}

inline int _hx_atomic_compare_exchange(volatile int *a, int expected,
int replacement) {
#if defined(HX_GCC_ATOMICS)
int _expected = expected;
__atomic_compare_exchange(a, &_expected, &replacement, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
return _expected;
#elif defined(HX_MSVC_ATOMICS)
return _InterlockedCompareExchange((long volatile *)a, replacement, expected);
#endif
}

inline int _hx_atomic_exchange(volatile int *a, int replacement) {
#if defined(HX_GCC_ATOMICS)
int ret = 0;
__atomic_exchange(a, &replacement, &ret, __ATOMIC_SEQ_CST);
return ret;
#elif defined(HX_MSVC_ATOMICS)
return _InterlockedExchange((long volatile *)a, replacement);
#endif
}

inline int _hx_atomic_load(volatile int *a) {
#if defined(HX_GCC_ATOMICS)
int ret = 0;
__atomic_load(a, &ret, __ATOMIC_SEQ_CST);
return ret;
#elif defined(HX_MSVC_ATOMICS)
return _InterlockedXor((long volatile *)a, 0);
#endif
}

inline int _hx_atomic_store(volatile int *a, int value) {
#if defined(HX_GCC_ATOMICS)
__atomic_store(a, &value, __ATOMIC_SEQ_CST);
return value;
#elif defined(HX_MSVC_ATOMICS)
_InterlockedExchange((long volatile *)a, value);
return value;
#endif
}

inline void* _hx_atomic_compare_exchange_ptr(volatile void **a, void *expected, void* replacement) {
#if defined(HX_GCC_ATOMICS)
void* _expected = expected;
__atomic_compare_exchange(a, (volatile void **)&_expected, (volatile void**)&replacement, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
return _expected;
#elif defined(HX_MSVC_ATOMICS)
return _InterlockedCompareExchangePointer((void *volatile *)a, replacement, expected);
#endif
}

inline void* _hx_atomic_compare_exchange_cast_ptr(void *a, void *expected, void *replacement) {
return _hx_atomic_compare_exchange_ptr((volatile void **)a, expected, replacement);
}

Array<String> __hxcpp_get_call_stack(bool inSkipLast);
Array<String> __hxcpp_get_exception_stack();
#define HXCPP_HAS_CLASSLIST
Expand Down
112 changes: 0 additions & 112 deletions include/hx/Thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,118 +41,6 @@
#undef RegisterClass
#endif

#if defined(ANDROID)

#define HX_HAS_ATOMIC 1

#if (HXCPP_ANDROID_PLATFORM>=16)
// Nice one, google, no one was using that.
#define __ATOMIC_INLINE__ static __inline__ __attribute__((always_inline))
// returns 0=exchange took place, 1=not
__ATOMIC_INLINE__ int __atomic_cmpxchg(int old, int _new, volatile int *ptr)
{ return __sync_val_compare_and_swap(ptr, old, _new) != old; }
__ATOMIC_INLINE__ int __atomic_dec(volatile int *ptr) { return __sync_fetch_and_sub (ptr, 1); }
__ATOMIC_INLINE__ int __atomic_inc(volatile int *ptr) { return __sync_fetch_and_add (ptr, 1); }
#else
#include <sys/atomics.h>
#endif

// returns 1 if exchange took place
inline bool HxAtomicExchangeIf(int inTest, int inNewVal,volatile int *ioWhere)
{ return !__atomic_cmpxchg(inTest, inNewVal, ioWhere); }
inline bool HxAtomicExchangeIfPtr(void *inTest, void *inNewVal,void * volatile *ioWhere)
{ return __sync_val_compare_and_swap(ioWhere, inTest, inNewVal)==inTest; }

// Returns old value naturally
inline int HxAtomicInc(volatile int *ioWhere)
{ return __atomic_inc(ioWhere); }
inline int HxAtomicDec(volatile int *ioWhere)
{ return __atomic_dec(ioWhere); }


#elif defined(HX_WINDOWS)

inline bool HxAtomicExchangeIf(int inTest, int inNewVal,volatile int *ioWhere)
{ return InterlockedCompareExchange((volatile LONG *)ioWhere, inNewVal, inTest)==inTest; }

inline bool HxAtomicExchangeIfPtr(void *inTest, void *inNewVal,void *volatile *ioWhere)
{ return InterlockedCompareExchangePointer(ioWhere, inNewVal, inTest)==inTest; }

// Make it return old value
inline int HxAtomicInc(volatile int *ioWhere)
{ return InterlockedIncrement((volatile LONG *)ioWhere)-1; }
inline int HxAtomicDec(volatile int *ioWhere)
{ return InterlockedDecrement((volatile LONG *)ioWhere)+1; }

#define HX_HAS_ATOMIC 1

#elif defined(HX_MACOS) || defined(IPHONE) || defined(APPLETV)
#include <libkern/OSAtomic.h>

#define HX_HAS_ATOMIC 1

inline bool HxAtomicExchangeIf(int inTest, int inNewVal,volatile int *ioWhere)
{ return OSAtomicCompareAndSwap32Barrier(inTest, inNewVal, ioWhere); }
inline bool HxAtomicExchangeIfPtr(void *inTest, void *inNewVal,void * volatile *ioWhere)
{ return OSAtomicCompareAndSwapPtrBarrier(inTest, inNewVal, ioWhere); }
inline int HxAtomicInc(volatile int *ioWhere)
{ return OSAtomicIncrement32Barrier(ioWhere)-1; }
inline int HxAtomicDec(volatile int *ioWhere)
{ return OSAtomicDecrement32Barrier(ioWhere)+1; }


#elif defined(HX_LINUX)

#define HX_HAS_ATOMIC 1

inline bool HxAtomicExchangeIf(int inTest, int inNewVal,volatile int *ioWhere)
{ return __sync_bool_compare_and_swap(ioWhere, inTest, inNewVal); }
inline bool HxAtomicExchangeIfPtr(void *inTest, void *inNewVal,void *volatile *ioWhere)
{ return __sync_bool_compare_and_swap(ioWhere, inTest, inNewVal); }
// Returns old value naturally
inline int HxAtomicInc(volatile int *ioWhere)
{ return __sync_fetch_and_add(ioWhere,1); }
inline int HxAtomicDec(volatile int *ioWhere)
{ return __sync_fetch_and_sub(ioWhere,1); }

#else

#define HX_HAS_ATOMIC 0

inline bool HxAtomicExchangeIfPtr(void *inTest, void *inNewVal,void *volatile *ioWhere)
{
if (*ioWhere == inTest)
{
*ioWhere = inNewVal;
return true;
}
return false;
}


inline int HxAtomicExchangeIf(int inTest, int inNewVal,volatile int *ioWhere)
{
if (*ioWhere == inTest)
{
*ioWhere = inNewVal;
return true;
}
return false;
}
inline int HxAtomicInc(volatile int *ioWhere)
{ return (*ioWhere)++; }
inline int HxAtomicDec(volatile int *ioWhere)
{ return (*ioWhere)--; }


#endif

inline bool HxAtomicExchangeIfCastPtr(void *inTest, void *inNewVal,void *ioWhere)
{
return HxAtomicExchangeIfPtr(inTest, inNewVal, (void *volatile *)ioWhere);
}


#if defined(HX_WINDOWS)


Expand Down
4 changes: 2 additions & 2 deletions src/String.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1172,7 +1172,7 @@ const ::String &::String::makePermanent() const
{
unsigned int myHash = hash();
{
while(! HxAtomicExchangeIf(0,1,&sPermanentStringSetMutex) )
while(_hx_atomic_compare_exchange(&sPermanentStringSetMutex, 0, 1) != 0)
__hxcpp_gc_safe_point();
TNonGcStringSet *element = sPermanentStringSet->find(myHash , *this);
sPermanentStringSetMutex = 0;
Expand All @@ -1198,7 +1198,7 @@ const ::String &::String::makePermanent() const
const_cast<String *>(this)->__s = s;
}

while(! HxAtomicExchangeIf(0,1,&sPermanentStringSetMutex) )
while(_hx_atomic_compare_exchange(&sPermanentStringSetMutex, 0, 1) != 0)
__hxcpp_gc_safe_point();
sPermanentStringSet->set(*this,null());
sPermanentStringSetMutex = 0;
Expand Down
6 changes: 3 additions & 3 deletions src/hx/Thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -930,17 +930,17 @@ int __hxcpp_GetCurrentThreadNumber()

bool _hx_atomic_exchange_if(::cpp::Pointer<cpp::AtomicInt> inPtr, int test, int newVal )
{
return HxAtomicExchangeIf(test, newVal, inPtr);
return _hx_atomic_compare_exchange(inPtr, test, newVal) == test;
}

int _hx_atomic_inc(::cpp::Pointer<cpp::AtomicInt> inPtr )
{
return HxAtomicInc(inPtr);
return _hx_atomic_add(inPtr, 1);
}

int _hx_atomic_dec(::cpp::Pointer<cpp::AtomicInt> inPtr )
{
return HxAtomicDec(inPtr);
return _hx_atomic_sub(inPtr, 1);
}


Loading