From 6acdcc5a8ad4911db859088980f06f9f1f6e1532 Mon Sep 17 00:00:00 2001 From: rdb Date: Thu, 18 Dec 2025 13:41:38 +0100 Subject: [PATCH] patomic: Fix support for macOS pre-10.12 For now we will unconditionally use ulock APIs on arm64 (which requires macOS 11 anyway) and weak-link it (with fallback to pthreads implementation) on Intel See also #1780 --- dtool/src/dtoolbase/patomic.I | 12 ++++++++++++ dtool/src/dtoolbase/patomic.cxx | 2 +- dtool/src/dtoolbase/patomic.h | 13 +++++++++---- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/dtool/src/dtoolbase/patomic.I b/dtool/src/dtoolbase/patomic.I index d1395c9e90..b679834713 100644 --- a/dtool/src/dtoolbase/patomic.I +++ b/dtool/src/dtoolbase/patomic.I @@ -454,6 +454,12 @@ patomic_notify_one(volatile uint32_t *value) { #elif defined(_WIN32) _patomic_wake_one_func((void *)value); #elif defined(__APPLE__) +#ifndef __arm64__ + if (UNLIKELY(__ulock_wake == nullptr || __ulock_wait == nullptr)) { + _patomic_notify_all(value); + return; + } +#endif __ulock_wake(UL_COMPARE_AND_WAIT, (void *)value, 0); #elif defined(HAVE_POSIX_THREADS) _patomic_notify_all(value); @@ -472,6 +478,12 @@ patomic_notify_all(volatile uint32_t *value) { #elif defined(_WIN32) _patomic_wake_all_func((void *)value); #elif defined(__APPLE__) +#ifndef __arm64__ + if (UNLIKELY(__ulock_wake == nullptr || __ulock_wait == nullptr)) { + _patomic_notify_all(value); + return; + } +#endif __ulock_wake(UL_COMPARE_AND_WAIT | ULF_WAKE_ALL, (void *)value, 0); #elif defined(HAVE_POSIX_THREADS) _patomic_notify_all(value); diff --git a/dtool/src/dtoolbase/patomic.cxx b/dtool/src/dtoolbase/patomic.cxx index 1b939a58c6..26949e564a 100644 --- a/dtool/src/dtoolbase/patomic.cxx +++ b/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); } -#elif !defined(CPPPARSER) && !defined(__linux__) && !defined(__APPLE__) && defined(HAVE_POSIX_THREADS) +#elif !defined(CPPPARSER) && !defined(__linux__) && (!defined(__APPLE__) || !defined(__arm64__)) && defined(HAVE_POSIX_THREADS) // Same as above, but using pthreads. struct alignas(64) WaitTableEntry { diff --git a/dtool/src/dtoolbase/patomic.h b/dtool/src/dtoolbase/patomic.h index 02d1ab6ebc..2b0fdaacc0 100644 --- a/dtool/src/dtoolbase/patomic.h +++ b/dtool/src/dtoolbase/patomic.h @@ -36,9 +36,6 @@ // 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) @@ -173,9 +170,17 @@ 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 void (__stdcall *_patomic_wake_one_func)(PVOID); EXPCL_DTOOL_DTOOLBASE extern void (__stdcall *_patomic_wake_all_func)(PVOID); -#elif !defined(__linux__) && !defined(__APPLE__) && defined(HAVE_POSIX_THREADS) +#elif defined(__APPLE__) && defined(__arm64__) +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); +#elif !defined(__linux__) && defined(HAVE_POSIX_THREADS) 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); +#ifdef __APPLE__ +// Use conditionally since we can't count on support before 10.12. +extern "C" int __ulock_wait(uint32_t op, void *addr, uint64_t value, uint32_t timeout) __attribute__((weak_import)); +extern "C" int __ulock_wake(uint32_t op, void *addr, uint64_t wake_value) __attribute__((weak_import)); +#endif #endif #include "patomic.I"