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