Skip to content

Commit

Permalink
Atomic operations.
Browse files Browse the repository at this point in the history
  • Loading branch information
Apprentice-Alchemist committed Nov 20, 2022
1 parent 066d5e1 commit c5f64d7
Show file tree
Hide file tree
Showing 2 changed files with 165 additions and 0 deletions.
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)

0 comments on commit c5f64d7

Please sign in to comment.