Skip to content

Commit 63bb534

Browse files
committed
review feedback
1 parent 1e7a0ff commit 63bb534

File tree

3 files changed

+173
-87
lines changed

3 files changed

+173
-87
lines changed

libcxx/include/__atomic/atomic_sync.h

Lines changed: 117 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,12 @@
99
#ifndef _LIBCPP___ATOMIC_ATOMIC_SYNC_H
1010
#define _LIBCPP___ATOMIC_ATOMIC_SYNC_H
1111

12-
#include <__algorithm/ranges_find.h>
1312
#include <__atomic/contention_t.h>
1413
#include <__atomic/memory_order.h>
1514
#include <__atomic/to_gcc_order.h>
1615
#include <__chrono/duration.h>
1716
#include <__config>
1817
#include <__memory/addressof.h>
19-
#include <__ranges/access.h>
2018
#include <__thread/poll_with_backoff.h>
2119
#include <__type_traits/conjunction.h>
2220
#include <__type_traits/decay.h>
@@ -78,70 +76,77 @@ _LIBCPP_EXPORTED_FROM_ABI void
7876
__libcpp_atomic_wait(__cxx_atomic_contention_t const volatile*, __cxx_contention_t) _NOEXCEPT;
7977

8078
// new dylib interface
79+
80+
// return the global contention state's current value for the address
8181
_LIBCPP_AVAILABILITY_NEW_SYNC _LIBCPP_EXPORTED_FROM_ABI __cxx_contention_t
82-
__libcpp_atomic_monitor_global(void const volatile* __address) _NOEXCEPT;
82+
__atomic_monitor_global(void const volatile* __address) _NOEXCEPT;
8383

84+
// wait on the global contention state to be changed from the given value for the address
8485
_LIBCPP_AVAILABILITY_NEW_SYNC _LIBCPP_EXPORTED_FROM_ABI void
85-
__libcpp_atomic_wait_global_table(void const volatile* __address, __cxx_contention_t __monitor_value) _NOEXCEPT;
86+
__atomic_wait_global_table(void const volatile* __address, __cxx_contention_t __monitor_value) _NOEXCEPT;
8687

88+
// notify one waiter waiting on the global contention state for the address
8789
_LIBCPP_AVAILABILITY_NEW_SYNC _LIBCPP_EXPORTED_FROM_ABI void
88-
__libcpp_atomic_notify_one_global_table(void const volatile*) _NOEXCEPT;
90+
__atomic_notify_one_global_table(void const volatile*) _NOEXCEPT;
91+
92+
// notify all waiters waiting on the global contention state for the address
8993
_LIBCPP_AVAILABILITY_NEW_SYNC _LIBCPP_EXPORTED_FROM_ABI void
90-
__libcpp_atomic_notify_all_global_table(void const volatile*) _NOEXCEPT;
94+
__atomic_notify_all_global_table(void const volatile*) _NOEXCEPT;
9195

96+
// wait on the address directly with the native platform wait
9297
template <std::size_t _Size>
9398
_LIBCPP_AVAILABILITY_NEW_SYNC _LIBCPP_EXPORTED_FROM_ABI void
94-
__libcpp_atomic_wait_native(void const volatile* __address, void const* __old_value) _NOEXCEPT;
99+
__atomic_wait_native(void const volatile* __address, void const* __old_value) _NOEXCEPT;
100+
101+
// notify one waiter waiting on the address directly with the native platform wait
95102
template <std::size_t _Size>
96-
_LIBCPP_AVAILABILITY_NEW_SYNC _LIBCPP_EXPORTED_FROM_ABI void
97-
__libcpp_atomic_notify_one_native(const volatile void*) _NOEXCEPT;
103+
_LIBCPP_AVAILABILITY_NEW_SYNC _LIBCPP_EXPORTED_FROM_ABI void __atomic_notify_one_native(const volatile void*) _NOEXCEPT;
98104

