1 /*
2  * Distributed under the Boost Software License, Version 1.0.
3  * (See accompanying file LICENSE_1_0.txt or copy at
4  * http://www.boost.org/LICENSE_1_0.txt)
5  *
6  * Copyright (c) 2014, 2020 Andrey Semashev
7  */
8 /*!
9  * \file   atomic/detail/core_operations_emulated.hpp
10  *
11  * This header contains lock pool-based implementation of the core atomic operations.
12  */
13 
14 #ifndef BOOST_ATOMIC_DETAIL_CORE_OPERATIONS_EMULATED_HPP_INCLUDED_
15 #define BOOST_ATOMIC_DETAIL_CORE_OPERATIONS_EMULATED_HPP_INCLUDED_
16 
17 #include <cstddef>
18 #include <boost/static_assert.hpp>
19 #include <boost/memory_order.hpp>
20 #include <boost/atomic/detail/config.hpp>
21 #include <boost/atomic/detail/storage_traits.hpp>
22 #include <boost/atomic/detail/core_operations_emulated_fwd.hpp>
23 #include <boost/atomic/detail/lock_pool.hpp>
24 #include <boost/atomic/detail/header.hpp>
25 
26 #ifdef BOOST_HAS_PRAGMA_ONCE
27 #pragma once
28 #endif
29 
30 namespace boost {
31 namespace atomics {
32 namespace detail {
33 
34 template< std::size_t Size, std::size_t Alignment, bool = Alignment >= storage_traits< Size >::native_alignment >
35 struct core_operations_emulated_base
36 {
37     typedef typename storage_traits< Size >::type storage_type;
38 };
39 
40 template< std::size_t Size, std::size_t Alignment >
41 struct core_operations_emulated_base< Size, Alignment, false >
42 {
43     typedef buffer_storage< Size, Alignment > storage_type;
44 };
45 
46 //! Emulated implementation of core atomic operations
47 template< std::size_t Size, std::size_t Alignment, bool Signed, bool Interprocess >
48 struct core_operations_emulated :
49     public core_operations_emulated_base< Size, Alignment >
50 {
51     typedef core_operations_emulated_base< Size, Alignment > base_type;
52 
53     // Define storage_type to have alignment not greater than Alignment. This will allow operations to work with value_types
54     // that possibly have weaker alignment requirements than storage_traits< Size >::type would. This is important for atomic_ref<>.
55     // atomic<> will allow higher alignment requirement than its value_type.
56     // Note that storage_type should be an integral type, if possible, so that arithmetic and bitwise operations are possible.
57     typedef typename base_type::storage_type storage_type;
58 
59     static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = Size;
60     static BOOST_CONSTEXPR_OR_CONST std::size_t storage_alignment = Alignment >= storage_traits< Size >::alignment ? storage_traits< Size >::alignment : Alignment;
61 
62     static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed;
63     static BOOST_CONSTEXPR_OR_CONST bool is_interprocess = Interprocess;
64     static BOOST_CONSTEXPR_OR_CONST bool full_cas_based = false;
65 
66     static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = false;
67 
68     typedef lock_pool::scoped_lock< storage_alignment > scoped_lock;
69 
storeboost::atomics::detail::core_operations_emulated70     static void store(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
71     {
72         BOOST_STATIC_ASSERT_MSG(!is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object");
73         scoped_lock lock(&storage);
74         const_cast< storage_type& >(storage) = v;
75     }
76 
loadboost::atomics::detail::core_operations_emulated77     static storage_type load(storage_type const volatile& storage, memory_order) BOOST_NOEXCEPT
78     {
79         BOOST_STATIC_ASSERT_MSG(!is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object");
80         scoped_lock lock(&storage);
81         return const_cast< storage_type const& >(storage);
82     }
83 
fetch_addboost::atomics::detail::core_operations_emulated84     static storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
85     {
86         BOOST_STATIC_ASSERT_MSG(!is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object");
87         storage_type& s = const_cast< storage_type& >(storage);
88         scoped_lock lock(&storage);
89         storage_type old_val = s;
90         s += v;
91         return old_val;
92     }
93 
fetch_subboost::atomics::detail::core_operations_emulated94     static storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
95     {
96         BOOST_STATIC_ASSERT_MSG(!is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object");
97         storage_type& s = const_cast< storage_type& >(storage);
98         scoped_lock lock(&storage);
99         storage_type old_val = s;
100         s -= v;
101         return old_val;
102     }
103 
exchangeboost::atomics::detail::core_operations_emulated104     static storage_type exchange(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
105     {
106         BOOST_STATIC_ASSERT_MSG(!is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object");
107         storage_type& s = const_cast< storage_type& >(storage);
108         scoped_lock lock(&storage);
109         storage_type old_val = s;
110         s = v;
111         return old_val;
112     }
113 
compare_exchange_strongboost::atomics::detail::core_operations_emulated114     static bool compare_exchange_strong(
115         storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT
116     {
117         BOOST_STATIC_ASSERT_MSG(!is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object");
118         storage_type& s = const_cast< storage_type& >(storage);
119         scoped_lock lock(&storage);
120         storage_type old_val = s;
121         const bool res = old_val == expected;
122         if (res)
123             s = desired;
124         expected = old_val;
125 
126         return res;
127     }
128 
compare_exchange_weakboost::atomics::detail::core_operations_emulated129     static bool compare_exchange_weak(
130         storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT
131     {
132         // Note: This function is the exact copy of compare_exchange_strong. The reason we're not just forwarding the call
133         // is that MSVC-12 ICEs in this case.
134         BOOST_STATIC_ASSERT_MSG(!is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object");
135         storage_type& s = const_cast< storage_type& >(storage);
136         scoped_lock lock(&storage);
137         storage_type old_val = s;
138         const bool res = old_val == expected;
139         if (res)
140             s = desired;
141         expected = old_val;
142 
143         return res;
144     }
145 
fetch_andboost::atomics::detail::core_operations_emulated146     static storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
147     {
148         BOOST_STATIC_ASSERT_MSG(!is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object");
149         storage_type& s = const_cast< storage_type& >(storage);
150         scoped_lock lock(&storage);
151         storage_type old_val = s;
152         s &= v;
153         return old_val;
154     }
155 
fetch_orboost::atomics::detail::core_operations_emulated156     static storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
157     {
158         BOOST_STATIC_ASSERT_MSG(!is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object");
159         storage_type& s = const_cast< storage_type& >(storage);
160         scoped_lock lock(&storage);
161         storage_type old_val = s;
162         s |= v;
163         return old_val;
164     }
165 
fetch_xorboost::atomics::detail::core_operations_emulated166     static storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
167     {
168         BOOST_STATIC_ASSERT_MSG(!is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object");
169         storage_type& s = const_cast< storage_type& >(storage);
170         scoped_lock lock(&storage);
171         storage_type old_val = s;
172         s ^= v;
173         return old_val;
174     }
175 
test_and_setboost::atomics::detail::core_operations_emulated176     static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
177     {
178         BOOST_STATIC_ASSERT_MSG(!is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object");
179         return !!exchange(storage, (storage_type)1, order);
180     }
181 
clearboost::atomics::detail::core_operations_emulated182     static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
183     {
184         BOOST_STATIC_ASSERT_MSG(!is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object");
185         store(storage, (storage_type)0, order);
186     }
187 };
188 
189 } // namespace detail
190 } // namespace atomics
191 } // namespace boost
192 
193 #include <boost/atomic/detail/footer.hpp>
194 
195 #endif // BOOST_ATOMIC_DETAIL_CORE_OPERATIONS_EMULATED_HPP_INCLUDED_
196