Browse Source

Atomic operations. (#523)

Zeta 2 years ago
parent
commit
67a6a9c59c
2 changed files with 165 additions and 0 deletions
  1. 6 0
      src/hl.h
  2. 159 0
      src/std/thread.c

+ 6 - 0
src/hl.h

@@ -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)

+ 159 - 0
src/std/thread.c

@@ -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)