On Tue, 25 Nov 2025 at 21:08, Jonathan Wakely <[email protected]> wrote:
>
> 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.

N.B. libc++ uses __ulock_wait based on this check:

#    if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101500

so we might want a similar check, and might want to not define the
__platform_wait_uses_type variable template to true in
bits/atomic_wait.h and instead only do a runtime check in
use_proxy_wait, based on whether a weak symbol is resolved at runtime.
So it would depend on the system where the code executes, instead of
being a compile-time constant.



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