Browse Source

patomic: Implement futexes on macOS using ulock API

This is what is also used by the libc++ futex implementation on macOS, and should be more efficient than the fallback hash table approach
rdb 2 years ago
parent
commit
034f1ea358
3 changed files with 17 additions and 2 deletions
  1. 6 0
      dtool/src/dtoolbase/patomic.I
  2. 1 1
      dtool/src/dtoolbase/patomic.cxx
  3. 10 1
      dtool/src/dtoolbase/patomic.h

+ 6 - 0
dtool/src/dtoolbase/patomic.I

@@ -433,6 +433,8 @@ patomic_wait(const volatile uint32_t *value, uint32_t old) {
   while (*value == old) {
   while (*value == old) {
     _patomic_wait_func((volatile void *)value, &old, sizeof(uint32_t), INFINITE);
     _patomic_wait_func((volatile void *)value, &old, sizeof(uint32_t), INFINITE);
   }
   }
+#elif defined(__APPLE__)
+  __ulock_wait(UL_COMPARE_AND_WAIT, (void *)value, old, 0);
 #elif defined(HAVE_POSIX_THREADS)
 #elif defined(HAVE_POSIX_THREADS)
   _patomic_wait(value, old);
   _patomic_wait(value, old);
 #else
 #else
@@ -451,6 +453,8 @@ patomic_notify_one(volatile uint32_t *value) {
 //  WakeByAddressSingle((void *)value);
 //  WakeByAddressSingle((void *)value);
 #elif defined(_WIN32)
 #elif defined(_WIN32)
   _patomic_wake_one_func((void *)value);
   _patomic_wake_one_func((void *)value);
+#elif defined(__APPLE__)
+  __ulock_wake(UL_COMPARE_AND_WAIT, (void *)value, 0);
 #elif defined(HAVE_POSIX_THREADS)
 #elif defined(HAVE_POSIX_THREADS)
   _patomic_notify_all(value);
   _patomic_notify_all(value);
 #endif
 #endif
@@ -467,6 +471,8 @@ patomic_notify_all(volatile uint32_t *value) {
 //  WakeByAddressAll((void *)value);
 //  WakeByAddressAll((void *)value);
 #elif defined(_WIN32)
 #elif defined(_WIN32)
   _patomic_wake_all_func((void *)value);
   _patomic_wake_all_func((void *)value);
+#elif defined(__APPLE__)
+  __ulock_wake(UL_COMPARE_AND_WAIT | ULF_WAKE_ALL, (void *)value, 0);
 #elif defined(HAVE_POSIX_THREADS)
 #elif defined(HAVE_POSIX_THREADS)
   _patomic_notify_all(value);
   _patomic_notify_all(value);
 #endif
 #endif

+ 1 - 1
dtool/src/dtoolbase/patomic.cxx

@@ -125,7 +125,7 @@ initialize_wait(volatile VOID *addr, PVOID cmp, SIZE_T size, DWORD timeout) {
   return emulated_wait(addr, cmp, size, timeout);
   return emulated_wait(addr, cmp, size, timeout);
 }
 }
 
 
-#elif !defined(CPPPARSER) && !defined(__linux__) && defined(HAVE_POSIX_THREADS)
+#elif !defined(CPPPARSER) && !defined(__linux__) && !defined(__APPLE__) && defined(HAVE_POSIX_THREADS)
 
 
 // Same as above, but using pthreads.
 // Same as above, but using pthreads.
 struct alignas(64) WaitTableEntry {
 struct alignas(64) WaitTableEntry {

+ 10 - 1
dtool/src/dtoolbase/patomic.h

@@ -32,6 +32,15 @@
 #include <unistd.h>
 #include <unistd.h>
 #endif
 #endif
 
 
+#ifdef __APPLE__
+// Undocumented API, see https://outerproduct.net/futex-dictionary.html
+#define UL_COMPARE_AND_WAIT 1
+#define ULF_WAKE_ALL 0x00000100
+
+extern "C" int __ulock_wait(uint32_t op, void *addr, uint64_t value, uint32_t timeout);
+extern "C" int __ulock_wake(uint32_t op, void *addr, uint64_t wake_value);
+#endif
+
 #if defined(THREAD_DUMMY_IMPL) || defined(THREAD_SIMPLE_IMPL)
 #if defined(THREAD_DUMMY_IMPL) || defined(THREAD_SIMPLE_IMPL)
 
 
 /**
 /**
@@ -164,7 +173,7 @@ ALWAYS_INLINE void patomic_notify_all(volatile uint32_t *value);
 EXPCL_DTOOL_DTOOLBASE extern BOOL (__stdcall *_patomic_wait_func)(volatile VOID *, PVOID, SIZE_T, DWORD);
 EXPCL_DTOOL_DTOOLBASE extern BOOL (__stdcall *_patomic_wait_func)(volatile VOID *, PVOID, SIZE_T, DWORD);
 EXPCL_DTOOL_DTOOLBASE extern void (__stdcall *_patomic_wake_one_func)(PVOID);
 EXPCL_DTOOL_DTOOLBASE extern void (__stdcall *_patomic_wake_one_func)(PVOID);
 EXPCL_DTOOL_DTOOLBASE extern void (__stdcall *_patomic_wake_all_func)(PVOID);
 EXPCL_DTOOL_DTOOLBASE extern void (__stdcall *_patomic_wake_all_func)(PVOID);
-#elif !defined(__linux__) && defined(HAVE_POSIX_THREADS)
+#elif !defined(__linux__) && !defined(__APPLE__) && defined(HAVE_POSIX_THREADS)
 EXPCL_DTOOL_DTOOLBASE void _patomic_wait(const volatile uint32_t *value, uint32_t old);
 EXPCL_DTOOL_DTOOLBASE void _patomic_wait(const volatile uint32_t *value, uint32_t old);
 EXPCL_DTOOL_DTOOLBASE void _patomic_notify_all(volatile uint32_t *value);
 EXPCL_DTOOL_DTOOLBASE void _patomic_notify_all(volatile uint32_t *value);
 #endif
 #endif