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

Reply via email to