Skip to content

Commit 73a1383

Browse files
huixie90ldionne
andauthored
[libc++] Allows any types of size 4 and 8 to use native platform ulock_wait (#161086)
This is to address #146145 The issue before was that, for `std::atomic::wait/notify`, we only support `uint64_t` to go through the native `ulock_wait` directly. Any other types will go through the global contention table's `atomic`, increasing the chances of spurious wakeup. This PR tries to allow any types that are of size 4 or 8 to directly go to the `ulock_wait`. This PR is just proof of concept. If we like this idea, I can go further to update the Linux/FreeBSD branch and add ABI macros so the existing behaviours are reserved under the stable ABI Here are some benchmark results ``` Benchmark Time CPU Time Old Time New CPU Old CPU New ---------------------------------------------------------------------------------------------------------------------------------------------------- BM_stop_token_single_thread_reg_unreg_callback/1024 -0.1113 -0.1165 51519 45785 51397 45408 BM_stop_token_single_thread_reg_unreg_callback/4096 -0.2727 -0.1447 249685 181608 211865 181203 BM_stop_token_single_thread_reg_unreg_callback/65536 -0.1241 -0.1237 3308930 2898396 3300986 2892608 BM_stop_token_single_thread_reg_unreg_callback/262144 +0.0335 -0.1920 13237682 13681632 13208849 10673254 OVERALL_GEOMEAN -0.1254 -0.1447 0 0 0 0 ``` ``` Benchmark Time CPU Time Old Time New CPU Old CPU New ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- BM_1_atomic_1_waiter_1_notifier<KeepNotifying, NumHighPrioTasks<0>>/65536 -0.3344 -0.2424 5960741 3967212 5232250 3964085 BM_1_atomic_1_waiter_1_notifier<KeepNotifying, NumHighPrioTasks<0>>/131072 -0.1474 -0.1475 9144356 7796745 9137547 7790193 BM_1_atomic_1_waiter_1_notifier<KeepNotifying, NumHighPrioTasks<0>>/262144 -0.1336 -0.1340 18333441 15883805 18323711 15868500 OVERALL_GEOMEAN -0.2107 -0.1761 0 0 0 0 ``` ``` Benchmark Time CPU Time Old Time New CPU Old CPU New -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- BM_1_atomic_multi_waiter_1_notifier<KeepNotifying, NumWaitingThreads<2>, NumHighPrioTasks<0>>/16384 +0.2321 -0.0081 836618 1030772 833197 826476 BM_1_atomic_multi_waiter_1_notifier<KeepNotifying, NumWaitingThreads<2>, NumHighPrioTasks<0>>/32768 -0.3034 -0.1329 2182721 1520569 1747211 1515028 BM_1_atomic_multi_waiter_1_notifier<KeepNotifying, NumWaitingThreads<2>, NumHighPrioTasks<0>>/65536 -0.0924 -0.0924 3389098 3075897 3378486 3066448 BM_1_atomic_multi_waiter_1_notifier<KeepNotifying, NumWaitingThreads<8>, NumHighPrioTasks<0>>/4096 +0.0464 +0.0474 664233 695080 657736 688892 BM_1_atomic_multi_waiter_1_notifier<KeepNotifying, NumWaitingThreads<8>, NumHighPrioTasks<0>>/8192 -0.0279 -0.0267 1336041 1298794 1324270 1288953 BM_1_atomic_multi_waiter_1_notifier<KeepNotifying, NumWaitingThreads<8>, NumHighPrioTasks<0>>/16384 +0.0270 +0.0304 2543004 2611786 2517471 2593975 BM_1_atomic_multi_waiter_1_notifier<KeepNotifying, NumWaitingThreads<32>, NumHighPrioTasks<0>>/1024 +0.0423 +0.0941 473621 493657 325604 356245 BM_1_atomic_multi_waiter_1_notifier<KeepNotifying, NumWaitingThreads<32>, NumHighPrioTasks<0>>/2048 +0.0420 +0.0675 906266 944349 636253 679169 BM_1_atomic_multi_waiter_1_notifier<KeepNotifying, NumWaitingThreads<32>, NumHighPrioTasks<0>>/4096 +0.0359 +0.0378 1761584 1824783 1015092 1053439 OVERALL_GEOMEAN -0.0097 -0.0007 0 0 0 0 ``` ``` Benchmark Time CPU Time Old Time New CPU Old CPU New --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- BM_N_atomics_N_waiter_N_notifier<KeepNotifying, NumberOfAtomics<2>, NumHighPrioTasks<0>>/4096 -0.0990 -0.1001 371100 334370 369984 332955 BM_N_atomics_N_waiter_N_notifier<KeepNotifying, NumberOfAtomics<2>, NumHighPrioTasks<0>>/8192 -0.0305 -0.0314 698228 676908 696418 674585 BM_N_atomics_N_waiter_N_notifier<KeepNotifying, NumberOfAtomics<2>, NumHighPrioTasks<0>>/16384 -0.0258 -0.0268 1383530 1347894 1380665 1343680 BM_N_atomics_N_waiter_N_notifier<KeepNotifying, NumberOfAtomics<8>, NumHighPrioTasks<0>>/1024 +0.0465 +0.4702 937821 981388 472087 694082 BM_N_atomics_N_waiter_N_notifier<KeepNotifying, NumberOfAtomics<8>, NumHighPrioTasks<0>>/2048 +0.1596 +0.9140 1704819 1976899 616419 1179852 BM_N_atomics_N_waiter_N_notifier<KeepNotifying, NumberOfAtomics<8>, NumHighPrioTasks<0>>/4096 -0.1018 -0.2316 3793976 3407609 1912209 1469331 BM_N_atomics_N_waiter_N_notifier<KeepNotifying, NumberOfAtomics<32>, NumHighPrioTasks<0>>/256 +0.0395 +0.5818 30102662 31292982 174650 276270 BM_N_atomics_N_waiter_N_notifier<KeepNotifying, NumberOfAtomics<32>, NumHighPrioTasks<0>>/512 -0.0065 +1.2860 33079634 32863968 162150 370680 BM_N_atomics_N_waiter_N_notifier<KeepNotifying, NumberOfAtomics<32>, NumHighPrioTasks<0>>/1024 -0.0325 +0.4683 36581740 35392385 282320 414520 OVERALL_GEOMEAN -0.0084 +0.2878 0 0 0 0 ``` --------- Co-authored-by: Louis Dionne <[email protected]>
1 parent fb0400f commit 73a1383

21 files changed

+579
-104
lines changed

libcxx/docs/ABIGuarantees.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,16 @@ This flag fixes the implementation of CityHash used for ``hash<fundamental-type>
205205
CityHash has the problem that it drops some bits on the floor. Fixing the implementation changes the hash of values,
206206
resulting in an ABI break.
207207

208+
``_LIBCPP_ABI_ATOMIC_WAIT_NATIVE_BY_SIZE``
209+
------------------------------------------
210+
This flag changes the implementation of ``atomic::wait()`` and ``atomic::notify_one()/notify_all()`` to use the
211+
native atomic wait/notify operations on platforms that support them based on the size of the atomic type, instead
212+
of the type itself. This means for example that a type with ``sizeof(T) == 4`` on Linux that doesn't have padding
213+
bytes would be able to use the underlying platform's atomic wait primitive, which is otherwise only used for ``int32_t``.
214+
Since the whole program must use the same implementation for correctness, changing this is an ABI break since libc++
215+
supports linking against TUs that were compiled against older versions of the library.
216+
217+
208218
inline namespaces
209219
=================
210220
Inline namespaces which contain types that are observable by the user need to be kept the same, since they affect

libcxx/docs/ReleaseNotes/22.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ Improvements and New Features
8282
- The ``std::{generate, generate_n}`` and ``std::ranges::generate_n`` algorithms have been optimized for segmented
8383
iterators, resulting in a performance improvement for ``std::deque<short>`` and
8484
``std::join_view<vector<vector<short>>>`` iterators.
85+
- ``std::atomic::wait`` has been refactored to accept more types to use platform native wait functions directly.
86+
This is guarded behind the ABI Macro ``_LIBCPP_ABI_ATOMIC_WAIT_NATIVE_BY_SIZE``.
8587

8688
- The ``num_get::do_get`` integral overloads have been optimized, resulting in a performance improvement of up to 2.8x.
8789

libcxx/include/__atomic/atomic.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,8 @@ struct __atomic_base<_Tp, true> : public __atomic_base<_Tp, false> {
206206
// __atomic_base<int, false>. So specializing __atomic_base<_Tp> does not work
207207
template <class _Tp, bool _IsIntegral>
208208
struct __atomic_waitable_traits<__atomic_base<_Tp, _IsIntegral> > {
209+
using __value_type _LIBCPP_NODEBUG = _Tp;
210+
209211
static _LIBCPP_HIDE_FROM_ABI _Tp __atomic_load(const __atomic_base<_Tp, _IsIntegral>& __a, memory_order __order) {
210212
return __a.load(__order);
211213
}

libcxx/include/__atomic/atomic_flag.h

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

7777
template <>
7878
struct __atomic_waitable_traits<atomic_flag> {
79+
using __value_type _LIBCPP_NODEBUG = _LIBCPP_ATOMIC_FLAG_TYPE;
80+
7981
static _LIBCPP_HIDE_FROM_ABI _LIBCPP_ATOMIC_FLAG_TYPE __atomic_load(const atomic_flag& __a, memory_order __order) {
8082
return std::__cxx_atomic_load(&__a.__a_, __order);
8183
}

libcxx/include/__atomic/atomic_ref.h

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

234234
template <class _Tp>
235235
struct __atomic_waitable_traits<__atomic_ref_base<_Tp>> {
236+
using __value_type _LIBCPP_NODEBUG = _Tp;
237+
236238
static _LIBCPP_HIDE_FROM_ABI _Tp __atomic_load(const __atomic_ref_base<_Tp>& __a, memory_order __order) {
237239
return __a.load(__order);
238240
}

libcxx/include/__atomic/atomic_sync.h

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@
1818
#include <__thread/poll_with_backoff.h>
1919
#include <__type_traits/conjunction.h>
2020
#include <__type_traits/decay.h>
21+
#include <__type_traits/has_unique_object_representation.h>
2122
#include <__type_traits/invoke.h>
23+
#include <__type_traits/is_same.h>
24+
#include <__type_traits/is_trivially_copyable.h>
2225
#include <__type_traits/void_t.h>
2326
#include <__utility/declval.h>
2427
#include <cstring>
@@ -38,6 +41,8 @@ _LIBCPP_BEGIN_NAMESPACE_STD
3841
// The below implementations look ugly to support C++03
3942
template <class _Tp, class = void>
4043
struct __atomic_waitable_traits {
44+
using __value_type _LIBCPP_NODEBUG = void;
45+
4146
template <class _AtomicWaitable>
4247
static void __atomic_load(_AtomicWaitable&&, memory_order) = delete;
4348

@@ -58,6 +63,9 @@ struct __atomic_waitable< _Tp,
5863
#if _LIBCPP_STD_VER >= 20
5964
# if _LIBCPP_HAS_THREADS
6065

66+
# if !_LIBCPP_AVAILABILITY_HAS_NEW_SYNC
67+
68+
// old dylib interface kept for backwards compatibility
6169
_LIBCPP_EXPORTED_FROM_ABI void __cxx_atomic_notify_one(void const volatile*) _NOEXCEPT;
6270
_LIBCPP_EXPORTED_FROM_ABI void __cxx_atomic_notify_all(void const volatile*) _NOEXCEPT;
6371
_LIBCPP_EXPORTED_FROM_ABI __cxx_contention_t __libcpp_atomic_monitor(void const volatile*) _NOEXCEPT;
@@ -69,6 +77,114 @@ _LIBCPP_EXPORTED_FROM_ABI __cxx_contention_t
6977
__libcpp_atomic_monitor(__cxx_atomic_contention_t const volatile*) _NOEXCEPT;
7078
_LIBCPP_EXPORTED_FROM_ABI void
7179
__libcpp_atomic_wait(__cxx_atomic_contention_t const volatile*, __cxx_contention_t) _NOEXCEPT;
80+
# endif // !_LIBCPP_AVAILABILITY_HAS_NEW_SYNC
81+
82+
// new dylib interface
83+
84+
// return the global contention state's current value for the address
85+
_LIBCPP_AVAILABILITY_NEW_SYNC _LIBCPP_EXPORTED_FROM_ABI __cxx_contention_t
86+
__atomic_monitor_global(void const* __address) _NOEXCEPT;
87+
88+
// wait on the global contention state to be changed from the given value for the address
89+
_LIBCPP_AVAILABILITY_NEW_SYNC _LIBCPP_EXPORTED_FROM_ABI void
90+
__atomic_wait_global_table(void const* __address, __cxx_contention_t __monitor_value) _NOEXCEPT;
91+
92+
// notify one waiter waiting on the global contention state for the address
93+
_LIBCPP_AVAILABILITY_NEW_SYNC _LIBCPP_EXPORTED_FROM_ABI void __atomic_notify_one_global_table(void const*) _NOEXCEPT;
94+
95+
// notify all waiters waiting on the global contention state for the address
96+
_LIBCPP_AVAILABILITY_NEW_SYNC _LIBCPP_EXPORTED_FROM_ABI void __atomic_notify_all_global_table(void const*) _NOEXCEPT;
97+
98+
// wait on the address directly with the native platform wait
99+
template <std::size_t _Size>
100+
_LIBCPP_AVAILABILITY_NEW_SYNC _LIBCPP_EXPORTED_FROM_ABI void
101+
__atomic_wait_native(void const* __address, void const* __old_value) _NOEXCEPT;
102+
103+
// notify one waiter waiting on the address directly with the native platform wait
104+
template <std::size_t _Size>
105+
_LIBCPP_AVAILABILITY_NEW_SYNC _LIBCPP_EXPORTED_FROM_ABI void __atomic_notify_one_native(const void*) _NOEXCEPT;
106+
107+
// notify all waiters waiting on the address directly with the native platform wait
108+
template <std::size_t _Size>
109+
_LIBCPP_AVAILABILITY_NEW_SYNC _LIBCPP_EXPORTED_FROM_ABI void __atomic_notify_all_native(const void*) _NOEXCEPT;
110+
111+
# ifdef __linux__
112+
# define _LIBCPP_NATIVE_PLATFORM_WAIT_SIZES(_APPLY) _APPLY(4)
113+
# elif defined(__APPLE__)
114+
# define _LIBCPP_NATIVE_PLATFORM_WAIT_SIZES(_APPLY) \
115+
_APPLY(4) \
116+
_APPLY(8)
117+
# elif defined(__FreeBSD__) && __SIZEOF_LONG__ == 8
118+
# define _LIBCPP_NATIVE_PLATFORM_WAIT_SIZES(_APPLY) _APPLY(8)
119+
# elif defined(_WIN32)
120+
# define _LIBCPP_NATIVE_PLATFORM_WAIT_SIZES(_APPLY) _APPLY(8)
121+
# else
122+
# define _LIBCPP_NATIVE_PLATFORM_WAIT_SIZES(_APPLY) _APPLY(sizeof(__cxx_contention_t))
123+
# endif // __linux__
124+
125+
// concepts defines the types are supported natively by the platform's wait
126+
127+
# if defined(_LIBCPP_ABI_ATOMIC_WAIT_NATIVE_BY_SIZE)
128+
129+
_LIBCPP_HIDE_FROM_ABI constexpr bool __has_native_atomic_wait_impl(size_t __size) {
130+
switch (__size) {
131+
# define _LIBCPP_MAKE_CASE(n) \
132+
case n: \
133+
return true;
134+
_LIBCPP_NATIVE_PLATFORM_WAIT_SIZES(_LIBCPP_MAKE_CASE)
135+
default:
136+
return false;
137+
# undef _LIBCPP_MAKE_CASE
138+
};
139+
}
140+
141+
template <class _Tp>
142+
concept __has_native_atomic_wait =
143+
has_unique_object_representations_v<_Tp> && is_trivially_copyable_v<_Tp> &&
144+
__has_native_atomic_wait_impl(sizeof(_Tp));
145+
146+
# else // _LIBCPP_ABI_ATOMIC_WAIT_NATIVE_BY_SIZE
147+
148+
template <class _Tp>
149+
concept __has_native_atomic_wait = is_same_v<_Tp, __cxx_contention_t>;
150+
151+
# endif // _LIBCPP_ABI_ATOMIC_WAIT_NATIVE_BY_SIZE
152+
153+
# if _LIBCPP_AVAILABILITY_HAS_NEW_SYNC
154+
155+
template <class _AtomicWaitable, class _Poll>
156+
struct __atomic_wait_backoff_impl {
157+
const _AtomicWaitable& __a_;
158+
_Poll __poll_;
159+
memory_order __order_;
160+
161+
using __waitable_traits _LIBCPP_NODEBUG = __atomic_waitable_traits<__decay_t<_AtomicWaitable> >;
162+
using __value_type _LIBCPP_NODEBUG = typename __waitable_traits::__value_type;
163+
164+
_LIBCPP_HIDE_FROM_ABI bool operator()(chrono::nanoseconds __elapsed) const {
165+
if (__elapsed > chrono::microseconds(4)) {
166+
auto __contention_address = const_cast<const void*>(
167+
static_cast<const volatile void*>(__waitable_traits::__atomic_contention_address(__a_)));
168+
169+
if constexpr (__has_native_atomic_wait<__value_type>) {
170+
auto __atomic_value = __waitable_traits::__atomic_load(__a_, __order_);
171+
if (__poll_(__atomic_value))
172+
return true;
173+
std::__atomic_wait_native<sizeof(__value_type)>(__contention_address, std::addressof(__atomic_value));
174+
} else {
175+
__cxx_contention_t __monitor_val = std::__atomic_monitor_global(__contention_address);
176+
auto __atomic_value = __waitable_traits::__atomic_load(__a_, __order_);
177+
if (__poll_(__atomic_value))
178+
return true;
179+
std::__atomic_wait_global_table(__contention_address, __monitor_val);
180+
}
181+
} else {
182+
} // poll
183+
return false;
184+
}
185+
};
186+
187+
# else // _LIBCPP_AVAILABILITY_HAS_NEW_SYNC
72188

73189
template <class _AtomicWaitable, class _Poll>
74190
struct __atomic_wait_backoff_impl {
@@ -112,6 +228,8 @@ struct __atomic_wait_backoff_impl {
112228
}
113229
};
114230

231+
# endif // _LIBCPP_AVAILABILITY_HAS_NEW_SYNC
232+
115233
// The semantics of this function are similar to `atomic`'s
116234
// `.wait(T old, std::memory_order order)`, but instead of having a hardcoded
117235
// predicate (is the loaded value unequal to `old`?), the predicate function is
@@ -133,6 +251,38 @@ _LIBCPP_HIDE_FROM_ABI void __atomic_wait_unless(const _AtomicWaitable& __a, memo
133251
/* backoff */ __backoff_fn);
134252
}
135253

254+
# if _LIBCPP_AVAILABILITY_HAS_NEW_SYNC
255+
256+
template <class _AtomicWaitable>
257+
_LIBCPP_HIDE_FROM_ABI void __atomic_notify_one(const _AtomicWaitable& __a) {
258+
static_assert(__atomic_waitable<_AtomicWaitable>::value, "");
259+
using __value_type _LIBCPP_NODEBUG = typename __atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__value_type;
260+
using __waitable_traits _LIBCPP_NODEBUG = __atomic_waitable_traits<__decay_t<_AtomicWaitable> >;
261+
auto __contention_address =
262+
const_cast<const void*>(static_cast<const volatile void*>(__waitable_traits::__atomic_contention_address(__a)));
263+
if constexpr (__has_native_atomic_wait<__value_type>) {
264+
std::__atomic_notify_one_native<sizeof(__value_type)>(__contention_address);
265+
} else {
266+
std::__atomic_notify_one_global_table(__contention_address);
267+
}
268+
}
269+
270+
template <class _AtomicWaitable>
271+
_LIBCPP_HIDE_FROM_ABI void __atomic_notify_all(const _AtomicWaitable& __a) {
272+
static_assert(__atomic_waitable<_AtomicWaitable>::value, "");
273+
using __value_type _LIBCPP_NODEBUG = typename __atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__value_type;
274+
using __waitable_traits _LIBCPP_NODEBUG = __atomic_waitable_traits<__decay_t<_AtomicWaitable> >;
275+
auto __contention_address =
276+
const_cast<const void*>(static_cast<const volatile void*>(__waitable_traits::__atomic_contention_address(__a)));
277+
if constexpr (__has_native_atomic_wait<__value_type>) {
278+
std::__atomic_notify_all_native<sizeof(__value_type)>(__contention_address);
279+
} else {
280+
std::__atomic_notify_all_global_table(__contention_address);
281+
}
282+
}
283+
284+
# else // _LIBCPP_AVAILABILITY_HAS_NEW_SYNC
285+
136286
template <class _AtomicWaitable>
137287
_LIBCPP_HIDE_FROM_ABI void __atomic_notify_one(const _AtomicWaitable& __a) {
138288
static_assert(__atomic_waitable<_AtomicWaitable>::value, "");
@@ -145,6 +295,8 @@ _LIBCPP_HIDE_FROM_ABI void __atomic_notify_all(const _AtomicWaitable& __a) {
145295
std::__cxx_atomic_notify_all(__atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__atomic_contention_address(__a));
146296
}
147297

298+
# endif
299+
148300
# else // _LIBCPP_HAS_THREADS
149301

150302
template <class _AtomicWaitable, class _Poll>

libcxx/include/__atomic/contention_t.h

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

2020
_LIBCPP_BEGIN_NAMESPACE_STD
2121

22-
#if defined(__linux__) || (defined(_AIX) && !defined(__64BIT__))
22+
// The original definition of `__cxx_contention_t` seemed a bit arbitrary.
23+
// When we enable the _LIBCPP_ABI_ATOMIC_WAIT_NATIVE_BY_SIZE ABI,
24+
// use definitions that are based on what the underlying platform supports
25+
// instead.
26+
#if defined(_LIBCPP_ABI_ATOMIC_WAIT_NATIVE_BY_SIZE)
27+
28+
# ifdef __linux__
29+
using __cxx_contention_t _LIBCPP_NODEBUG = int32_t;
30+
# elif defined(__APPLE__)
31+
using __cxx_contention_t _LIBCPP_NODEBUG = int64_t;
32+
# elif defined(__FreeBSD__) && __SIZEOF_LONG__ == 8
33+
using __cxx_contention_t _LIBCPP_NODEBUG = int64_t;
34+
# elif defined(_AIX) && !defined(__64BIT__)
35+
using __cxx_contention_t _LIBCPP_NODEBUG = int32_t;
36+
# elif defined(_WIN32)
37+
using __cxx_contention_t _LIBCPP_NODEBUG = int64_t;
38+
# else
39+
using __cxx_contention_t _LIBCPP_NODEBUG = int64_t;
40+
# endif // __linux__
41+
42+
#else // _LIBCPP_ABI_ATOMIC_WAIT_NATIVE_BY_SIZE
43+
44+
# if defined(__linux__) || (defined(_AIX) && !defined(__64BIT__))
2345
using __cxx_contention_t _LIBCPP_NODEBUG = int32_t;
24-
#else
46+
# else
2547
using __cxx_contention_t _LIBCPP_NODEBUG = int64_t;
26-
#endif // __linux__ || (_AIX && !__64BIT__)
48+
# endif // __linux__ || (_AIX && !__64BIT__)
49+
50+
#endif // _LIBCPP_ABI_ATOMIC_WAIT_NATIVE_BY_SIZE
2751

2852
using __cxx_atomic_contention_t _LIBCPP_NODEBUG = __cxx_atomic_impl<__cxx_contention_t>;
2953

libcxx/include/__configuration/abi.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363

6464
// These flags are documented in ABIGuarantees.rst
6565
# define _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT
66+
# define _LIBCPP_ABI_ATOMIC_WAIT_NATIVE_BY_SIZE
6667
# define _LIBCPP_ABI_DO_NOT_EXPORT_BASIC_STRING_COMMON
6768
# define _LIBCPP_ABI_DO_NOT_EXPORT_VECTOR_BASE_COMMON
6869
# define _LIBCPP_ABI_DO_NOT_EXPORT_TO_CHARS_BASE_10

libcxx/include/__configuration/availability.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@
3939
// in all versions of the library are available.
4040
#if !_LIBCPP_HAS_VENDOR_AVAILABILITY_ANNOTATIONS
4141

42+
# define _LIBCPP_INTRODUCED_IN_LLVM_22 1
43+
# define _LIBCPP_INTRODUCED_IN_LLVM_22_ATTRIBUTE /* nothing */
44+
4245
# define _LIBCPP_INTRODUCED_IN_LLVM_21 1
4346
# define _LIBCPP_INTRODUCED_IN_LLVM_21_ATTRIBUTE /* nothing */
4447

@@ -67,6 +70,11 @@
6770

6871
// clang-format off
6972

73+
// LLVM 22
74+
// TODO: Fill this in
75+
# define _LIBCPP_INTRODUCED_IN_LLVM_22 0
76+
# define _LIBCPP_INTRODUCED_IN_LLVM_22_ATTRIBUTE __attribute__((unavailable))
77+
7078
// LLVM 21
7179
// TODO: Fill this in
7280
# define _LIBCPP_INTRODUCED_IN_LLVM_21 0
@@ -197,6 +205,13 @@
197205

198206
#endif
199207

208+
// This controls the availability of new implementation of std::atomic's
209+
// wait, notify_one and notify_all. The new implementation uses
210+
// the native atomic wait/notify operations on platforms that support them
211+
// based on the size of the atomic type, instead of the type itself.
212+
#define _LIBCPP_AVAILABILITY_HAS_NEW_SYNC _LIBCPP_INTRODUCED_IN_LLVM_22
213+
#define _LIBCPP_AVAILABILITY_NEW_SYNC _LIBCPP_INTRODUCED_IN_LLVM_22_ATTRIBUTE
214+
200215
// Enable additional explicit instantiations of iostreams components. This
201216
// reduces the number of weak definitions generated in programs that use
202217
// iostreams by providing a single strong definition in the shared library.

libcxx/lib/abi/CHANGELOG.TXT

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,20 @@ New entries should be added directly below the "Version" header.
1616
Version 22.0
1717
------------
1818

19+
* [libc++] Allows any types of size 4 and 8 to use native platform ulock_wait
20+
21+
This patch added symbols for platform wait functions with the size of the type
22+
23+
All platforms
24+
-------------
25+
Symbol added: __ZNSt3__123__atomic_monitor_globalEPKv
26+
Symbol added: __ZNSt3__126__atomic_wait_global_tableEPKvx
27+
Symbol added: __ZNSt3__126__atomic_notify_one_nativeILm8EEEvPKv
28+
Symbol added: __ZNSt3__132__atomic_notify_all_global_tableEPKv
29+
Symbol added: __ZNSt3__120__atomic_wait_nativeILm8EEEvPKvS2_
30+
Symbol added: __ZNSt3__126__atomic_notify_all_nativeILm8EEEvPKv
31+
Symbol added: __ZNSt3__132__atomic_notify_one_global_tableEPKv
32+
1933
* [libc++] Remove __time_get_storage::{__analyze,init} from the ABI
2034

2135
These functions have never been used outside the dylib, so there is no point in exporting them.

0 commit comments

Comments
 (0)