This defines __platform_wait, __platform_notify, and
__platform_wait_until for darwin, making use of the __ulock_wait and
__ulock_wake functions.
As with the FreeBSD _mutx_op syscall, these functions support both
32-bit and 64-bit types.
libstdc++-v3/ChangeLog:
PR libstdc++/120527
* include/bits/atomic_wait.h [__APPLE__]: Reuse FreeBSD
definitions of __platform_wait_t and __platform_wait_uses_type.
* src/c++20/atomic.cc [__APPLE__] (_GLIBCXX_HAVE_PLATFORM_WAIT)
(__platform_wait, __platform_notify, __platform_wait_until):
Define.
---
Untested, so I don't plan to commit this, but maybe Iain will want to
test it some time.
libstdc++-v3/include/bits/atomic_wait.h | 2 +-
libstdc++-v3/src/c++20/atomic.cc | 49 +++++++++++++++++++++++++
2 files changed, 50 insertions(+), 1 deletion(-)
diff --git a/libstdc++-v3/include/bits/atomic_wait.h
b/libstdc++-v3/include/bits/atomic_wait.h
index 0205df40d68c..752f0e1e1baa 100644
--- a/libstdc++-v3/include/bits/atomic_wait.h
+++ b/libstdc++-v3/include/bits/atomic_wait.h
@@ -68,7 +68,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
inline constexpr bool __platform_wait_uses_type
= __detail::__waitable<_Tp>
&& sizeof(_Tp) == sizeof(int) && alignof(_Tp) >= 4;
-#elif defined __FreeBSD__ && __SIZEOF_LONG__ == 8
+#elif defined __APPLE__ || (defined __FreeBSD__ && __SIZEOF_LONG__ == 8)
namespace __detail
{
using __platform_wait_t = __UINT64_TYPE__;
diff --git a/libstdc++-v3/src/c++20/atomic.cc b/libstdc++-v3/src/c++20/atomic.cc
index af3b074a52c9..57509caca87a 100644
--- a/libstdc++-v3/src/c++20/atomic.cc
+++ b/libstdc++-v3/src/c++20/atomic.cc
@@ -39,6 +39,15 @@
# include <syscall.h>
# include <sys/time.h> // timespec
# define _GLIBCXX_HAVE_PLATFORM_WAIT 1
+#elif defined __APPLE__
+extern "C" int
+__ulock_wait(uint32_t operation, void* addr, uint64_t value, uint32_t timeout);
+extern "C" int
+__ulock_wake(uint32_t operation, void* addr, uint64_t wake_value);
+# define UL_COMPARE_AND_WAIT 1
+# define UL_COMPARE_AND_WAIT64 5
+# define ULF_WAKE_ALL 0x00000100
+# define _GLIBCXX_HAVE_PLATFORM_WAIT 1
#elif defined __FreeBSD__ && __SIZEOF_LONG__ == 8
# include <sys/types.h>
# include <sys/umtx.h>
@@ -113,6 +122,46 @@ namespace
}
return true;
}
+#elif defined __APPLE__
+ void
+ __platform_wait(const void* addr, uint64_t val, int obj_sz) noexcept
+ {
+ const uint32_t op = obj_sz == 4 ? UL_COMPARE_AND_WAIT :
UL_COMPARE_AND_WAIT64;
+ if (__ulock_wait(op, const_cast<void*>(addr), val, 0))
+ if (errno != EINTR && errno != EFAULT)
+ __throw_system_error(errno);
+ }
+
+ void
+ __platform_notify(const void* addr, bool all, int obj_sz) noexcept
+ {
+ uint32_t op = obj_sz == 4 ? UL_COMPARE_AND_WAIT : UL_COMPARE_AND_WAIT64;
+ if (all)
+ op |= ULF_WAKE_ALL;
+ __ulock_wake(op, const_cast<void*>(addr), 0);
+ }
+
+ // returns true if wait ended before timeout
+ bool
+ __platform_wait_until(const void* addr, uint64_t val,
+ const __wait_clock_t::time_point& atime,
+ int obj_sz) noexcept
+ {
+ auto reltime
+ = chrono::ceil<chrono::microseconds>(__wait_clock_t::now() - atime);
+ if (reltime <= reltime.zero())
+ return false;
+ uint32_t op = obj_sz == 4 ? UL_COMPARE_AND_WAIT : UL_COMPARE_AND_WAIT64;
+
+ if (__ulock_wait(op, const_cast<void*>(addr), val, reltime.count()))
+ {
+ if (errno == ETIMEDOUT)
+ return false;
+ if (errno != EINTR && errno != EFAULT)
+ __throw_system_error(errno);
+ }
+ return true;
+ }
#elif defined __FreeBSD__ && __SIZEOF_LONG__ == 8
void
__platform_wait(const void* addr, uint64_t val, int obj_sz) noexcept
--
2.51.1