106c3fb27SDimitry Andric //===----------------------------------------------------------------------===// 206c3fb27SDimitry Andric // 306c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 406c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 506c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 606c3fb27SDimitry Andric // 706c3fb27SDimitry Andric //===----------------------------------------------------------------------===// 806c3fb27SDimitry Andric 906c3fb27SDimitry Andric #ifndef _LIBCPP___ATOMIC_ATOMIC_SYNC_H 1006c3fb27SDimitry Andric #define _LIBCPP___ATOMIC_ATOMIC_SYNC_H 1106c3fb27SDimitry Andric 1206c3fb27SDimitry Andric #include <__atomic/contention_t.h> 1306c3fb27SDimitry Andric #include <__atomic/cxx_atomic_impl.h> 1406c3fb27SDimitry Andric #include <__atomic/memory_order.h> 15*0fca6ea1SDimitry Andric #include <__atomic/to_gcc_order.h> 1606c3fb27SDimitry Andric #include <__chrono/duration.h> 1706c3fb27SDimitry Andric #include <__config> 1806c3fb27SDimitry Andric #include <__memory/addressof.h> 1906c3fb27SDimitry Andric #include <__thread/poll_with_backoff.h> 20*0fca6ea1SDimitry Andric #include <__thread/support.h> 21*0fca6ea1SDimitry Andric #include <__type_traits/conjunction.h> 2206c3fb27SDimitry Andric #include <__type_traits/decay.h> 23*0fca6ea1SDimitry Andric #include <__type_traits/invoke.h> 24*0fca6ea1SDimitry Andric #include <__type_traits/void_t.h> 25*0fca6ea1SDimitry Andric #include <__utility/declval.h> 2606c3fb27SDimitry Andric #include <cstring> 2706c3fb27SDimitry Andric 2806c3fb27SDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 2906c3fb27SDimitry Andric # pragma GCC system_header 3006c3fb27SDimitry Andric #endif 3106c3fb27SDimitry Andric 3206c3fb27SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD 3306c3fb27SDimitry Andric 34*0fca6ea1SDimitry Andric // The customisation points to enable the following functions: 35*0fca6ea1SDimitry Andric // - __atomic_wait 36*0fca6ea1SDimitry Andric // - __atomic_wait_unless 37*0fca6ea1SDimitry Andric // - __atomic_notify_one 38*0fca6ea1SDimitry Andric // - __atomic_notify_all 39*0fca6ea1SDimitry Andric // Note that std::atomic<T>::wait was back-ported to C++03 40*0fca6ea1SDimitry Andric // The below implementations look ugly to support C++03 41*0fca6ea1SDimitry Andric template <class _Tp, class = void> 42*0fca6ea1SDimitry Andric struct __atomic_waitable_traits { 43*0fca6ea1SDimitry Andric template <class _AtomicWaitable> 44*0fca6ea1SDimitry Andric static void __atomic_load(_AtomicWaitable&&, memory_order) = delete; 45*0fca6ea1SDimitry Andric 46*0fca6ea1SDimitry Andric template <class _AtomicWaitable> 47*0fca6ea1SDimitry Andric static void __atomic_contention_address(_AtomicWaitable&&) = delete; 48*0fca6ea1SDimitry Andric }; 49*0fca6ea1SDimitry Andric 50*0fca6ea1SDimitry Andric template <class _Tp, class = void> 51*0fca6ea1SDimitry Andric struct __atomic_waitable : false_type {}; 52*0fca6ea1SDimitry Andric 53*0fca6ea1SDimitry Andric template <class _Tp> 54*0fca6ea1SDimitry Andric struct __atomic_waitable< _Tp, 55*0fca6ea1SDimitry Andric __void_t<decltype(__atomic_waitable_traits<__decay_t<_Tp> >::__atomic_load( 56*0fca6ea1SDimitry Andric std::declval<const _Tp&>(), std::declval<memory_order>())), 57*0fca6ea1SDimitry Andric decltype(__atomic_waitable_traits<__decay_t<_Tp> >::__atomic_contention_address( 58*0fca6ea1SDimitry Andric std::declval<const _Tp&>()))> > : true_type {}; 59*0fca6ea1SDimitry Andric 60*0fca6ea1SDimitry Andric template <class _AtomicWaitable, class _Poll> 61*0fca6ea1SDimitry Andric struct __atomic_wait_poll_impl { 62*0fca6ea1SDimitry Andric const _AtomicWaitable& __a_; 63*0fca6ea1SDimitry Andric _Poll __poll_; 64*0fca6ea1SDimitry Andric memory_order __order_; 65*0fca6ea1SDimitry Andric 66*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI bool operator()() const { 67*0fca6ea1SDimitry Andric auto __current_val = __atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__atomic_load(__a_, __order_); 68*0fca6ea1SDimitry Andric return __poll_(__current_val); 69*0fca6ea1SDimitry Andric } 70*0fca6ea1SDimitry Andric }; 71*0fca6ea1SDimitry Andric 7206c3fb27SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS 7306c3fb27SDimitry Andric 74*0fca6ea1SDimitry Andric _LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void __cxx_atomic_notify_one(void const volatile*) _NOEXCEPT; 75*0fca6ea1SDimitry Andric _LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void __cxx_atomic_notify_all(void const volatile*) _NOEXCEPT; 76cb14a3feSDimitry Andric _LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI __cxx_contention_t 77*0fca6ea1SDimitry Andric __libcpp_atomic_monitor(void const volatile*) _NOEXCEPT; 78cb14a3feSDimitry Andric _LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void 79*0fca6ea1SDimitry Andric __libcpp_atomic_wait(void const volatile*, __cxx_contention_t) _NOEXCEPT; 8006c3fb27SDimitry Andric 81*0fca6ea1SDimitry Andric _LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void 82*0fca6ea1SDimitry Andric __cxx_atomic_notify_one(__cxx_atomic_contention_t const volatile*) _NOEXCEPT; 83*0fca6ea1SDimitry Andric _LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void 84*0fca6ea1SDimitry Andric __cxx_atomic_notify_all(__cxx_atomic_contention_t const volatile*) _NOEXCEPT; 85*0fca6ea1SDimitry Andric _LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI __cxx_contention_t 86*0fca6ea1SDimitry Andric __libcpp_atomic_monitor(__cxx_atomic_contention_t const volatile*) _NOEXCEPT; 87*0fca6ea1SDimitry Andric _LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void 88*0fca6ea1SDimitry Andric __libcpp_atomic_wait(__cxx_atomic_contention_t const volatile*, __cxx_contention_t) _NOEXCEPT; 89*0fca6ea1SDimitry Andric 90*0fca6ea1SDimitry Andric template <class _AtomicWaitable, class _Poll> 91*0fca6ea1SDimitry Andric struct __atomic_wait_backoff_impl { 92*0fca6ea1SDimitry Andric const _AtomicWaitable& __a_; 93*0fca6ea1SDimitry Andric _Poll __poll_; 94*0fca6ea1SDimitry Andric memory_order __order_; 95*0fca6ea1SDimitry Andric 96*0fca6ea1SDimitry Andric using __waitable_traits = __atomic_waitable_traits<__decay_t<_AtomicWaitable> >; 97*0fca6ea1SDimitry Andric 98*0fca6ea1SDimitry Andric _LIBCPP_AVAILABILITY_SYNC 99*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI bool 100*0fca6ea1SDimitry Andric __update_monitor_val_and_poll(__cxx_atomic_contention_t const volatile*, __cxx_contention_t& __monitor_val) const { 101*0fca6ea1SDimitry Andric // In case the contention type happens to be __cxx_atomic_contention_t, i.e. __cxx_atomic_impl<int64_t>, 102*0fca6ea1SDimitry Andric // the platform wait is directly monitoring the atomic value itself. 103*0fca6ea1SDimitry Andric // `__poll_` takes the current value of the atomic as an in-out argument 104*0fca6ea1SDimitry Andric // to potentially modify it. After it returns, `__monitor` has a value 105*0fca6ea1SDimitry Andric // which can be safely waited on by `std::__libcpp_atomic_wait` without any 106*0fca6ea1SDimitry Andric // ABA style issues. 107*0fca6ea1SDimitry Andric __monitor_val = __waitable_traits::__atomic_load(__a_, __order_); 108*0fca6ea1SDimitry Andric return __poll_(__monitor_val); 109*0fca6ea1SDimitry Andric } 110*0fca6ea1SDimitry Andric 111*0fca6ea1SDimitry Andric _LIBCPP_AVAILABILITY_SYNC 112*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI bool 113*0fca6ea1SDimitry Andric __update_monitor_val_and_poll(void const volatile* __contention_address, __cxx_contention_t& __monitor_val) const { 114*0fca6ea1SDimitry Andric // In case the contention type is anything else, platform wait is monitoring a __cxx_atomic_contention_t 115*0fca6ea1SDimitry Andric // from the global pool, the monitor comes from __libcpp_atomic_monitor 116*0fca6ea1SDimitry Andric __monitor_val = std::__libcpp_atomic_monitor(__contention_address); 117*0fca6ea1SDimitry Andric auto __current_val = __waitable_traits::__atomic_load(__a_, __order_); 118*0fca6ea1SDimitry Andric return __poll_(__current_val); 119*0fca6ea1SDimitry Andric } 120*0fca6ea1SDimitry Andric 12106c3fb27SDimitry Andric _LIBCPP_AVAILABILITY_SYNC 122cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI bool operator()(chrono::nanoseconds __elapsed) const { 123cb14a3feSDimitry Andric if (__elapsed > chrono::microseconds(64)) { 124*0fca6ea1SDimitry Andric auto __contention_address = __waitable_traits::__atomic_contention_address(__a_); 125*0fca6ea1SDimitry Andric __cxx_contention_t __monitor_val; 126*0fca6ea1SDimitry Andric if (__update_monitor_val_and_poll(__contention_address, __monitor_val)) 12706c3fb27SDimitry Andric return true; 128*0fca6ea1SDimitry Andric std::__libcpp_atomic_wait(__contention_address, __monitor_val); 129cb14a3feSDimitry Andric } else if (__elapsed > chrono::microseconds(4)) 13006c3fb27SDimitry Andric __libcpp_thread_yield(); 131cb14a3feSDimitry Andric else { 132cb14a3feSDimitry Andric } // poll 13306c3fb27SDimitry Andric return false; 13406c3fb27SDimitry Andric } 13506c3fb27SDimitry Andric }; 13606c3fb27SDimitry Andric 137*0fca6ea1SDimitry Andric // The semantics of this function are similar to `atomic`'s 138*0fca6ea1SDimitry Andric // `.wait(T old, std::memory_order order)`, but instead of having a hardcoded 139*0fca6ea1SDimitry Andric // predicate (is the loaded value unequal to `old`?), the predicate function is 140*0fca6ea1SDimitry Andric // specified as an argument. The loaded value is given as an in-out argument to 141*0fca6ea1SDimitry Andric // the predicate. If the predicate function returns `true`, 142*0fca6ea1SDimitry Andric // `__atomic_wait_unless` will return. If the predicate function returns 143*0fca6ea1SDimitry Andric // `false`, it must set the argument to its current understanding of the atomic 144*0fca6ea1SDimitry Andric // value. The predicate function must not return `false` spuriously. 145*0fca6ea1SDimitry Andric template <class _AtomicWaitable, class _Poll> 146*0fca6ea1SDimitry Andric _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void 147*0fca6ea1SDimitry Andric __atomic_wait_unless(const _AtomicWaitable& __a, _Poll&& __poll, memory_order __order) { 148*0fca6ea1SDimitry Andric static_assert(__atomic_waitable<_AtomicWaitable>::value, ""); 149*0fca6ea1SDimitry Andric __atomic_wait_poll_impl<_AtomicWaitable, __decay_t<_Poll> > __poll_impl = {__a, __poll, __order}; 150*0fca6ea1SDimitry Andric __atomic_wait_backoff_impl<_AtomicWaitable, __decay_t<_Poll> > __backoff_fn = {__a, __poll, __order}; 151*0fca6ea1SDimitry Andric std::__libcpp_thread_poll_with_backoff(__poll_impl, __backoff_fn); 152*0fca6ea1SDimitry Andric } 153*0fca6ea1SDimitry Andric 154*0fca6ea1SDimitry Andric template <class _AtomicWaitable> 155*0fca6ea1SDimitry Andric _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void __atomic_notify_one(const _AtomicWaitable& __a) { 156*0fca6ea1SDimitry Andric static_assert(__atomic_waitable<_AtomicWaitable>::value, ""); 157*0fca6ea1SDimitry Andric std::__cxx_atomic_notify_one(__atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__atomic_contention_address(__a)); 158*0fca6ea1SDimitry Andric } 159*0fca6ea1SDimitry Andric 160*0fca6ea1SDimitry Andric template <class _AtomicWaitable> 161*0fca6ea1SDimitry Andric _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void __atomic_notify_all(const _AtomicWaitable& __a) { 162*0fca6ea1SDimitry Andric static_assert(__atomic_waitable<_AtomicWaitable>::value, ""); 163*0fca6ea1SDimitry Andric std::__cxx_atomic_notify_all(__atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__atomic_contention_address(__a)); 16406c3fb27SDimitry Andric } 16506c3fb27SDimitry Andric 16606c3fb27SDimitry Andric #else // _LIBCPP_HAS_NO_THREADS 16706c3fb27SDimitry Andric 168*0fca6ea1SDimitry Andric template <class _AtomicWaitable, class _Poll> 169*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI void __atomic_wait_unless(const _AtomicWaitable& __a, _Poll&& __poll, memory_order __order) { 170*0fca6ea1SDimitry Andric __atomic_wait_poll_impl<_AtomicWaitable, __decay_t<_Poll> > __poll_fn = {__a, __poll, __order}; 171*0fca6ea1SDimitry Andric std::__libcpp_thread_poll_with_backoff(__poll_fn, __spinning_backoff_policy()); 17206c3fb27SDimitry Andric } 17306c3fb27SDimitry Andric 174*0fca6ea1SDimitry Andric template <class _AtomicWaitable> 175*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI void __atomic_notify_one(const _AtomicWaitable&) {} 176*0fca6ea1SDimitry Andric 177*0fca6ea1SDimitry Andric template <class _AtomicWaitable> 178*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI void __atomic_notify_all(const _AtomicWaitable&) {} 179*0fca6ea1SDimitry Andric 18006c3fb27SDimitry Andric #endif // _LIBCPP_HAS_NO_THREADS 18106c3fb27SDimitry Andric 182cb14a3feSDimitry Andric template <typename _Tp> 183cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI bool __cxx_nonatomic_compare_equal(_Tp const& __lhs, _Tp const& __rhs) { 18406c3fb27SDimitry Andric return std::memcmp(std::addressof(__lhs), std::addressof(__rhs), sizeof(_Tp)) == 0; 18506c3fb27SDimitry Andric } 18606c3fb27SDimitry Andric 187*0fca6ea1SDimitry Andric template <class _Tp> 188*0fca6ea1SDimitry Andric struct __atomic_compare_unequal_to { 189*0fca6ea1SDimitry Andric _Tp __val_; 190*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI bool operator()(const _Tp& __arg) const { 191*0fca6ea1SDimitry Andric return !std::__cxx_nonatomic_compare_equal(__arg, __val_); 19206c3fb27SDimitry Andric } 19306c3fb27SDimitry Andric }; 19406c3fb27SDimitry Andric 195*0fca6ea1SDimitry Andric template <class _AtomicWaitable, class _Up> 196*0fca6ea1SDimitry Andric _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void 197*0fca6ea1SDimitry Andric __atomic_wait(_AtomicWaitable& __a, _Up __val, memory_order __order) { 198*0fca6ea1SDimitry Andric static_assert(__atomic_waitable<_AtomicWaitable>::value, ""); 199*0fca6ea1SDimitry Andric __atomic_compare_unequal_to<_Up> __nonatomic_equal = {__val}; 200*0fca6ea1SDimitry Andric std::__atomic_wait_unless(__a, __nonatomic_equal, __order); 20106c3fb27SDimitry Andric } 20206c3fb27SDimitry Andric 20306c3fb27SDimitry Andric _LIBCPP_END_NAMESPACE_STD 20406c3fb27SDimitry Andric 20506c3fb27SDimitry Andric #endif // _LIBCPP___ATOMIC_ATOMIC_SYNC_H 206