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. #523

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/hl.h
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,12 @@ typedef unsigned long long uint64;
#define HL_API IMPORT
#endif

#if defined(HL_VCC)
#define HL_INLINE __inline
#else
#define HL_INLINE inline
#endif

// -------------- UNICODE -----------------------------------

#if defined(HL_WIN) && !defined(HL_LLVM)
Expand Down
159 changes: 159 additions & 0 deletions src/std/thread.c
Original file line number Diff line number Diff line change
Expand Up @@ -962,3 +962,162 @@ HL_PRIM void hl_thread_set_name( hl_thread *t, const char *name ) {
DEFINE_PRIM(_THREAD, thread_current, _NO_ARG);
DEFINE_PRIM(_THREAD, thread_create, _FUN(_VOID,_NO_ARG));
DEFINE_PRIM(_VOID, thread_set_name, _THREAD _BYTES);

// ----------------- ATOMICS

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

#if defined(HL_GCC) || defined(HL_CLANG)
#define HL_GCC_ATOMICS
#elif defined(HL_VCC)
#define HL_VCC_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."
#endif

HL_PRIM int hl_atomic_add32(int *a, int b) {
#if defined(HL_GCC_ATOMICS)
return __atomic_fetch_add(a, b, __ATOMIC_SEQ_CST);
#elif defined(HL_VCC_ATOMICS)
return _InterlockedExchangeAdd((LONG volatile *)a, b);
#endif
}

HL_PRIM int hl_atomic_sub32(int *a, int b) {
#if defined(HL_GCC_ATOMICS)
return __atomic_fetch_sub(a, b, __ATOMIC_SEQ_CST);
#elif defined(HL_VCC_ATOMICS)
return _InterlockedExchangeAdd((LONG volatile *)a, -b);
#endif
}

HL_PRIM int hl_atomic_and32(int *a, int b) {
#if defined(HL_GCC_ATOMICS)
return __atomic_fetch_and(a, b, __ATOMIC_SEQ_CST);
#elif defined(HL_VCC_ATOMICS)
return _InterlockedAnd((LONG volatile *)a, b);
#endif
}

HL_PRIM int hl_atomic_or32(int *a, int b) {
#if defined(HL_GCC_ATOMICS)
return __atomic_fetch_or(a, b, __ATOMIC_SEQ_CST);
#elif defined(HL_VCC_ATOMICS)
return _InterlockedOr((LONG volatile *)a, b);
#endif
}

HL_PRIM int hl_atomic_xor32(int *a, int b) {
#if defined(HL_GCC_ATOMICS)
return __atomic_fetch_xor(a, b, __ATOMIC_SEQ_CST);
#elif defined(HL_VCC_ATOMICS)
return _InterlockedXor((LONG volatile *)a, b);
#endif
}

HL_PRIM int hl_atomic_compare_exchange32(int *a, int expected,
int replacement) {
#if defined(HL_GCC_ATOMICS)
int _expected = expected;
__atomic_compare_exchange(a, &_expected, &replacement, false,
__ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
return _expected;
#elif defined(HL_VCC_ATOMICS)
return _InterlockedCompareExchange((LONG volatile *)a, replacement, expected);
#endif
}

HL_PRIM void *hl_atomic_compare_exchange_ptr(void **a, void *expected,
void *replacement) {
#if defined(HL_GCC_ATOMICS)
void *_expected = expected;
__atomic_compare_exchange(a, &_expected, &replacement, false,
__ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
return _expected;
#elif defined(HL_VCC_ATOMICS)
return _InterlockedCompareExchangePointer((void *volatile *)a, replacement,
expected);
#endif
}

HL_PRIM int hl_atomic_exchange32(int *a, int replacement) {
#if defined(HL_GCC_ATOMICS)
int ret = 0;
__atomic_exchange(a, &replacement, &ret, __ATOMIC_SEQ_CST);
return ret;
#elif defined(HL_VCC_ATOMICS)
return _InterlockedExchange((LONG volatile *)a, replacement);
#endif
}

HL_PRIM void *hl_atomic_exchange_ptr(void **a, void *replacement) {
#if defined(HL_GCC_ATOMICS)
void *ret = 0;
__atomic_exchange(a, &replacement, &ret, __ATOMIC_SEQ_CST);
return ret;
#elif defined(HL_VCC_ATOMICS)
return _InterlockedExchangePointer((void *volatile *)a, replacement);
#endif
}

HL_PRIM int hl_atomic_load32(int *a) {
#if defined(HL_GCC_ATOMICS)
int ret = 0;
__atomic_load(a, &ret, __ATOMIC_SEQ_CST);
return ret;
#elif defined(HL_VCC_ATOMICS)
return _InterlockedXor((LONG volatile *)a, 0);
#endif
}

HL_PRIM void *hl_atomic_load_ptr(void **a) {
#if defined(HL_GCC_ATOMICS)
void *ret = 0;
__atomic_load(a, &ret, __ATOMIC_SEQ_CST);
return ret;
#elif defined(HL_VCC_ATOMICS)
#ifdef HL_64
return (void *)_InterlockedXor64((__int64 volatile *)a, 0);
#else
return (void *)_InterlockedXor((LONG volatile *)a, 0);
#endif
#endif
}

HL_PRIM int hl_atomic_store32(int *a, int value) {
#if defined(HL_GCC_ATOMICS)
__atomic_store(a, &value, __ATOMIC_SEQ_CST);
return value;
#elif defined(HL_VCC_ATOMICS)
_InterlockedExchange((LONG volatile *)a, value);
return value;
#endif
}

HL_PRIM void *hl_atomic_store_ptr(void **a, void *value) {
#if defined(HL_GCC_ATOMICS)
__atomic_store(a, &value, __ATOMIC_SEQ_CST);
return value;
#elif defined(HL_VCC_ATOMICS)
_InterlockedExchangePointer((void *volatile *)a, value);
return value;
#endif
}

DEFINE_PRIM(_I32, atomic_add32, _REF(_I32) _I32)
DEFINE_PRIM(_I32, atomic_sub32, _REF(_I32) _I32)
DEFINE_PRIM(_I32, atomic_and32, _REF(_I32) _I32)
DEFINE_PRIM(_I32, atomic_or32, _REF(_I32) _I32)
DEFINE_PRIM(_I32, atomic_xor32, _REF(_I32) _I32)
DEFINE_PRIM(_I32, atomic_compare_exchange32, _REF(_I32) _I32 _I32)
DEFINE_PRIM(_DYN, atomic_compare_exchange_ptr, _REF(_DYN) _DYN _DYN)
DEFINE_PRIM(_I32, atomic_exchange32, _REF(_I32) _I32)
DEFINE_PRIM(_DYN, atomic_exchange_ptr, _REF(_DYN) _DYN)
DEFINE_PRIM(_I32, atomic_load32, _REF(_I32))
DEFINE_PRIM(_DYN, atomic_load_ptr, _REF(_DYN))
DEFINE_PRIM(_I32, atomic_store32, _REF(_I32) _I32)
DEFINE_PRIM(_DYN, atomic_store_ptr, _REF(_DYN) _DYN)