Skip to content

Commit 59d6fc2

Browse files
committed
[libc++] Allows any types of size 4 and 8 to use native platform ulock_wait
1 parent fcf020f commit 59d6fc2

File tree

6 files changed

+161
-88
lines changed

6 files changed

+161
-88
lines changed

libcxx/include/__atomic/atomic.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,8 @@ struct __atomic_base<_Tp, true> : public __atomic_base<_Tp, false> {
212212
// __atomic_base<int, false>. So specializing __atomic_base<_Tp> does not work
213213
template <class _Tp, bool _IsIntegral>
214214
struct __atomic_waitable_traits<__atomic_base<_Tp, _IsIntegral> > {
215+
using __inner_type _LIBCPP_NODEBUG = _Tp;
216+
215217
static _LIBCPP_HIDE_FROM_ABI _Tp __atomic_load(const __atomic_base<_Tp, _IsIntegral>& __a, memory_order __order) {
216218
return __a.load(__order);
217219
}

libcxx/include/__atomic/atomic_flag.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ struct atomic_flag {
8282

8383
template <>
8484
struct __atomic_waitable_traits<atomic_flag> {
85+
using __inner_type _LIBCPP_NODEBUG = _LIBCPP_ATOMIC_FLAG_TYPE;
86+
8587
static _LIBCPP_HIDE_FROM_ABI _LIBCPP_ATOMIC_FLAG_TYPE __atomic_load(const atomic_flag& __a, memory_order __order) {
8688
return std::__cxx_atomic_load(&__a.__a_, __order);
8789
}

libcxx/include/__atomic/atomic_ref.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,8 @@ struct __atomic_ref_base {
230230

231231
template <class _Tp>
232232
struct __atomic_waitable_traits<__atomic_ref_base<_Tp>> {
233+
using __inner_type _LIBCPP_NODEBUG = _Tp;
234+
233235
static _LIBCPP_HIDE_FROM_ABI _Tp __atomic_load(const __atomic_ref_base<_Tp>& __a, memory_order __order) {
234236
return __a.load(__order);
235237
}

libcxx/include/__atomic/atomic_sync.h

Lines changed: 43 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ _LIBCPP_BEGIN_NAMESPACE_STD
3838
// The below implementations look ugly to support C++03
3939
template <class _Tp, class = void>
4040
struct __atomic_waitable_traits {
41+
using __inner_type _LIBCPP_NODEBUG = void;
42+
4143
template <class _AtomicWaitable>
4244
static void __atomic_load(_AtomicWaitable&&, memory_order) = delete;
4345

@@ -58,21 +60,26 @@ struct __atomic_waitable< _Tp,
5860
#if _LIBCPP_STD_VER >= 20
5961
# if _LIBCPP_HAS_THREADS
6062

61-
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void __cxx_atomic_notify_one(void const volatile*) _NOEXCEPT;
62-
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void __cxx_atomic_notify_all(void const volatile*) _NOEXCEPT;
63-
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI __cxx_contention_t
64-
__libcpp_atomic_monitor(void const volatile*) _NOEXCEPT;
63+
template <std::size_t _Size>
6564
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void
66-
__libcpp_atomic_wait(void const volatile*, __cxx_contention_t) _NOEXCEPT;
65+
__libcpp_atomic_wait_native(void const volatile* __address, void const volatile* __old_value) _NOEXCEPT;
66+
67+
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI __cxx_contention_t
68+
__libcpp_atomic_monitor_global(void const volatile* __address) _NOEXCEPT;
6769

6870
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void
69-
__cxx_atomic_notify_one(__cxx_atomic_contention_t const volatile*) _NOEXCEPT;
71+
__libcpp_atomic_wait_global_table(void const volatile* __address, __cxx_contention_t __monitor_value) _NOEXCEPT;
72+
73+
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void __cxx_atomic_notify_one_global_table(void const volatile*) _NOEXCEPT;
74+
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void __cxx_atomic_notify_all_global_table(void const volatile*) _NOEXCEPT;
75+
76+
template <std::size_t _Size>
7077
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void
71-
__cxx_atomic_notify_all(__cxx_atomic_contention_t const volatile*) _NOEXCEPT;
72-
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI __cxx_contention_t
73-
__libcpp_atomic_monitor(__cxx_atomic_contention_t const volatile*) _NOEXCEPT;
78+
__cxx_atomic_notify_one_native(const volatile void*) _NOEXCEPT;
79+
80+
template <std::size_t _Size>
7481
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void
75-
__libcpp_atomic_wait(__cxx_atomic_contention_t const volatile*, __cxx_contention_t) _NOEXCEPT;
82+
__cxx_atomic_notify_all_native(const volatile void*) _NOEXCEPT;
7683

7784
template <class _AtomicWaitable, class _Poll>
7885
struct __atomic_wait_backoff_impl {
@@ -81,38 +88,25 @@ struct __atomic_wait_backoff_impl {
8188
memory_order __order_;
8289

8390
using __waitable_traits _LIBCPP_NODEBUG = __atomic_waitable_traits<__decay_t<_AtomicWaitable> >;
84-
85-
_LIBCPP_AVAILABILITY_SYNC
86-
_LIBCPP_HIDE_FROM_ABI bool
87-
__update_monitor_val_and_poll(__cxx_atomic_contention_t const volatile*, __cxx_contention_t& __monitor_val) const {
88-
// In case the contention type happens to be __cxx_atomic_contention_t, i.e. __cxx_atomic_impl<int64_t>,
89-
// the platform wait is directly monitoring the atomic value itself.
90-
// `__poll_` takes the current value of the atomic as an in-out argument
91-
// to potentially modify it. After it returns, `__monitor` has a value
92-
// which can be safely waited on by `std::__libcpp_atomic_wait` without any
93-
// ABA style issues.
94-
__monitor_val = __waitable_traits::__atomic_load(__a_, __order_);
95-
return __poll_(__monitor_val);
96-
}
97-
98-
_LIBCPP_AVAILABILITY_SYNC
99-
_LIBCPP_HIDE_FROM_ABI bool
100-
__update_monitor_val_and_poll(void const volatile* __contention_address, __cxx_contention_t& __monitor_val) const {
101-
// In case the contention type is anything else, platform wait is monitoring a __cxx_atomic_contention_t
102-
// from the global pool, the monitor comes from __libcpp_atomic_monitor
103-
__monitor_val = std::__libcpp_atomic_monitor(__contention_address);
104-
auto __current_val = __waitable_traits::__atomic_load(__a_, __order_);
105-
return __poll_(__current_val);
106-
}
91+
using __inner_type _LIBCPP_NODEBUG = typename __waitable_traits::__inner_type;
10792

10893
_LIBCPP_AVAILABILITY_SYNC
10994
_LIBCPP_HIDE_FROM_ABI bool operator()(chrono::nanoseconds __elapsed) const {
11095
if (__elapsed > chrono::microseconds(4)) {
11196
auto __contention_address = __waitable_traits::__atomic_contention_address(__a_);
112-
__cxx_contention_t __monitor_val;
113-
if (__update_monitor_val_and_poll(__contention_address, __monitor_val))
114-
return true;
115-
std::__libcpp_atomic_wait(__contention_address, __monitor_val);
97+
98+
if constexpr (__is_atomic_wait_native_type<__inner_type>::value) {
99+
auto __atomic_value = __waitable_traits::__atomic_load(__a_, __order_);
100+
if (__poll_(__atomic_value))
101+
return true;
102+
std::__libcpp_atomic_wait_native<sizeof(__inner_type)>(__contention_address, &__atomic_value);
103+
} else {
104+
__cxx_contention_t __monitor_val = std::__libcpp_atomic_monitor_global(__contention_address);
105+
auto __atomic_value = __waitable_traits::__atomic_load(__a_, __order_);
106+
if (__poll_(__atomic_value))
107+
return true;
108+
std::__libcpp_atomic_wait_global_table(__contention_address, __monitor_val);
109+
}
116110
} else {
117111
} // poll
118112
return false;
@@ -144,13 +138,23 @@ __atomic_wait_unless(const _AtomicWaitable& __a, memory_order __order, _Poll&& _
144138
template <class _AtomicWaitable>
145139
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void __atomic_notify_one(const _AtomicWaitable& __a) {
146140
static_assert(__atomic_waitable<_AtomicWaitable>::value, "");
147-
std::__cxx_atomic_notify_one(__atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__atomic_contention_address(__a));
141+
using __inner_type _LIBCPP_NODEBUG = typename __atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__inner_type;
142+
if constexpr (__is_atomic_wait_native_type<__inner_type>::value) {
143+
std::__cxx_atomic_notify_one_native<sizeof(__inner_type)>(__atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__atomic_contention_address(__a));
144+
} else {
145+
std::__cxx_atomic_notify_one_global_table(__atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__atomic_contention_address(__a));
146+
}
148147
}
149148

150149
template <class _AtomicWaitable>
151150
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void __atomic_notify_all(const _AtomicWaitable& __a) {
152151
static_assert(__atomic_waitable<_AtomicWaitable>::value, "");
153-
std::__cxx_atomic_notify_all(__atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__atomic_contention_address(__a));
152+
using __inner_type _LIBCPP_NODEBUG = typename __atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__inner_type;
153+
if constexpr (__is_atomic_wait_native_type<__inner_type>::value) {
154+
std::__cxx_atomic_notify_all_native<sizeof(__inner_type)>(__atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__atomic_contention_address(__a));
155+
} else {
156+
std::__cxx_atomic_notify_all_global_table(__atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__atomic_contention_address(__a));
157+
}
154158
}
155159

156160
# else // _LIBCPP_HAS_THREADS

libcxx/include/__atomic/contention_t.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111

1212
#include <__atomic/support.h>
1313
#include <__config>
14+
#include <__type_traits/enable_if.h>
15+
#include <__type_traits/integral_constant.h>
16+
#include <__type_traits/is_integral.h>
17+
#include <cstddef>
1418
#include <cstdint>
1519

1620
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -19,10 +23,23 @@
1923

2024
_LIBCPP_BEGIN_NAMESPACE_STD
2125

26+
template <class _Tp, class = void>
27+
struct __is_atomic_wait_native_type : false_type {};
28+
2229
#if defined(__linux__) || (defined(_AIX) && !defined(__64BIT__))
2330
using __cxx_contention_t _LIBCPP_NODEBUG = int32_t;
31+
32+
template <class _Tp>
33+
struct __is_atomic_wait_native_type<_Tp, __enable_if_t<is_integral<_Tp>::value && sizeof(_Tp) == 4> > : true_type {};
34+
2435
#else
2536
using __cxx_contention_t _LIBCPP_NODEBUG = int64_t;
37+
38+
template <class _Tp>
39+
struct __is_atomic_wait_native_type<_Tp,
40+
__enable_if_t<is_integral<_Tp>::value && (sizeof(_Tp) == 4 || sizeof(_Tp) == 8)> >
41+
: true_type {};
42+
2643
#endif // __linux__ || (_AIX && !__64BIT__)
2744

2845
using __cxx_atomic_contention_t _LIBCPP_NODEBUG = __cxx_atomic_impl<__cxx_contention_t>;

0 commit comments

Comments
 (0)