core_operations_emulated.hpp 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  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. #ifndef BOOST_ATOMIC_DETAIL_CORE_OPERATIONS_EMULATED_HPP_INCLUDED_
  14. #define BOOST_ATOMIC_DETAIL_CORE_OPERATIONS_EMULATED_HPP_INCLUDED_
  15. #include <cstddef>
  16. #include <boost/memory_order.hpp>
  17. #include <boost/atomic/detail/config.hpp>
  18. #include <boost/atomic/detail/storage_traits.hpp>
  19. #include <boost/atomic/detail/core_operations_emulated_fwd.hpp>
  20. #include <boost/atomic/detail/lock_pool.hpp>
  21. #include <boost/atomic/detail/header.hpp>
  22. #ifdef BOOST_HAS_PRAGMA_ONCE
  23. #pragma once
  24. #endif
  25. namespace boost {
  26. namespace atomics {
  27. namespace detail {
  28. template< std::size_t Size, std::size_t Alignment, bool = Alignment >= storage_traits< Size >::native_alignment >
  29. struct core_operations_emulated_base
  30. {
  31. typedef typename storage_traits< Size >::type storage_type;
  32. };
  33. template< std::size_t Size, std::size_t Alignment >
  34. struct core_operations_emulated_base< Size, Alignment, false >
  35. {
  36. typedef buffer_storage< Size, Alignment > storage_type;
  37. };
  38. //! Emulated implementation of core atomic operations
  39. template< std::size_t Size, std::size_t Alignment, bool Signed, bool Interprocess >
  40. struct core_operations_emulated :
  41. public core_operations_emulated_base< Size, Alignment >
  42. {
  43. typedef core_operations_emulated_base< Size, Alignment > base_type;
  44. // Define storage_type to have alignment not greater than Alignment. This will allow operations to work with value_types
  45. // that possibly have weaker alignment requirements than storage_traits< Size >::type would. This is important for atomic_ref<>.
  46. // atomic<> will allow higher alignment requirement than its value_type.
  47. // Note that storage_type should be an integral type, if possible, so that arithmetic and bitwise operations are possible.
  48. typedef typename base_type::storage_type storage_type;
  49. static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = Size;
  50. static BOOST_CONSTEXPR_OR_CONST std::size_t storage_alignment = Alignment >= storage_traits< Size >::alignment ? storage_traits< Size >::alignment : Alignment;
  51. static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed;
  52. static BOOST_CONSTEXPR_OR_CONST bool is_interprocess = Interprocess;
  53. static BOOST_CONSTEXPR_OR_CONST bool full_cas_based = false;
  54. static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = false;
  55. typedef lock_pool::scoped_lock< storage_alignment > scoped_lock;
  56. static void store(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
  57. {
  58. static_assert(!is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object");
  59. scoped_lock lock(&storage);
  60. const_cast< storage_type& >(storage) = v;
  61. }
  62. static storage_type load(storage_type const volatile& storage, memory_order) BOOST_NOEXCEPT
  63. {
  64. static_assert(!is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object");
  65. scoped_lock lock(&storage);
  66. return const_cast< storage_type const& >(storage);
  67. }
  68. static storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
  69. {
  70. static_assert(!is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object");
  71. storage_type& s = const_cast< storage_type& >(storage);
  72. scoped_lock lock(&storage);
  73. storage_type old_val = s;
  74. s += v;
  75. return old_val;
  76. }
  77. static storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
  78. {
  79. static_assert(!is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object");
  80. storage_type& s = const_cast< storage_type& >(storage);
  81. scoped_lock lock(&storage);
  82. storage_type old_val = s;
  83. s -= v;
  84. return old_val;
  85. }
  86. static storage_type exchange(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
  87. {
  88. static_assert(!is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object");
  89. storage_type& s = const_cast< storage_type& >(storage);
  90. scoped_lock lock(&storage);
  91. storage_type old_val = s;
  92. s = v;
  93. return old_val;
  94. }
  95. static bool compare_exchange_strong(
  96. storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT
  97. {
  98. static_assert(!is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object");
  99. storage_type& s = const_cast< storage_type& >(storage);
  100. scoped_lock lock(&storage);
  101. storage_type old_val = s;
  102. const bool res = old_val == expected;
  103. if (res)
  104. s = desired;
  105. expected = old_val;
  106. return res;
  107. }
  108. static bool compare_exchange_weak(
  109. storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT
  110. {
  111. // Note: This function is the exact copy of compare_exchange_strong. The reason we're not just forwarding the call
  112. // is that MSVC-12 ICEs in this case.
  113. static_assert(!is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object");
  114. storage_type& s = const_cast< storage_type& >(storage);
  115. scoped_lock lock(&storage);
  116. storage_type old_val = s;
  117. const bool res = old_val == expected;
  118. if (res)
  119. s = desired;
  120. expected = old_val;
  121. return res;
  122. }
  123. static storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
  124. {
  125. static_assert(!is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object");
  126. storage_type& s = const_cast< storage_type& >(storage);
  127. scoped_lock lock(&storage);
  128. storage_type old_val = s;
  129. s &= v;
  130. return old_val;
  131. }
  132. static storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
  133. {
  134. static_assert(!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. s |= v;
  139. return old_val;
  140. }
  141. static storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
  142. {
  143. static_assert(!is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object");
  144. storage_type& s = const_cast< storage_type& >(storage);
  145. scoped_lock lock(&storage);
  146. storage_type old_val = s;
  147. s ^= v;
  148. return old_val;
  149. }
  150. static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
  151. {
  152. static_assert(!is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object");
  153. return !!exchange(storage, (storage_type)1, order);
  154. }
  155. static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
  156. {
  157. static_assert(!is_interprocess, "Boost.Atomic: operation invoked on a non-lock-free inter-process atomic object");
  158. store(storage, (storage_type)0, order);
  159. }
  160. };
  161. } // namespace detail
  162. } // namespace atomics
  163. } // namespace boost
  164. #include <boost/atomic/detail/footer.hpp>
  165. #endif // BOOST_ATOMIC_DETAIL_CORE_OPERATIONS_EMULATED_HPP_INCLUDED_