105+
// notify all waiters waiting on the address directly with the native platform wait
99106
template <std::size_t _Size>
100-
_LIBCPP_AVAILABILITY_NEW_SYNC _LIBCPP_EXPORTED_FROM_ABI void
101-
__libcpp_atomic_notify_all_native(const volatile void*) _NOEXCEPT;
107+
_LIBCPP_AVAILABILITY_NEW_SYNC _LIBCPP_EXPORTED_FROM_ABI void __atomic_notify_all_native(const volatile void*) _NOEXCEPT;
108+
109+
# ifdef __linux__
110+
# define _LIBCPP_NATIVE_PLATFORM_WAIT_SIZES(_APPLY) _APPLY(4)
111+
# elif defined(__APPLE__)
112+
# define _LIBCPP_NATIVE_PLATFORM_WAIT_SIZES(_APPLY) \
113+
_APPLY(4) \
114+
_APPLY(8)
115+
# elif defined(__FreeBSD__) && __SIZEOF_LONG__ == 8
116+
# define _LIBCPP_NATIVE_PLATFORM_WAIT_SIZES(_APPLY) _APPLY(8)
117+
# else
118+
# define _LIBCPP_NATIVE_PLATFORM_WAIT_SIZES(_APPLY) _APPLY(sizeof(__cxx_contention_t))
119+
# endif // __linux__
102120

103121
// concepts defines the types are supported natively by the platform's wait
104122

105123
# if defined(_LIBCPP_ABI_ATOMIC_WAIT_NATIVE_BY_SIZE)
106124

107-
# ifdef __linux__
108-
109-
# define _LIBCPP_ATOMIC_WAIT_SIZES_LIST(_APPLY) _APPLY(4)
110-
111-
# elif defined(__APPLE__)
112-
113-
# define _LIBCPP_ATOMIC_WAIT_SIZES_LIST(_APPLY) \
114-
_APPLY(4) \
115-
_APPLY(8)
116-
117-
# elif defined(__FreeBSD__) && __SIZEOF_LONG__ == 8
118-
119-
# define _LIBCPP_ATOMIC_WAIT_SIZES_LIST(_APPLY) _APPLY(8)
120-
121-
# else
122-
123-
# define _LIBCPP_ATOMIC_WAIT_SIZES_LIST(_APPLY) _APPLY(sizeof(__cxx_contention_t))
124-
125-
# endif // __linux__
126-
127-
inline constexpr std::size_t __supported_native_wait_sizes[] = {
128-
# define _IDENTITY(_SIZE) _SIZE,
129-
_LIBCPP_ATOMIC_WAIT_SIZES_LIST(_IDENTITY)
130-
# undef _IDENTITY
131-
};
125+
_LIBCPP_HIDE_FROM_ABI constexpr bool __has_native_atomic_wait_impl(size_t __size) {
126+
switch (__size) {
127+
# define _LIBCPP_MAKE_CASE(n) \
128+
case n: \
129+
return true;
130+
_LIBCPP_NATIVE_PLATFORM_WAIT_SIZES(_LIBCPP_MAKE_CASE)
131+
default:
132+
return false;
133+
# undef _LIBCPP_MAKE_CASE
134+
};
135+
}
132136

133137
template <class _Tp>
134-
concept __atomic_wait_native_type =
135-
has_unique_object_representations_v<_Tp> &&
136-
std::ranges::find(__supported_native_wait_sizes, sizeof(_Tp)) != ranges::end(__supported_native_wait_sizes);
138+
concept __has_native_atomic_wait =
139+
has_unique_object_representations_v<_Tp> && __has_native_atomic_wait_impl(sizeof(_Tp));
137140

138141
# else // _LIBCPP_ABI_ATOMIC_WAIT_NATIVE_BY_SIZE
139142

140143
template <class _Tp>
141-
concept __atomic_wait_native_type = is_same_v<_Tp, __cxx_contention_t>;
144+
concept __has_native_atomic_wait = is_same_v<_Tp, __cxx_contention_t>;
142145

143146
# endif // _LIBCPP_ABI_ATOMIC_WAIT_NATIVE_BY_SIZE
144147

