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
9297template <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
95102template <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
99106template <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
133137template <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
140143template <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+
145150template <class _AtomicWaitable , class _Poll >
146151struct __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+
197250template <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
225292template <class _AtomicWaitable , class _Poll >
0 commit comments