Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-03 08:13:23

0001 //===----------------------------------------------------------------------===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 
0009 #ifndef _LIBCPP___CXX03___ATOMIC_ATOMIC_SYNC_H
0010 #define _LIBCPP___CXX03___ATOMIC_ATOMIC_SYNC_H
0011 
0012 #include <__cxx03/__atomic/contention_t.h>
0013 #include <__cxx03/__atomic/cxx_atomic_impl.h>
0014 #include <__cxx03/__atomic/memory_order.h>
0015 #include <__cxx03/__atomic/to_gcc_order.h>
0016 #include <__cxx03/__chrono/duration.h>
0017 #include <__cxx03/__config>
0018 #include <__cxx03/__memory/addressof.h>
0019 #include <__cxx03/__thread/poll_with_backoff.h>
0020 #include <__cxx03/__thread/support.h>
0021 #include <__cxx03/__type_traits/conjunction.h>
0022 #include <__cxx03/__type_traits/decay.h>
0023 #include <__cxx03/__type_traits/invoke.h>
0024 #include <__cxx03/__type_traits/void_t.h>
0025 #include <__cxx03/__utility/declval.h>
0026 #include <__cxx03/cstring>
0027 
0028 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
0029 #  pragma GCC system_header
0030 #endif
0031 
0032 _LIBCPP_BEGIN_NAMESPACE_STD
0033 
0034 // The customisation points to enable the following functions:
0035 // - __atomic_wait
0036 // - __atomic_wait_unless
0037 // - __atomic_notify_one
0038 // - __atomic_notify_all
0039 // Note that std::atomic<T>::wait was back-ported to C++03
0040 // The below implementations look ugly to support C++03
0041 template <class _Tp, class = void>
0042 struct __atomic_waitable_traits {
0043   template <class _AtomicWaitable>
0044   static void __atomic_load(_AtomicWaitable&&, memory_order) = delete;
0045 
0046   template <class _AtomicWaitable>
0047   static void __atomic_contention_address(_AtomicWaitable&&) = delete;
0048 };
0049 
0050 template <class _Tp, class = void>
0051 struct __atomic_waitable : false_type {};
0052 
0053 template <class _Tp>
0054 struct __atomic_waitable< _Tp,
0055                           __void_t<decltype(__atomic_waitable_traits<__decay_t<_Tp> >::__atomic_load(
0056                                        std::declval<const _Tp&>(), std::declval<memory_order>())),
0057                                    decltype(__atomic_waitable_traits<__decay_t<_Tp> >::__atomic_contention_address(
0058                                        std::declval<const _Tp&>()))> > : true_type {};
0059 
0060 template <class _AtomicWaitable, class _Poll>
0061 struct __atomic_wait_poll_impl {
0062   const _AtomicWaitable& __a_;
0063   _Poll __poll_;
0064   memory_order __order_;
0065 
0066   _LIBCPP_HIDE_FROM_ABI bool operator()() const {
0067     auto __current_val = __atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__atomic_load(__a_, __order_);
0068     return __poll_(__current_val);
0069   }
0070 };
0071 
0072 #ifndef _LIBCPP_HAS_NO_THREADS
0073 
0074 _LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void __cxx_atomic_notify_one(void const volatile*) _NOEXCEPT;
0075 _LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void __cxx_atomic_notify_all(void const volatile*) _NOEXCEPT;
0076 _LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI __cxx_contention_t
0077 __libcpp_atomic_monitor(void const volatile*) _NOEXCEPT;
0078 _LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void
0079 __libcpp_atomic_wait(void const volatile*, __cxx_contention_t) _NOEXCEPT;
0080 
0081 _LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void
0082 __cxx_atomic_notify_one(__cxx_atomic_contention_t const volatile*) _NOEXCEPT;
0083 _LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void
0084 __cxx_atomic_notify_all(__cxx_atomic_contention_t const volatile*) _NOEXCEPT;
0085 _LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI __cxx_contention_t
0086 __libcpp_atomic_monitor(__cxx_atomic_contention_t const volatile*) _NOEXCEPT;
0087 _LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void
0088 __libcpp_atomic_wait(__cxx_atomic_contention_t const volatile*, __cxx_contention_t) _NOEXCEPT;
0089 
0090 template <class _AtomicWaitable, class _Poll>
0091 struct __atomic_wait_backoff_impl {
0092   const _AtomicWaitable& __a_;
0093   _Poll __poll_;
0094   memory_order __order_;
0095 
0096   using __waitable_traits = __atomic_waitable_traits<__decay_t<_AtomicWaitable> >;
0097 
0098   _LIBCPP_AVAILABILITY_SYNC
0099   _LIBCPP_HIDE_FROM_ABI bool
0100   __update_monitor_val_and_poll(__cxx_atomic_contention_t const volatile*, __cxx_contention_t& __monitor_val) const {
0101     // In case the contention type happens to be __cxx_atomic_contention_t, i.e. __cxx_atomic_impl<int64_t>,
0102     // the platform wait is directly monitoring the atomic value itself.
0103     // `__poll_` takes the current value of the atomic as an in-out argument
0104     // to potentially modify it. After it returns, `__monitor` has a value
0105     // which can be safely waited on by `std::__libcpp_atomic_wait` without any
0106     // ABA style issues.
0107     __monitor_val = __waitable_traits::__atomic_load(__a_, __order_);
0108     return __poll_(__monitor_val);
0109   }
0110 
0111   _LIBCPP_AVAILABILITY_SYNC
0112   _LIBCPP_HIDE_FROM_ABI bool
0113   __update_monitor_val_and_poll(void const volatile* __contention_address, __cxx_contention_t& __monitor_val) const {
0114     // In case the contention type is anything else, platform wait is monitoring a __cxx_atomic_contention_t
0115     // from the global pool, the monitor comes from __libcpp_atomic_monitor
0116     __monitor_val      = std::__libcpp_atomic_monitor(__contention_address);
0117     auto __current_val = __waitable_traits::__atomic_load(__a_, __order_);
0118     return __poll_(__current_val);
0119   }
0120 
0121   _LIBCPP_AVAILABILITY_SYNC
0122   _LIBCPP_HIDE_FROM_ABI bool operator()(chrono::nanoseconds __elapsed) const {
0123     if (__elapsed > chrono::microseconds(64)) {
0124       auto __contention_address = __waitable_traits::__atomic_contention_address(__a_);
0125       __cxx_contention_t __monitor_val;
0126       if (__update_monitor_val_and_poll(__contention_address, __monitor_val))
0127         return true;
0128       std::__libcpp_atomic_wait(__contention_address, __monitor_val);
0129     } else if (__elapsed > chrono::microseconds(4))
0130       __libcpp_thread_yield();
0131     else {
0132     } // poll
0133     return false;
0134   }
0135 };
0136 
0137 // The semantics of this function are similar to `atomic`'s
0138 // `.wait(T old, std::memory_order order)`, but instead of having a hardcoded
0139 // predicate (is the loaded value unequal to `old`?), the predicate function is
0140 // specified as an argument. The loaded value is given as an in-out argument to
0141 // the predicate. If the predicate function returns `true`,
0142 // `__atomic_wait_unless` will return. If the predicate function returns
0143 // `false`, it must set the argument to its current understanding of the atomic
0144 // value. The predicate function must not return `false` spuriously.
0145 template <class _AtomicWaitable, class _Poll>
0146 _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void
0147 __atomic_wait_unless(const _AtomicWaitable& __a, _Poll&& __poll, memory_order __order) {
0148   static_assert(__atomic_waitable<_AtomicWaitable>::value, "");
0149   __atomic_wait_poll_impl<_AtomicWaitable, __decay_t<_Poll> > __poll_impl     = {__a, __poll, __order};
0150   __atomic_wait_backoff_impl<_AtomicWaitable, __decay_t<_Poll> > __backoff_fn = {__a, __poll, __order};
0151   std::__libcpp_thread_poll_with_backoff(__poll_impl, __backoff_fn);
0152 }
0153 
0154 template <class _AtomicWaitable>
0155 _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void __atomic_notify_one(const _AtomicWaitable& __a) {
0156   static_assert(__atomic_waitable<_AtomicWaitable>::value, "");
0157   std::__cxx_atomic_notify_one(__atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__atomic_contention_address(__a));
0158 }
0159 
0160 template <class _AtomicWaitable>
0161 _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void __atomic_notify_all(const _AtomicWaitable& __a) {
0162   static_assert(__atomic_waitable<_AtomicWaitable>::value, "");
0163   std::__cxx_atomic_notify_all(__atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__atomic_contention_address(__a));
0164 }
0165 
0166 #else // _LIBCPP_HAS_NO_THREADS
0167 
0168 template <class _AtomicWaitable, class _Poll>
0169 _LIBCPP_HIDE_FROM_ABI void __atomic_wait_unless(const _AtomicWaitable& __a, _Poll&& __poll, memory_order __order) {
0170   __atomic_wait_poll_impl<_AtomicWaitable, __decay_t<_Poll> > __poll_fn = {__a, __poll, __order};
0171   std::__libcpp_thread_poll_with_backoff(__poll_fn, __spinning_backoff_policy());
0172 }
0173 
0174 template <class _AtomicWaitable>
0175 _LIBCPP_HIDE_FROM_ABI void __atomic_notify_one(const _AtomicWaitable&) {}
0176 
0177 template <class _AtomicWaitable>
0178 _LIBCPP_HIDE_FROM_ABI void __atomic_notify_all(const _AtomicWaitable&) {}
0179 
0180 #endif // _LIBCPP_HAS_NO_THREADS
0181 
0182 template <typename _Tp>
0183 _LIBCPP_HIDE_FROM_ABI bool __cxx_nonatomic_compare_equal(_Tp const& __lhs, _Tp const& __rhs) {
0184   return std::memcmp(std::addressof(__lhs), std::addressof(__rhs), sizeof(_Tp)) == 0;
0185 }
0186 
0187 template <class _Tp>
0188 struct __atomic_compare_unequal_to {
0189   _Tp __val_;
0190   _LIBCPP_HIDE_FROM_ABI bool operator()(const _Tp& __arg) const {
0191     return !std::__cxx_nonatomic_compare_equal(__arg, __val_);
0192   }
0193 };
0194 
0195 template <class _AtomicWaitable, class _Up>
0196 _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void
0197 __atomic_wait(_AtomicWaitable& __a, _Up __val, memory_order __order) {
0198   static_assert(__atomic_waitable<_AtomicWaitable>::value, "");
0199   __atomic_compare_unequal_to<_Up> __nonatomic_equal = {__val};
0200   std::__atomic_wait_unless(__a, __nonatomic_equal, __order);
0201 }
0202 
0203 _LIBCPP_END_NAMESPACE_STD
0204 
0205 #endif // _LIBCPP___CXX03___ATOMIC_ATOMIC_SYNC_H