-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[libc++] Allows any types of size 4 and 8 to use native platform ulock_wait #161086
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
7ca1290
1949548
62a774e
c5d6769
71bba6f
9450b1d
e979655
5f39c04
f536ff4
2a87a3e
9950df2
012aad2
2711c89
c24586b
59be9f6
e5df955
6b6f018
1729b7a
114c868
8c5cbf5
94a5d68
b92abf2
8dda22a
4105e50
310400f
3959e16
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,7 +18,9 @@ | |
| #include <__thread/poll_with_backoff.h> | ||
| #include <__type_traits/conjunction.h> | ||
| #include <__type_traits/decay.h> | ||
| #include <__type_traits/has_unique_object_representation.h> | ||
| #include <__type_traits/invoke.h> | ||
| #include <__type_traits/is_same.h> | ||
| #include <__type_traits/void_t.h> | ||
| #include <__utility/declval.h> | ||
| #include <cstring> | ||
|
|
@@ -38,6 +40,8 @@ _LIBCPP_BEGIN_NAMESPACE_STD | |
| // The below implementations look ugly to support C++03 | ||
| template <class _Tp, class = void> | ||
| struct __atomic_waitable_traits { | ||
| using __value_type _LIBCPP_NODEBUG = void; | ||
|
|
||
| template <class _AtomicWaitable> | ||
| static void __atomic_load(_AtomicWaitable&&, memory_order) = delete; | ||
|
|
||
|
|
@@ -58,6 +62,9 @@ struct __atomic_waitable< _Tp, | |
| #if _LIBCPP_STD_VER >= 20 | ||
| # if _LIBCPP_HAS_THREADS | ||
|
|
||
| # if !_LIBCPP_AVAILABILITY_HAS_NEW_SYNC | ||
|
|
||
| // old dylib interface kept for backwards compatibility | ||
huixie90 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| _LIBCPP_EXPORTED_FROM_ABI void __cxx_atomic_notify_one(void const volatile*) _NOEXCEPT; | ||
| _LIBCPP_EXPORTED_FROM_ABI void __cxx_atomic_notify_all(void const volatile*) _NOEXCEPT; | ||
| _LIBCPP_EXPORTED_FROM_ABI __cxx_contention_t __libcpp_atomic_monitor(void const volatile*) _NOEXCEPT; | ||
|
|
@@ -69,6 +76,113 @@ _LIBCPP_EXPORTED_FROM_ABI __cxx_contention_t | |
| __libcpp_atomic_monitor(__cxx_atomic_contention_t const volatile*) _NOEXCEPT; | ||
| _LIBCPP_EXPORTED_FROM_ABI void | ||
| __libcpp_atomic_wait(__cxx_atomic_contention_t const volatile*, __cxx_contention_t) _NOEXCEPT; | ||
| # endif // !_LIBCPP_AVAILABILITY_HAS_NEW_SYNC | ||
|
|
||
| // new dylib interface | ||
|
|
||
| // return the global contention state's current value for the address | ||
| _LIBCPP_AVAILABILITY_NEW_SYNC _LIBCPP_EXPORTED_FROM_ABI __cxx_contention_t | ||
| __atomic_monitor_global(void const* __address) _NOEXCEPT; | ||
|
|
||
| // wait on the global contention state to be changed from the given value for the address | ||
| _LIBCPP_AVAILABILITY_NEW_SYNC _LIBCPP_EXPORTED_FROM_ABI void | ||
| __atomic_wait_global_table(void const* __address, __cxx_contention_t __monitor_value) _NOEXCEPT; | ||
|
|
||
| // notify one waiter waiting on the global contention state for the address | ||
| _LIBCPP_AVAILABILITY_NEW_SYNC _LIBCPP_EXPORTED_FROM_ABI void __atomic_notify_one_global_table(void const*) _NOEXCEPT; | ||
|
|
||
| // notify all waiters waiting on the global contention state for the address | ||
| _LIBCPP_AVAILABILITY_NEW_SYNC _LIBCPP_EXPORTED_FROM_ABI void __atomic_notify_all_global_table(void const*) _NOEXCEPT; | ||
|
|
||
| // wait on the address directly with the native platform wait | ||
| template <std::size_t _Size> | ||
| _LIBCPP_AVAILABILITY_NEW_SYNC _LIBCPP_EXPORTED_FROM_ABI void | ||
| __atomic_wait_native(void const* __address, void const* __old_value) _NOEXCEPT; | ||
|
|
||
| // notify one waiter waiting on the address directly with the native platform wait | ||
| template <std::size_t _Size> | ||
| _LIBCPP_AVAILABILITY_NEW_SYNC _LIBCPP_EXPORTED_FROM_ABI void __atomic_notify_one_native(const void*) _NOEXCEPT; | ||
|
|
||
| // notify all waiters waiting on the address directly with the native platform wait | ||
| template <std::size_t _Size> | ||
| _LIBCPP_AVAILABILITY_NEW_SYNC _LIBCPP_EXPORTED_FROM_ABI void __atomic_notify_all_native(const void*) _NOEXCEPT; | ||
|
|
||
| # ifdef __linux__ | ||
| # define _LIBCPP_NATIVE_PLATFORM_WAIT_SIZES(_APPLY) _APPLY(4) | ||
| # elif defined(__APPLE__) | ||
| # define _LIBCPP_NATIVE_PLATFORM_WAIT_SIZES(_APPLY) \ | ||
| _APPLY(4) \ | ||
| _APPLY(8) | ||
| # elif defined(__FreeBSD__) && __SIZEOF_LONG__ == 8 | ||
| # define _LIBCPP_NATIVE_PLATFORM_WAIT_SIZES(_APPLY) _APPLY(8) | ||
| # elif defined(_WIN32) | ||
| # define _LIBCPP_NATIVE_PLATFORM_WAIT_SIZES(_APPLY) _APPLY(8) | ||
| # else | ||
| # define _LIBCPP_NATIVE_PLATFORM_WAIT_SIZES(_APPLY) _APPLY(sizeof(__cxx_contention_t)) | ||
| # endif // __linux__ | ||
|
|
||
huixie90 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| // concepts defines the types are supported natively by the platform's wait | ||
|
|
||
| # if defined(_LIBCPP_ABI_ATOMIC_WAIT_NATIVE_BY_SIZE) | ||
|
|
||
| _LIBCPP_HIDE_FROM_ABI constexpr bool __has_native_atomic_wait_impl(size_t __size) { | ||
| switch (__size) { | ||
| # define _LIBCPP_MAKE_CASE(n) \ | ||
| case n: \ | ||
| return true; | ||
ldionne marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| _LIBCPP_NATIVE_PLATFORM_WAIT_SIZES(_LIBCPP_MAKE_CASE) | ||
| default: | ||
| return false; | ||
| # undef _LIBCPP_MAKE_CASE | ||
| }; | ||
| } | ||
|
|
||
| template <class _Tp> | ||
| concept __has_native_atomic_wait = | ||
| has_unique_object_representations_v<_Tp> && __has_native_atomic_wait_impl(sizeof(_Tp)); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we need |
||
|
|
||
| # else // _LIBCPP_ABI_ATOMIC_WAIT_NATIVE_BY_SIZE | ||
|
|
||
| template <class _Tp> | ||
| concept __has_native_atomic_wait = is_same_v<_Tp, __cxx_contention_t>; | ||
|
|
||
| # endif // _LIBCPP_ABI_ATOMIC_WAIT_NATIVE_BY_SIZE | ||
|
|
||
| # if _LIBCPP_AVAILABILITY_HAS_NEW_SYNC | ||
|
|
||
| template <class _AtomicWaitable, class _Poll> | ||
| struct __atomic_wait_backoff_impl { | ||
| const _AtomicWaitable& __a_; | ||
| _Poll __poll_; | ||
| memory_order __order_; | ||
|
|
||
| using __waitable_traits _LIBCPP_NODEBUG = __atomic_waitable_traits<__decay_t<_AtomicWaitable> >; | ||
| using __value_type _LIBCPP_NODEBUG = typename __waitable_traits::__value_type; | ||
|
|
||
| _LIBCPP_HIDE_FROM_ABI bool operator()(chrono::nanoseconds __elapsed) const { | ||
| if (__elapsed > chrono::microseconds(4)) { | ||
| auto __contention_address = const_cast<const void*>( | ||
| static_cast<const volatile void*>(__waitable_traits::__atomic_contention_address(__a_))); | ||
|
|
||
| if constexpr (__has_native_atomic_wait<__value_type>) { | ||
| auto __atomic_value = __waitable_traits::__atomic_load(__a_, __order_); | ||
| if (__poll_(__atomic_value)) | ||
| return true; | ||
| std::__atomic_wait_native<sizeof(__value_type)>(__contention_address, std::addressof(__atomic_value)); | ||
| } else { | ||
| __cxx_contention_t __monitor_val = std::__atomic_monitor_global(__contention_address); | ||
| auto __atomic_value = __waitable_traits::__atomic_load(__a_, __order_); | ||
| if (__poll_(__atomic_value)) | ||
| return true; | ||
| std::__atomic_wait_global_table(__contention_address, __monitor_val); | ||
| } | ||
| } else { | ||
| } // poll | ||
| return false; | ||
| } | ||
| }; | ||
|
|
||
| # else // _LIBCPP_AVAILABILITY_HAS_NEW_SYNC | ||
|
|
||
| template <class _AtomicWaitable, class _Poll> | ||
| struct __atomic_wait_backoff_impl { | ||
|
|
@@ -112,6 +226,8 @@ struct __atomic_wait_backoff_impl { | |
| } | ||
| }; | ||
|
|
||
| # endif // _LIBCPP_AVAILABILITY_HAS_NEW_SYNC | ||
|
|
||
| // The semantics of this function are similar to `atomic`'s | ||
| // `.wait(T old, std::memory_order order)`, but instead of having a hardcoded | ||
| // predicate (is the loaded value unequal to `old`?), the predicate function is | ||
|
|
@@ -133,6 +249,38 @@ _LIBCPP_HIDE_FROM_ABI void __atomic_wait_unless(const _AtomicWaitable& __a, memo | |
| /* backoff */ __backoff_fn); | ||
| } | ||
|
|
||
| # if _LIBCPP_AVAILABILITY_HAS_NEW_SYNC | ||
|
|
||
| template <class _AtomicWaitable> | ||
| _LIBCPP_HIDE_FROM_ABI void __atomic_notify_one(const _AtomicWaitable& __a) { | ||
| static_assert(__atomic_waitable<_AtomicWaitable>::value, ""); | ||
| using __value_type _LIBCPP_NODEBUG = typename __atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__value_type; | ||
| using __waitable_traits _LIBCPP_NODEBUG = __atomic_waitable_traits<__decay_t<_AtomicWaitable> >; | ||
| auto __contention_address = | ||
| const_cast<const void*>(static_cast<const volatile void*>(__waitable_traits::__atomic_contention_address(__a))); | ||
| if constexpr (__has_native_atomic_wait<__value_type>) { | ||
| std::__atomic_notify_one_native<sizeof(__value_type)>(__contention_address); | ||
| } else { | ||
| std::__atomic_notify_one_global_table(__contention_address); | ||
| } | ||
| } | ||
|
|
||
| template <class _AtomicWaitable> | ||
| _LIBCPP_HIDE_FROM_ABI void __atomic_notify_all(const _AtomicWaitable& __a) { | ||
| static_assert(__atomic_waitable<_AtomicWaitable>::value, ""); | ||
| using __value_type _LIBCPP_NODEBUG = typename __atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__value_type; | ||
| using __waitable_traits _LIBCPP_NODEBUG = __atomic_waitable_traits<__decay_t<_AtomicWaitable> >; | ||
| auto __contention_address = | ||
| const_cast<const void*>(static_cast<const volatile void*>(__waitable_traits::__atomic_contention_address(__a))); | ||
| if constexpr (__has_native_atomic_wait<__value_type>) { | ||
| std::__atomic_notify_all_native<sizeof(__value_type)>(__contention_address); | ||
| } else { | ||
| std::__atomic_notify_all_global_table(__contention_address); | ||
| } | ||
| } | ||
|
|
||
| # else // _LIBCPP_AVAILABILITY_HAS_NEW_SYNC | ||
huixie90 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| template <class _AtomicWaitable> | ||
| _LIBCPP_HIDE_FROM_ABI void __atomic_notify_one(const _AtomicWaitable& __a) { | ||
| static_assert(__atomic_waitable<_AtomicWaitable>::value, ""); | ||
|
|
@@ -145,6 +293,8 @@ _LIBCPP_HIDE_FROM_ABI void __atomic_notify_all(const _AtomicWaitable& __a) { | |
| std::__cxx_atomic_notify_all(__atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__atomic_contention_address(__a)); | ||
| } | ||
|
|
||
| # endif | ||
huixie90 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| # else // _LIBCPP_HAS_THREADS | ||
|
|
||
| template <class _AtomicWaitable, class _Poll> | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -27,6 +27,20 @@ Version 22.0 | |
| Symbol removed: _ZNSt3__118__time_get_storageIwE4initERKNS_5ctypeIwEE | ||
| Symbol removed: _ZNSt3__118__time_get_storageIwE9__analyzeEcRKNS_5ctypeIwEE | ||
|
|
||
| * [libc++] Allows any types of size 4 and 8 to use native platform ulock_wait | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Minor nitpick, let's swap the order. Usually higher entries are more recent. |
||
|
|
||
| This patch added symbols for platform wait functions with the size of the type | ||
|
|
||
| All platforms | ||
| ------------- | ||
| Symbol added: __ZNSt3__123__atomic_monitor_globalEPKv | ||
| Symbol added: __ZNSt3__126__atomic_wait_global_tableEPKvx | ||
| Symbol added: __ZNSt3__126__atomic_notify_one_nativeILm8EEEvPKv | ||
| Symbol added: __ZNSt3__132__atomic_notify_all_global_tableEPKv | ||
| Symbol added: __ZNSt3__120__atomic_wait_nativeILm8EEEvPKvS2_ | ||
| Symbol added: __ZNSt3__126__atomic_notify_all_nativeILm8EEEvPKv | ||
| Symbol added: __ZNSt3__132__atomic_notify_one_global_tableEPKv | ||
|
|
||
| ------------ | ||
| Version 21.0 | ||
| ------------ | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's also add a release note for this. Make sure to mention it's guarded behind an ABI macro.