148+
# if _LIBCPP_AVAILABILITY_HAS_NEW_SYNC
149+
145150
template <class _AtomicWaitable, class _Poll>
146151
struct __atomic_wait_backoff_impl {
147152
const _AtomicWaitable& __a_;
@@ -155,24 +160,70 @@ struct __atomic_wait_backoff_impl {
155160
if (__elapsed > chrono::microseconds(4)) {
156161
auto __contention_address = __waitable_traits::__atomic_contention_address(__a_);
157162

158-
if constexpr (__atomic_wait_native_type<__value_type>) {
163+
if constexpr (__has_native_atomic_wait<__value_type>) {
159164
auto __atomic_value = __waitable_traits::__atomic_load(__a_, __order_);
160165
if (__poll_(__atomic_value))
161166
return true;
162-
std::__libcpp_atomic_wait_native<sizeof(__value_type)>(__contention_address, std::addressof(__atomic_value));
167+
std::__atomic_wait_native<sizeof(__value_type)>(__contention_address, std::addressof(__atomic_value));
163168
} else {
164-
__cxx_contention_t __monitor_val = std::__libcpp_atomic_monitor_global(__contention_address);
169+
__cxx_contention_t __monitor_val = std::__atomic_monitor_global(__contention_address);
165170
auto __atomic_value = __waitable_traits::__atomic_load(__a_, __order_);
166171
if (__poll_(__atomic_value))
167172
return true;
168-
std::__libcpp_atomic_wait_global_table(__contention_address, __monitor_val);
173+
std::__atomic_wait_global_table(__contention_address, __monitor_val);
169174
}
170175
} else {
171176
} // poll
172177
return false;
173178
}
174179
};
175180

181+
# else // _LIBCPP_AVAILABILITY_HAS_NEW_SYNC
182+
183+
template <class _AtomicWaitable, class _Poll>
184+
struct __atomic_wait_backoff_impl {
185+
const _AtomicWaitable& __a_;
186+
_Poll __poll_;
187+
memory_order __order_;
188+
189+
using __waitable_traits _LIBCPP_NODEBUG = __atomic_waitable_traits<__decay_t<_AtomicWaitable> >;
190+
191+
_LIBCPP_HIDE_FROM_ABI bool
192+
__update_monitor_val_and_poll(__cxx_atomic_contention_t const volatile*, __cxx_contention_t& __monitor_val) const {
193+
// In case the contention type happens to be __cxx_atomic_contention_t, i.e. __cxx_atomic_impl<int64_t>,
194+
// the platform wait is directly monitoring the atomic value itself.
195+
// `__poll_` takes the current value of the atomic as an in-out argument
196+
// to potentially modify it. After it returns, `__monitor` has a value
197+
// which can be safely waited on by `std::__libcpp_atomic_wait` without any
198+
// ABA style issues.
199+
__monitor_val = __waitable_traits::__atomic_load(__a_, __order_);
200+
return __poll_(__monitor_val);
201+
}
202+
203+
_LIBCPP_HIDE_FROM_ABI bool
204+
__update_monitor_val_and_poll(void const volatile* __contention_address, __cxx_contention_t& __monitor_val) const {
205+
// In case the contention type is anything else, platform wait is monitoring a __cxx_atomic_contention_t
206+
// from the global pool, the monitor comes from __libcpp_atomic_monitor
207+
__monitor_val = std::__libcpp_atomic_monitor(__contention_address);
208+
auto __current_val = __waitable_traits::__atomic_load(__a_, __order_);
209+
return __poll_(__current_val);
210+
}
211+
212+
_LIBCPP_HIDE_FROM_ABI bool operator()(chrono::nanoseconds __elapsed) const {
213+
if (__elapsed > chrono::microseconds(4)) {
214+
auto __contention_address = __waitable_traits::__atomic_contention_address(__a_);
215+
__cxx_contention_t __monitor_val;
216+
if (__update_monitor_val_and_poll(__contention_address, __monitor_val))
217+
return true;
218+
std::__libcpp_atomic_wait(__contention_address, __monitor_val);
219+
} else {
220+
} // poll
221+
return false;
222+
}
223+
};
224+
225+
# endif // _LIBCPP_AVAILABILITY_HAS_NEW_SYNC
226+
176227
// The semantics of this function are similar to `atomic`'s
177228
// `.wait(T old, std::memory_order order)`, but instead of having a hardcoded
178229
// predicate (is the loaded value unequal to `old`?), the predicate function is
@@ -194,15 +245,17 @@ _LIBCPP_HIDE_FROM_ABI void __atomic_wait_unless(const _AtomicWaitable& __a, memo
194245
/* backoff */ __backoff_fn);
195246
}
196247

