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) 2009, 2011 Helge Bahmann 7 * Copyright (c) 2009 Phil Endecott 8 * Copyright (c) 2013 Tim Blechmann 9 * Linux-specific code by Phil Endecott 10 * Copyright (c) 2014 Andrey Semashev 11 */ 12 /*! 13 * \file atomic/detail/core_ops_linux_arm.hpp 14 * 15 * This header contains implementation of the \c core_operations template. 16 */ 17 18 #ifndef BOOST_ATOMIC_DETAIL_CORE_OPS_LINUX_ARM_HPP_INCLUDED_ 19 #define BOOST_ATOMIC_DETAIL_CORE_OPS_LINUX_ARM_HPP_INCLUDED_ 20 21 #include <cstddef> 22 #include <boost/memory_order.hpp> 23 #include <boost/atomic/detail/config.hpp> 24 #include <boost/atomic/detail/storage_traits.hpp> 25 #include <boost/atomic/detail/core_operations_fwd.hpp> 26 #include <boost/atomic/detail/core_ops_cas_based.hpp> 27 #include <boost/atomic/detail/cas_based_exchange.hpp> 28 #include <boost/atomic/detail/extending_cas_based_arithmetic.hpp> 29 #include <boost/atomic/detail/fence_operations.hpp> 30 #include <boost/atomic/detail/header.hpp> 31 32 #ifdef BOOST_HAS_PRAGMA_ONCE 33 #pragma once 34 #endif 35 36 namespace boost { 37 namespace atomics { 38 namespace detail { 39 40 // Different ARM processors have different atomic instructions. In particular, 41 // architecture versions before v6 (which are still in widespread use, e.g. the 42 // Intel/Marvell XScale chips like the one in the NSLU2) have only atomic swap. 43 // On Linux the kernel provides some support that lets us abstract away from 44 // these differences: it provides emulated CAS and barrier functions at special 45 // addresses that are guaranteed not to be interrupted by the kernel. Using 46 // this facility is slightly slower than inline assembler would be, but much 47 // faster than a system call. 48 // 49 // https://lwn.net/Articles/314561/ 50 // 51 // While this emulated CAS is "strong" in the sense that it does not fail 52 // "spuriously" (i.e.: it never fails to perform the exchange when the value 53 // found equals the value expected), it does not return the found value on 54 // failure. To satisfy the atomic API, compare_exchange_{weak|strong} must 55 // return the found value on failure, and we have to manually load this value 56 // after the emulated CAS reports failure. This in turn introduces a race 57 // between the CAS failing (due to the "wrong" value being found) and subsequently 58 // loading (which might turn up the "right" value). From an application's 59 // point of view this looks like "spurious failure", and therefore the 60 // emulated CAS is only good enough to provide compare_exchange_weak 61 // semantics. 62 63 struct linux_arm_cas_base 64 { 65 static BOOST_CONSTEXPR_OR_CONST bool full_cas_based = true; 66 static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = true; 67 fence_before_storeboost::atomics::detail::linux_arm_cas_base68 static BOOST_FORCEINLINE void fence_before_store(memory_order order) BOOST_NOEXCEPT 69 { 70 if ((static_cast< unsigned int >(order) & static_cast< unsigned int >(memory_order_release)) != 0u) 71 fence_operations::hardware_full_fence(); 72 } 73 fence_after_storeboost::atomics::detail::linux_arm_cas_base74 static BOOST_FORCEINLINE void fence_after_store(memory_order order) BOOST_NOEXCEPT 75 { 76 if (order == memory_order_seq_cst) 77 fence_operations::hardware_full_fence(); 78 } 79 fence_after_loadboost::atomics::detail::linux_arm_cas_base80 static BOOST_FORCEINLINE void fence_after_load(memory_order order) BOOST_NOEXCEPT 81 { 82 if ((static_cast< unsigned int >(order) & (static_cast< unsigned int >(memory_order_consume) | static_cast< unsigned int >(memory_order_acquire))) != 0u) 83 fence_operations::hardware_full_fence(); 84 } 85 }; 86 87 template< bool Signed, bool Interprocess > 88 struct linux_arm_cas : 89 public linux_arm_cas_base 90 { 91 typedef typename storage_traits< 4u >::type storage_type; 92 93 static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 4u; 94 static BOOST_CONSTEXPR_OR_CONST std::size_t storage_alignment = 4u; 95 static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; 96 static BOOST_CONSTEXPR_OR_CONST bool is_interprocess = Interprocess; 97 storeboost::atomics::detail::linux_arm_cas98 static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT 99 { 100 fence_before_store(order); 101 storage = v; 102 fence_after_store(order); 103 } 104 loadboost::atomics::detail::linux_arm_cas105 static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT 106 { 107 storage_type v = storage; 108 fence_after_load(order); 109 return v; 110 } 111 compare_exchange_strongboost::atomics::detail::linux_arm_cas112 static BOOST_FORCEINLINE bool compare_exchange_strong( 113 storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT 114 { 115 while (true) 116 { 117 storage_type tmp = expected; 118 if (compare_exchange_weak(storage, tmp, desired, success_order, failure_order)) 119 return true; 120 if (tmp != expected) 121 { 122 expected = tmp; 123 return false; 124 } 125 } 126 } 127 compare_exchange_weakboost::atomics::detail::linux_arm_cas128 static BOOST_FORCEINLINE bool compare_exchange_weak( 129 storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT 130 { 131 typedef storage_type (*kernel_cmpxchg32_t)(storage_type oldval, storage_type newval, volatile storage_type* ptr); 132 133 if (((kernel_cmpxchg32_t)0xffff0fc0)(expected, desired, &storage) == 0) 134 { 135 return true; 136 } 137 else 138 { 139 expected = storage; 140 return false; 141 } 142 } 143 }; 144 145 template< bool Signed, bool Interprocess > 146 struct core_operations< 1u, Signed, Interprocess > : 147 public extending_cas_based_arithmetic< core_operations_cas_based< cas_based_exchange< linux_arm_cas< Signed, Interprocess > > >, 1u, Signed > 148 { 149 }; 150 151 template< bool Signed, bool Interprocess > 152 struct core_operations< 2u, Signed, Interprocess > : 153 public extending_cas_based_arithmetic< core_operations_cas_based< cas_based_exchange< linux_arm_cas< Signed, Interprocess > > >, 2u, Signed > 154 { 155 }; 156 157 template< bool Signed, bool Interprocess > 158 struct core_operations< 4u, Signed, Interprocess > : 159 public core_operations_cas_based< cas_based_exchange< linux_arm_cas< Signed, Interprocess > > > 160 { 161 }; 162 163 } // namespace detail 164 } // namespace atomics 165 } // namespace boost 166 167 #include <boost/atomic/detail/footer.hpp> 168 169 #endif // BOOST_ATOMIC_DETAIL_CORE_OPS_LINUX_ARM_HPP_INCLUDED_ 170