Skip to content

Commit bd39eb9

Browse files
committed
add abi macro and availablity macro
1 parent 4a1442d commit bd39eb9

File tree

9 files changed

+202
-110
lines changed

9 files changed

+202
-110
lines changed

libcxx/docs/ABIGuarantees.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,14 @@ 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 changes the behaviour of ``atomic::wait()`` and ``atomic::notify_one()/notify_all()`` in
213+
some cases, resulting in an ABI break.
214+
215+
208216
inline namespaces
209217
=================
210218
Inline namespaces which contain types that are observable by the user need to be kept the same, since they affect

libcxx/include/__atomic/atomic.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ 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 __inner_type _LIBCPP_NODEBUG = _Tp;
209+
using __value_type _LIBCPP_NODEBUG = _Tp;
210210

211211
static _LIBCPP_HIDE_FROM_ABI _Tp __atomic_load(const __atomic_base<_Tp, _IsIntegral>& __a, memory_order __order) {
212212
return __a.load(__order);

libcxx/include/__atomic/atomic_flag.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ struct atomic_flag {
7676

7777
template <>
7878
struct __atomic_waitable_traits<atomic_flag> {
79-
using __inner_type _LIBCPP_NODEBUG = _LIBCPP_ATOMIC_FLAG_TYPE;
79+
using __value_type _LIBCPP_NODEBUG = _LIBCPP_ATOMIC_FLAG_TYPE;
8080

8181
static _LIBCPP_HIDE_FROM_ABI _LIBCPP_ATOMIC_FLAG_TYPE __atomic_load(const atomic_flag& __a, memory_order __order) {
8282
return std::__cxx_atomic_load(&__a.__a_, __order);

libcxx/include/__atomic/atomic_ref.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ struct __atomic_ref_base {
233233

234234
template <class _Tp>
235235
struct __atomic_waitable_traits<__atomic_ref_base<_Tp>> {
236-
using __inner_type _LIBCPP_NODEBUG = _Tp;
236+
using __value_type _LIBCPP_NODEBUG = _Tp;
237237

238238
static _LIBCPP_HIDE_FROM_ABI _Tp __atomic_load(const __atomic_ref_base<_Tp>& __a, memory_order __order) {
239239
return __a.load(__order);

libcxx/include/__atomic/atomic_sync.h

Lines changed: 32 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ _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;
41+
using __value_type _LIBCPP_NODEBUG = void;
4242

4343
template <class _AtomicWaitable>
4444
static void __atomic_load(_AtomicWaitable&&, memory_order) = delete;
@@ -60,7 +60,7 @@ struct __atomic_waitable< _Tp,
6060
#if _LIBCPP_STD_VER >= 20
6161
# if _LIBCPP_HAS_THREADS
6262

63-
<<<<<<< HEAD
63+
// old dylib interface
6464
_LIBCPP_EXPORTED_FROM_ABI void __cxx_atomic_notify_one(void const volatile*) _NOEXCEPT;
6565
_LIBCPP_EXPORTED_FROM_ABI void __cxx_atomic_notify_all(void const volatile*) _NOEXCEPT;
6666
_LIBCPP_EXPORTED_FROM_ABI __cxx_contention_t __libcpp_atomic_monitor(void const volatile*) _NOEXCEPT;
@@ -72,28 +72,30 @@ _LIBCPP_EXPORTED_FROM_ABI __cxx_contention_t
7272
__libcpp_atomic_monitor(__cxx_atomic_contention_t const volatile*) _NOEXCEPT;
7373
_LIBCPP_EXPORTED_FROM_ABI void
7474
__libcpp_atomic_wait(__cxx_atomic_contention_t const volatile*, __cxx_contention_t) _NOEXCEPT;
75-
=======
76-
template <std::size_t _Size>
77-
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void
78-
__libcpp_atomic_wait_native(void const volatile* __address, void const volatile* __old_value) _NOEXCEPT;
7975

80-
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI __cxx_contention_t
76+
// new dylib interface
77+
_LIBCPP_AVAILABILITY_NEW_SYNC _LIBCPP_EXPORTED_FROM_ABI __cxx_contention_t
8178
__libcpp_atomic_monitor_global(void const volatile* __address) _NOEXCEPT;
8279

83-
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void
80+
_LIBCPP_AVAILABILITY_NEW_SYNC _LIBCPP_EXPORTED_FROM_ABI void
8481
__libcpp_atomic_wait_global_table(void const volatile* __address, __cxx_contention_t __monitor_value) _NOEXCEPT;
8582

86-
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void __cxx_atomic_notify_one_global_table(void const volatile*) _NOEXCEPT;
87-
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void __cxx_atomic_notify_all_global_table(void const volatile*) _NOEXCEPT;
83+
_LIBCPP_AVAILABILITY_NEW_SYNC _LIBCPP_EXPORTED_FROM_ABI void
84+
__libcpp_atomic_notify_one_global_table(void const volatile*) _NOEXCEPT;
85+
_LIBCPP_AVAILABILITY_NEW_SYNC _LIBCPP_EXPORTED_FROM_ABI void
86+
__libcpp_atomic_notify_all_global_table(void const volatile*) _NOEXCEPT;
87+
88+
template <std::size_t _Size>
89+
_LIBCPP_AVAILABILITY_NEW_SYNC _LIBCPP_EXPORTED_FROM_ABI void
8890

91+
__libcpp_atomic_wait_native(void const volatile* __address, void const volatile* __old_value) _NOEXCEPT;
8992
template <std::size_t _Size>
90-
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void
91-
__cxx_atomic_notify_one_native(const volatile void*) _NOEXCEPT;
93+
_LIBCPP_AVAILABILITY_NEW_SYNC _LIBCPP_EXPORTED_FROM_ABI void
94+
__libcpp_atomic_notify_one_native(const volatile void*) _NOEXCEPT;
9295

9396
template <std::size_t _Size>
94-
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void
95-
__cxx_atomic_notify_all_native(const volatile void*) _NOEXCEPT;
96-
>>>>>>> 59d6fc2ba487 ([libc++] Allows any types of size 4 and 8 to use native platform ulock_wait)
97+
_LIBCPP_AVAILABILITY_NEW_SYNC _LIBCPP_EXPORTED_FROM_ABI void
98+
__libcpp_atomic_notify_all_native(const volatile void*) _NOEXCEPT;
9799

98100
template <class _AtomicWaitable, class _Poll>
99101
struct __atomic_wait_backoff_impl {
@@ -102,41 +104,17 @@ struct __atomic_wait_backoff_impl {
102104
memory_order __order_;
103105

104106
using __waitable_traits _LIBCPP_NODEBUG = __atomic_waitable_traits<__decay_t<_AtomicWaitable> >;
105-
<<<<<<< HEAD
106-
107-
_LIBCPP_HIDE_FROM_ABI bool
108-
__update_monitor_val_and_poll(__cxx_atomic_contention_t const volatile*, __cxx_contention_t& __monitor_val) const {
109-
// In case the contention type happens to be __cxx_atomic_contention_t, i.e. __cxx_atomic_impl<int64_t>,
110-
// the platform wait is directly monitoring the atomic value itself.
111-
// `__poll_` takes the current value of the atomic as an in-out argument
112-
// to potentially modify it. After it returns, `__monitor` has a value
113-
// which can be safely waited on by `std::__libcpp_atomic_wait` without any
114-
// ABA style issues.
115-
__monitor_val = __waitable_traits::__atomic_load(__a_, __order_);
116-
return __poll_(__monitor_val);
117-
}
118-
119-
_LIBCPP_HIDE_FROM_ABI bool
120-
__update_monitor_val_and_poll(void const volatile* __contention_address, __cxx_contention_t& __monitor_val) const {
121-
// In case the contention type is anything else, platform wait is monitoring a __cxx_atomic_contention_t
122-
// from the global pool, the monitor comes from __libcpp_atomic_monitor
123-
__monitor_val = std::__libcpp_atomic_monitor(__contention_address);
124-
auto __current_val = __waitable_traits::__atomic_load(__a_, __order_);
125-
return __poll_(__current_val);
126-
}
127-
=======
128-
using __inner_type _LIBCPP_NODEBUG = typename __waitable_traits::__inner_type;
129-
>>>>>>> 59d6fc2ba487 ([libc++] Allows any types of size 4 and 8 to use native platform ulock_wait)
107+
using __value_type _LIBCPP_NODEBUG = typename __waitable_traits::__value_type;
130108

131109
_LIBCPP_HIDE_FROM_ABI bool operator()(chrono::nanoseconds __elapsed) const {
132110
if (__elapsed > chrono::microseconds(4)) {
133111
auto __contention_address = __waitable_traits::__atomic_contention_address(__a_);
134112

135-
if constexpr (__is_atomic_wait_native_type<__inner_type>::value) {
113+
if constexpr (__is_atomic_wait_native_type<__value_type>::value) {
136114
auto __atomic_value = __waitable_traits::__atomic_load(__a_, __order_);
137115
if (__poll_(__atomic_value))
138116
return true;
139-
std::__libcpp_atomic_wait_native<sizeof(__inner_type)>(__contention_address, &__atomic_value);
117+
std::__libcpp_atomic_wait_native<sizeof(__value_type)>(__contention_address, &__atomic_value);
140118
} else {
141119
__cxx_contention_t __monitor_val = std::__libcpp_atomic_monitor_global(__contention_address);
142120
auto __atomic_value = __waitable_traits::__atomic_load(__a_, __order_);
@@ -174,22 +152,26 @@ _LIBCPP_HIDE_FROM_ABI void __atomic_wait_unless(const _AtomicWaitable& __a, memo
174152
template <class _AtomicWaitable>
175153
_LIBCPP_HIDE_FROM_ABI void __atomic_notify_one(const _AtomicWaitable& __a) {
176154
static_assert(__atomic_waitable<_AtomicWaitable>::value, "");
177-
using __inner_type _LIBCPP_NODEBUG = typename __atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__inner_type;
178-
if constexpr (__is_atomic_wait_native_type<__inner_type>::value) {
179-
std::__cxx_atomic_notify_one_native<sizeof(__inner_type)>(__atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__atomic_contention_address(__a));
155+
using __value_type _LIBCPP_NODEBUG = typename __atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__value_type;
156+
if constexpr (__is_atomic_wait_native_type<__value_type>::value) {
157+
std::__libcpp_atomic_notify_one_native<sizeof(__value_type)>(
158+
__atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__atomic_contention_address(__a));
180159
} else {
181-
std::__cxx_atomic_notify_one_global_table(__atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__atomic_contention_address(__a));
160+
std::__libcpp_atomic_notify_one_global_table(
161+
__atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__atomic_contention_address(__a));
182162
}
183163
}
184164

185165
template <class _AtomicWaitable>
186166
_LIBCPP_HIDE_FROM_ABI void __atomic_notify_all(const _AtomicWaitable& __a) {
187167
static_assert(__atomic_waitable<_AtomicWaitable>::value, "");
188-
using __inner_type _LIBCPP_NODEBUG = typename __atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__inner_type;
189-
if constexpr (__is_atomic_wait_native_type<__inner_type>::value) {
190-
std::__cxx_atomic_notify_all_native<sizeof(__inner_type)>(__atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__atomic_contention_address(__a));
168+
using __value_type _LIBCPP_NODEBUG = typename __atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__value_type;
169+
if constexpr (__is_atomic_wait_native_type<__value_type>::value) {
170+
std::__libcpp_atomic_notify_all_native<sizeof(__value_type)>(
171+
__atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__atomic_contention_address(__a));
191172
} else {
192-
std::__cxx_atomic_notify_all_global_table(__atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__atomic_contention_address(__a));
173+
std::__libcpp_atomic_notify_all_global_table(
174+
__atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__atomic_contention_address(__a));
193175
}
194176
}
195177

libcxx/include/__atomic/contention_t.h

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@
1212
#include <__atomic/support.h>
1313
#include <__config>
1414
#include <__type_traits/enable_if.h>
15+
#include <__type_traits/has_unique_object_representation.h>
1516
#include <__type_traits/integral_constant.h>
16-
#include <__type_traits/is_standard_layout.h>
17+
#include <__type_traits/is_same.h>
1718
#include <cstddef>
1819
#include <cstdint>
1920

@@ -29,16 +30,31 @@ struct __is_atomic_wait_native_type : false_type {};
2930
#if defined(__linux__) || (defined(_AIX) && !defined(__64BIT__))
3031
using __cxx_contention_t _LIBCPP_NODEBUG = int32_t;
3132

33+
# if defined(_LIBCPP_ABI_ATOMIC_WAIT_NATIVE_BY_SIZE)
3234
template <class _Tp>
33-
struct __is_atomic_wait_native_type<_Tp, __enable_if_t<is_standard_layout<_Tp>::value && sizeof(_Tp) == 4> > : true_type {};
35+
struct __is_atomic_wait_native_type<_Tp,
36+
__enable_if_t<has_unique_object_representations<_Tp>::value && sizeof(_Tp) == 4> >
37+
: true_type {};
38+
# else
39+
template <class _Tp>
40+
struct __is_atomic_wait_native_type<_Tp, __enable_if_t<is_same<_Tp, int32_t>::value && sizeof(_Tp) == 4> > : true_type {
41+
};
42+
# endif // _LIBCPP_ABI_ATOMIC_WAIT_NATIVE_BY_SIZE
3443

3544
#else
3645
using __cxx_contention_t _LIBCPP_NODEBUG = int64_t;
3746

47+
# if defined(_LIBCPP_ABI_ATOMIC_WAIT_NATIVE_BY_SIZE)
3848
template <class _Tp>
39-
struct __is_atomic_wait_native_type<_Tp,
40-
__enable_if_t<is_standard_layout<_Tp>::value && (sizeof(_Tp) == 4 || sizeof(_Tp) == 8)> >
49+
struct __is_atomic_wait_native_type<
50+
_Tp,
51+
__enable_if_t<has_unique_object_representations<_Tp>::value && (sizeof(_Tp) == 4 || sizeof(_Tp) == 8)> >
4152
: true_type {};
53+
# else
54+
template <class _Tp>
55+
struct __is_atomic_wait_native_type<_Tp, __enable_if_t<is_same<_Tp, int64_t>::value && sizeof(_Tp) == 4> > : true_type {
56+
};
57+
# endif // _LIBCPP_ABI_ATOMIC_WAIT_NATIVE_BY_SIZE
4258

4359
#endif // __linux__ || (_AIX && !__64BIT__)
4460

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
@@ -84,6 +84,9 @@
8484
// in all versions of the library are available.
8585
#if !_LIBCPP_HAS_VENDOR_AVAILABILITY_ANNOTATIONS
8686

87+
# define _LIBCPP_INTRODUCED_IN_LLVM_22 1
88+
# define _LIBCPP_INTRODUCED_IN_LLVM_22_ATTRIBUTE /* nothing */
89+
8790
# define _LIBCPP_INTRODUCED_IN_LLVM_21 1
8891
# define _LIBCPP_INTRODUCED_IN_LLVM_21_ATTRIBUTE /* nothing */
8992

@@ -112,6 +115,11 @@
112115

113116
// clang-format off
114117

118+
// LLVM 22
119+
// TODO: Fill this in
120+
# define _LIBCPP_INTRODUCED_IN_LLVM_22 0
121+
# define _LIBCPP_INTRODUCED_IN_LLVM_22_ATTRIBUTE __attribute__((unavailable))
122+
115123
// LLVM 21
116124
// TODO: Fill this in
117125
# define _LIBCPP_INTRODUCED_IN_LLVM_21 0
@@ -216,6 +224,13 @@
216224

217225
#endif
218226

227+
// This controls the availability of new implementation of std::atomic's
228+
// wait, notify_one and notify all. The new implementation uses
229+
// the native atomic wait/notify operations on platforms that support them
230+
// based on the size of the atomic type, instead of the type itself.
231+
#define _LIBCPP_AVAILABILITY_HAS_NEW_SYNC _LIBCPP_INTRODUCED_IN_LLVM_22
232+
#define _LIBCPP_AVAILABILITY_NEW_SYNC _LIBCPP_INTRODUCED_IN_LLVM_22_ATTRIBUTE
233+
219234
// Enable additional explicit instantiations of iostreams components. This
220235
// reduces the number of weak definitions generated in programs that use
221236
// iostreams by providing a single strong definition in the shared library.

0 commit comments

Comments
 (0)