248+
# if _LIBCPP_AVAILABILITY_HAS_NEW_SYNC
249+
197250
template <class _AtomicWaitable>
198251
_LIBCPP_HIDE_FROM_ABI void __atomic_notify_one(const _AtomicWaitable& __a) {
199252
static_assert(__atomic_waitable<_AtomicWaitable>::value, "");
200253
using __value_type _LIBCPP_NODEBUG = typename __atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__value_type;
201-
if constexpr (__atomic_wait_native_type<__value_type>) {
202-
std::__libcpp_atomic_notify_one_native<sizeof(__value_type)>(
254+
if constexpr (__has_native_atomic_wait<__value_type>) {
255+
std::__atomic_notify_one_native<sizeof(__value_type)>(
203256
__atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__atomic_contention_address(__a));
204257
} else {
205-
std::__libcpp_atomic_notify_one_global_table(
258+
std::__atomic_notify_one_global_table(
206259
__atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__atomic_contention_address(__a));
207260
}
208261
}
@@ -211,15 +264,29 @@ template <class _AtomicWaitable>
211264
_LIBCPP_HIDE_FROM_ABI void __atomic_notify_all(const _AtomicWaitable& __a) {
212265
static_assert(__atomic_waitable<_AtomicWaitable>::value, "");
213266
using __value_type _LIBCPP_NODEBUG = typename __atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__value_type;
214-
if constexpr (__atomic_wait_native_type<__value_type>) {
215-
std::__libcpp_atomic_notify_all_native<sizeof(__value_type)>(
267+
if constexpr (__has_native_atomic_wait<__value_type>) {
268+
std::__atomic_notify_all_native<sizeof(__value_type)>(
216269
__atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__atomic_contention_address(__a));
217270
} else {
218-
std::__libcpp_atomic_notify_all_global_table(
271+
std::__atomic_notify_all_global_table(
219272
__atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__atomic_contention_address(__a));
220273
}
221274
}
222275

276+
# else // _LIBCPP_AVAILABILITY_HAS_NEW_SYNC
277+
template <class _AtomicWaitable>
278+
_LIBCPP_HIDE_FROM_ABI void __atomic_notify_one(const _AtomicWaitable& __a) {
279+
static_assert(__atomic_waitable<_AtomicWaitable>::value, "");
280+
std::__cxx_atomic_notify_one(__atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__atomic_contention_address(__a));
281+
}
282+
283+
template <class _AtomicWaitable>
284+
_LIBCPP_HIDE_FROM_ABI void __atomic_notify_all(const _AtomicWaitable& __a) {
285+
static_assert(__atomic_waitable<_AtomicWaitable>::value, "");
286+
std::__cxx_atomic_notify_all(__atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__atomic_contention_address(__a));
287+
}
288+
# endif
289+
223290
# else // _LIBCPP_HAS_THREADS
224291

225292
template <class _AtomicWaitable, class _Poll>

libcxx/include/__atomic/contention_t.h

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,29 @@
1919

2020
_LIBCPP_BEGIN_NAMESPACE_STD
2121

22-
#if defined(__linux__) || (defined(_AIX) && !defined(__64BIT__))
22+
#if defined(_LIBCPP_ABI_ATOMIC_WAIT_NATIVE_BY_SIZE)
23+
24+
# ifdef __linux__
2325
using __cxx_contention_t _LIBCPP_NODEBUG = int32_t;
24-
#else
26+
# elif defined(__APPLE__)
27+
using __cxx_contention_t _LIBCPP_NODEBUG = int64_t;
28+
# elif defined(__FreeBSD__) && __SIZEOF_LONG__ == 8
2529
using __cxx_contention_t _LIBCPP_NODEBUG = int64_t;
26-
#endif // __linux__ || (_AIX && !__64BIT__)
30+
# elif defined(_AIX) && !defined(__64BIT__)
31+
using __cxx_contention_t _LIBCPP_NODEBUG = int32_t;
32+
# else
33+
using __cxx_contention_t _LIBCPP_NODEBUG = int64_t;
34+
# endif // __linux__
35+
36+
#else // _LIBCPP_ABI_ATOMIC_WAIT_NATIVE_BY_SIZE
37+
38+
# if defined(__linux__) || (defined(_AIX) && !defined(__64BIT__))
39+
using __cxx_contention_t _LIBCPP_NODEBUG = int32_t;
40+
# else
41+
using __cxx_contention_t _LIBCPP_NODEBUG = int64_t;
42+
# endif // __linux__ || (_AIX && !__64BIT__)
43+
44+
#endif // _LIBCPP_ABI_ATOMIC_WAIT_NATIVE_BY_SIZE
2745

2846
using __cxx_atomic_contention_t _LIBCPP_NODEBUG = __cxx_atomic_impl<__cxx_contention_t>;
2947

0 commit comments

Comments
 (0)