xref: /freebsd-src/contrib/llvm-project/libcxx/include/__atomic/atomic_base.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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_BASE_H
1006c3fb27SDimitry Andric #define _LIBCPP___ATOMIC_ATOMIC_BASE_H
1106c3fb27SDimitry Andric 
1206c3fb27SDimitry Andric #include <__atomic/atomic_sync.h>
1306c3fb27SDimitry Andric #include <__atomic/check_memory_order.h>
1406c3fb27SDimitry Andric #include <__atomic/cxx_atomic_impl.h>
1506c3fb27SDimitry Andric #include <__atomic/is_always_lock_free.h>
1606c3fb27SDimitry Andric #include <__atomic/memory_order.h>
1706c3fb27SDimitry Andric #include <__config>
1806c3fb27SDimitry Andric #include <__memory/addressof.h>
1906c3fb27SDimitry Andric #include <__type_traits/is_integral.h>
20*0fca6ea1SDimitry Andric #include <__type_traits/is_nothrow_constructible.h>
2106c3fb27SDimitry Andric #include <__type_traits/is_same.h>
2206c3fb27SDimitry Andric #include <version>
2306c3fb27SDimitry Andric 
2406c3fb27SDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
2506c3fb27SDimitry Andric #  pragma GCC system_header
2606c3fb27SDimitry Andric #endif
2706c3fb27SDimitry Andric 
2806c3fb27SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD
2906c3fb27SDimitry Andric 
3006c3fb27SDimitry Andric template <class _Tp, bool = is_integral<_Tp>::value && !is_same<_Tp, bool>::value>
3106c3fb27SDimitry Andric struct __atomic_base // false
3206c3fb27SDimitry Andric {
3306c3fb27SDimitry Andric   mutable __cxx_atomic_impl<_Tp> __a_;
3406c3fb27SDimitry Andric 
3506c3fb27SDimitry Andric #if _LIBCPP_STD_VER >= 17
36*0fca6ea1SDimitry Andric   static constexpr bool is_always_lock_free = __libcpp_is_always_lock_free<__cxx_atomic_impl<_Tp> >::__value;
3706c3fb27SDimitry Andric #endif
3806c3fb27SDimitry Andric 
39cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI bool is_lock_free() const volatile _NOEXCEPT {
40cb14a3feSDimitry Andric     return __cxx_atomic_is_lock_free(sizeof(__cxx_atomic_impl<_Tp>));
41cb14a3feSDimitry Andric   }
42cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI bool is_lock_free() const _NOEXCEPT {
43cb14a3feSDimitry Andric     return static_cast<__atomic_base const volatile*>(this)->is_lock_free();
44cb14a3feSDimitry Andric   }
4506c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI void store(_Tp __d, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT
4606c3fb27SDimitry Andric       _LIBCPP_CHECK_STORE_MEMORY_ORDER(__m) {
4706c3fb27SDimitry Andric     std::__cxx_atomic_store(std::addressof(__a_), __d, __m);
4806c3fb27SDimitry Andric   }
4906c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI void store(_Tp __d, memory_order __m = memory_order_seq_cst) _NOEXCEPT
5006c3fb27SDimitry Andric       _LIBCPP_CHECK_STORE_MEMORY_ORDER(__m) {
5106c3fb27SDimitry Andric     std::__cxx_atomic_store(std::addressof(__a_), __d, __m);
5206c3fb27SDimitry Andric   }
5306c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI _Tp load(memory_order __m = memory_order_seq_cst) const volatile _NOEXCEPT
5406c3fb27SDimitry Andric       _LIBCPP_CHECK_LOAD_MEMORY_ORDER(__m) {
5506c3fb27SDimitry Andric     return std::__cxx_atomic_load(std::addressof(__a_), __m);
5606c3fb27SDimitry Andric   }
5706c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI _Tp load(memory_order __m = memory_order_seq_cst) const _NOEXCEPT
5806c3fb27SDimitry Andric       _LIBCPP_CHECK_LOAD_MEMORY_ORDER(__m) {
5906c3fb27SDimitry Andric     return std::__cxx_atomic_load(std::addressof(__a_), __m);
6006c3fb27SDimitry Andric   }
61cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI operator _Tp() const volatile _NOEXCEPT { return load(); }
62cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI operator _Tp() const _NOEXCEPT { return load(); }
6306c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI _Tp exchange(_Tp __d, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT {
6406c3fb27SDimitry Andric     return std::__cxx_atomic_exchange(std::addressof(__a_), __d, __m);
6506c3fb27SDimitry Andric   }
6606c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI _Tp exchange(_Tp __d, memory_order __m = memory_order_seq_cst) _NOEXCEPT {
6706c3fb27SDimitry Andric     return std::__cxx_atomic_exchange(std::addressof(__a_), __d, __m);
6806c3fb27SDimitry Andric   }
6906c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI bool
7006c3fb27SDimitry Andric   compare_exchange_weak(_Tp& __e, _Tp __d, memory_order __s, memory_order __f) volatile _NOEXCEPT
7106c3fb27SDimitry Andric       _LIBCPP_CHECK_EXCHANGE_MEMORY_ORDER(__s, __f) {
7206c3fb27SDimitry Andric     return std::__cxx_atomic_compare_exchange_weak(std::addressof(__a_), std::addressof(__e), __d, __s, __f);
7306c3fb27SDimitry Andric   }
7406c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI bool compare_exchange_weak(_Tp& __e, _Tp __d, memory_order __s, memory_order __f) _NOEXCEPT
7506c3fb27SDimitry Andric       _LIBCPP_CHECK_EXCHANGE_MEMORY_ORDER(__s, __f) {
7606c3fb27SDimitry Andric     return std::__cxx_atomic_compare_exchange_weak(std::addressof(__a_), std::addressof(__e), __d, __s, __f);
7706c3fb27SDimitry Andric   }
7806c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI bool
7906c3fb27SDimitry Andric   compare_exchange_strong(_Tp& __e, _Tp __d, memory_order __s, memory_order __f) volatile _NOEXCEPT
8006c3fb27SDimitry Andric       _LIBCPP_CHECK_EXCHANGE_MEMORY_ORDER(__s, __f) {
8106c3fb27SDimitry Andric     return std::__cxx_atomic_compare_exchange_strong(std::addressof(__a_), std::addressof(__e), __d, __s, __f);
8206c3fb27SDimitry Andric   }
8306c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI bool compare_exchange_strong(_Tp& __e, _Tp __d, memory_order __s, memory_order __f) _NOEXCEPT
8406c3fb27SDimitry Andric       _LIBCPP_CHECK_EXCHANGE_MEMORY_ORDER(__s, __f) {
8506c3fb27SDimitry Andric     return std::__cxx_atomic_compare_exchange_strong(std::addressof(__a_), std::addressof(__e), __d, __s, __f);
8606c3fb27SDimitry Andric   }
8706c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI bool
8806c3fb27SDimitry Andric   compare_exchange_weak(_Tp& __e, _Tp __d, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT {
8906c3fb27SDimitry Andric     return std::__cxx_atomic_compare_exchange_weak(std::addressof(__a_), std::addressof(__e), __d, __m, __m);
9006c3fb27SDimitry Andric   }
9106c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI bool
9206c3fb27SDimitry Andric   compare_exchange_weak(_Tp& __e, _Tp __d, memory_order __m = memory_order_seq_cst) _NOEXCEPT {
9306c3fb27SDimitry Andric     return std::__cxx_atomic_compare_exchange_weak(std::addressof(__a_), std::addressof(__e), __d, __m, __m);
9406c3fb27SDimitry Andric   }
9506c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI bool
9606c3fb27SDimitry Andric   compare_exchange_strong(_Tp& __e, _Tp __d, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT {
9706c3fb27SDimitry Andric     return std::__cxx_atomic_compare_exchange_strong(std::addressof(__a_), std::addressof(__e), __d, __m, __m);
9806c3fb27SDimitry Andric   }
9906c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI bool
10006c3fb27SDimitry Andric   compare_exchange_strong(_Tp& __e, _Tp __d, memory_order __m = memory_order_seq_cst) _NOEXCEPT {
10106c3fb27SDimitry Andric     return std::__cxx_atomic_compare_exchange_strong(std::addressof(__a_), std::addressof(__e), __d, __m, __m);
10206c3fb27SDimitry Andric   }
10306c3fb27SDimitry Andric 
10406c3fb27SDimitry Andric   _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void wait(_Tp __v, memory_order __m = memory_order_seq_cst) const
10506c3fb27SDimitry Andric       volatile _NOEXCEPT {
106*0fca6ea1SDimitry Andric     std::__atomic_wait(*this, __v, __m);
10706c3fb27SDimitry Andric   }
10806c3fb27SDimitry Andric   _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void
10906c3fb27SDimitry Andric   wait(_Tp __v, memory_order __m = memory_order_seq_cst) const _NOEXCEPT {
110*0fca6ea1SDimitry Andric     std::__atomic_wait(*this, __v, __m);
11106c3fb27SDimitry Andric   }
11206c3fb27SDimitry Andric   _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void notify_one() volatile _NOEXCEPT {
113*0fca6ea1SDimitry Andric     std::__atomic_notify_one(*this);
11406c3fb27SDimitry Andric   }
115*0fca6ea1SDimitry Andric   _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void notify_one() _NOEXCEPT { std::__atomic_notify_one(*this); }
11606c3fb27SDimitry Andric   _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void notify_all() volatile _NOEXCEPT {
117*0fca6ea1SDimitry Andric     std::__atomic_notify_all(*this);
11806c3fb27SDimitry Andric   }
119*0fca6ea1SDimitry Andric   _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void notify_all() _NOEXCEPT { std::__atomic_notify_all(*this); }
12006c3fb27SDimitry Andric 
12106c3fb27SDimitry Andric #if _LIBCPP_STD_VER >= 20
122cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI constexpr __atomic_base() noexcept(is_nothrow_default_constructible_v<_Tp>) : __a_(_Tp()) {}
12306c3fb27SDimitry Andric #else
124cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI __atomic_base() _NOEXCEPT = default;
12506c3fb27SDimitry Andric #endif
12606c3fb27SDimitry Andric 
127cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __atomic_base(_Tp __d) _NOEXCEPT : __a_(__d) {}
12806c3fb27SDimitry Andric 
12906c3fb27SDimitry Andric   __atomic_base(const __atomic_base&) = delete;
13006c3fb27SDimitry Andric };
13106c3fb27SDimitry Andric 
13206c3fb27SDimitry Andric // atomic<Integral>
13306c3fb27SDimitry Andric 
13406c3fb27SDimitry Andric template <class _Tp>
135cb14a3feSDimitry Andric struct __atomic_base<_Tp, true> : public __atomic_base<_Tp, false> {
13606c3fb27SDimitry Andric   using __base = __atomic_base<_Tp, false>;
13706c3fb27SDimitry Andric 
138cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __atomic_base() _NOEXCEPT = default;
13906c3fb27SDimitry Andric 
140cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __atomic_base(_Tp __d) _NOEXCEPT : __base(__d) {}
14106c3fb27SDimitry Andric 
14206c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI _Tp fetch_add(_Tp __op, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT {
14306c3fb27SDimitry Andric     return std::__cxx_atomic_fetch_add(std::addressof(this->__a_), __op, __m);
14406c3fb27SDimitry Andric   }
14506c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI _Tp fetch_add(_Tp __op, memory_order __m = memory_order_seq_cst) _NOEXCEPT {
14606c3fb27SDimitry Andric     return std::__cxx_atomic_fetch_add(std::addressof(this->__a_), __op, __m);
14706c3fb27SDimitry Andric   }
14806c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI _Tp fetch_sub(_Tp __op, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT {
14906c3fb27SDimitry Andric     return std::__cxx_atomic_fetch_sub(std::addressof(this->__a_), __op, __m);
15006c3fb27SDimitry Andric   }
15106c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI _Tp fetch_sub(_Tp __op, memory_order __m = memory_order_seq_cst) _NOEXCEPT {
15206c3fb27SDimitry Andric     return std::__cxx_atomic_fetch_sub(std::addressof(this->__a_), __op, __m);
15306c3fb27SDimitry Andric   }
15406c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI _Tp fetch_and(_Tp __op, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT {
15506c3fb27SDimitry Andric     return std::__cxx_atomic_fetch_and(std::addressof(this->__a_), __op, __m);
15606c3fb27SDimitry Andric   }
15706c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI _Tp fetch_and(_Tp __op, memory_order __m = memory_order_seq_cst) _NOEXCEPT {
15806c3fb27SDimitry Andric     return std::__cxx_atomic_fetch_and(std::addressof(this->__a_), __op, __m);
15906c3fb27SDimitry Andric   }
16006c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI _Tp fetch_or(_Tp __op, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT {
16106c3fb27SDimitry Andric     return std::__cxx_atomic_fetch_or(std::addressof(this->__a_), __op, __m);
16206c3fb27SDimitry Andric   }
16306c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI _Tp fetch_or(_Tp __op, memory_order __m = memory_order_seq_cst) _NOEXCEPT {
16406c3fb27SDimitry Andric     return std::__cxx_atomic_fetch_or(std::addressof(this->__a_), __op, __m);
16506c3fb27SDimitry Andric   }
16606c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI _Tp fetch_xor(_Tp __op, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT {
16706c3fb27SDimitry Andric     return std::__cxx_atomic_fetch_xor(std::addressof(this->__a_), __op, __m);
16806c3fb27SDimitry Andric   }
16906c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI _Tp fetch_xor(_Tp __op, memory_order __m = memory_order_seq_cst) _NOEXCEPT {
17006c3fb27SDimitry Andric     return std::__cxx_atomic_fetch_xor(std::addressof(this->__a_), __op, __m);
17106c3fb27SDimitry Andric   }
17206c3fb27SDimitry Andric 
173cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _Tp operator++(int) volatile _NOEXCEPT { return fetch_add(_Tp(1)); }
174cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _Tp operator++(int) _NOEXCEPT { return fetch_add(_Tp(1)); }
175cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _Tp operator--(int) volatile _NOEXCEPT { return fetch_sub(_Tp(1)); }
176cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _Tp operator--(int) _NOEXCEPT { return fetch_sub(_Tp(1)); }
177cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _Tp operator++() volatile _NOEXCEPT { return fetch_add(_Tp(1)) + _Tp(1); }
178cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _Tp operator++() _NOEXCEPT { return fetch_add(_Tp(1)) + _Tp(1); }
179cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _Tp operator--() volatile _NOEXCEPT { return fetch_sub(_Tp(1)) - _Tp(1); }
180cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _Tp operator--() _NOEXCEPT { return fetch_sub(_Tp(1)) - _Tp(1); }
181cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _Tp operator+=(_Tp __op) volatile _NOEXCEPT { return fetch_add(__op) + __op; }
182cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _Tp operator+=(_Tp __op) _NOEXCEPT { return fetch_add(__op) + __op; }
183cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _Tp operator-=(_Tp __op) volatile _NOEXCEPT { return fetch_sub(__op) - __op; }
184cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _Tp operator-=(_Tp __op) _NOEXCEPT { return fetch_sub(__op) - __op; }
185cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _Tp operator&=(_Tp __op) volatile _NOEXCEPT { return fetch_and(__op) & __op; }
186cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _Tp operator&=(_Tp __op) _NOEXCEPT { return fetch_and(__op) & __op; }
187cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _Tp operator|=(_Tp __op) volatile _NOEXCEPT { return fetch_or(__op) | __op; }
188cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _Tp operator|=(_Tp __op) _NOEXCEPT { return fetch_or(__op) | __op; }
189cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _Tp operator^=(_Tp __op) volatile _NOEXCEPT { return fetch_xor(__op) ^ __op; }
190cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _Tp operator^=(_Tp __op) _NOEXCEPT { return fetch_xor(__op) ^ __op; }
19106c3fb27SDimitry Andric };
19206c3fb27SDimitry Andric 
193*0fca6ea1SDimitry Andric // Here we need _IsIntegral because the default template argument is not enough
194*0fca6ea1SDimitry Andric // e.g  __atomic_base<int> is __atomic_base<int, true>, which inherits from
195*0fca6ea1SDimitry Andric // __atomic_base<int, false> and the caller of the wait function is
196*0fca6ea1SDimitry Andric // __atomic_base<int, false>. So specializing __atomic_base<_Tp> does not work
197*0fca6ea1SDimitry Andric template <class _Tp, bool _IsIntegral>
198*0fca6ea1SDimitry Andric struct __atomic_waitable_traits<__atomic_base<_Tp, _IsIntegral> > {
199*0fca6ea1SDimitry Andric   static _LIBCPP_HIDE_FROM_ABI _Tp __atomic_load(const __atomic_base<_Tp, _IsIntegral>& __a, memory_order __order) {
200*0fca6ea1SDimitry Andric     return __a.load(__order);
201*0fca6ea1SDimitry Andric   }
202*0fca6ea1SDimitry Andric 
203*0fca6ea1SDimitry Andric   static _LIBCPP_HIDE_FROM_ABI _Tp
204*0fca6ea1SDimitry Andric   __atomic_load(const volatile __atomic_base<_Tp, _IsIntegral>& __this, memory_order __order) {
205*0fca6ea1SDimitry Andric     return __this.load(__order);
206*0fca6ea1SDimitry Andric   }
207*0fca6ea1SDimitry Andric 
208*0fca6ea1SDimitry Andric   static _LIBCPP_HIDE_FROM_ABI const __cxx_atomic_impl<_Tp>*
209*0fca6ea1SDimitry Andric   __atomic_contention_address(const __atomic_base<_Tp, _IsIntegral>& __a) {
210*0fca6ea1SDimitry Andric     return std::addressof(__a.__a_);
211*0fca6ea1SDimitry Andric   }
212*0fca6ea1SDimitry Andric 
213*0fca6ea1SDimitry Andric   static _LIBCPP_HIDE_FROM_ABI const volatile __cxx_atomic_impl<_Tp>*
214*0fca6ea1SDimitry Andric   __atomic_contention_address(const volatile __atomic_base<_Tp, _IsIntegral>& __this) {
215*0fca6ea1SDimitry Andric     return std::addressof(__this.__a_);
216*0fca6ea1SDimitry Andric   }
217*0fca6ea1SDimitry Andric };
218*0fca6ea1SDimitry Andric 
21906c3fb27SDimitry Andric _LIBCPP_END_NAMESPACE_STD
22006c3fb27SDimitry Andric 
22106c3fb27SDimitry Andric #endif // _LIBCPP___ATOMIC_ATOMIC_BASE_H
222