]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/atomic/doc/platform.qbk
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / boost / libs / atomic / doc / platform.qbk
1 [/
2 / Copyright (c) 2009 Helge Bahmann
3 /
4 / Distributed under the Boost Software License, Version 1.0. (See accompanying
5 / file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 /]
7
8 [section:template_organization Organization of class template layers]
9
10 The implementation uses multiple layers of template classes that
11 inherit from the next lower level each and refine or adapt the respective
12 underlying class:
13
14 * [^boost::atomic<T>] is the topmost-level, providing
15 the external interface. Implementation-wise, it does not add anything
16 (except for hiding copy constructor and assignment operator).
17
18 * [^boost::detail::atomic::internal_atomic&<T,S=sizeof(T),I=is_integral_type<T> >]:
19 This layer is mainly responsible for providing the overloaded operators
20 mapping to API member functions (e.g. [^+=] to [^fetch_add]).
21 The defaulted template parameter [^I] allows
22 to expose the correct API functions (via partial template
23 specialization): For non-integral types, it only
24 publishes the various [^exchange] functions
25 as well as load and store, for integral types it
26 additionally exports arithmetic and logic operations.
27 [br]
28 Depending on whether the given type is integral, it
29 inherits from either [^boost::detail::atomic::platform_atomic<T,S=sizeof(T)>]
30 or [^boost::detail::atomic::platform_atomic_integral<T,S=sizeof(T)>].
31 There is however some special-casing: for non-integral types
32 of size 1, 2, 4 or 8, it will coerce the datatype into an integer representation
33 and delegate to [^boost::detail::atomic::platform_atomic_integral<T,S=sizeof(T)>]
34 -- the rationale is that platform implementors only need to provide
35 integer-type operations.
36
37 * [^boost::detail::atomic::platform_atomic_integral<T,S=sizeof(T)>]
38 must provide the full set of operations for an integral type T
39 (i.e. [^load], [^store], [^exchange],
40 [^compare_exchange_weak], [^compare_exchange_strong],
41 [^fetch_add], [^fetch_sub], [^fetch_and],
42 [^fetch_or], [^fetch_xor], [^is_lock_free]).
43 The default implementation uses locking to emulate atomic operations, so
44 this is the level at which implementors should provide template specializations
45 to add support for platform-specific atomic operations.
46 [br]
47 The two separate template parameters allow separate specialization
48 on size and type (which, with fixed size, cannot
49 specify more than signedness/unsignedness). The rationale is that
50 most platform-specific atomic operations usually depend only on the
51 operand size, so that common implementations for signed/unsigned
52 types are possible. Signedness allows to properly to choose sign-extending
53 instructions for the [^load] operation, avoiding later
54 conversion. The expectation is that in most implementations this will
55 be a normal assignment in C, possibly accompanied by memory
56 fences, so that the compiler can automatically choose the correct
57 instruction.
58
59 * At the lowest level, [^boost::detail::atomic::platform_atomic<T,S=sizeof(T)>]
60 provides the most basic atomic operations ([^load], [^store],
61 [^exchange], [^compare_exchange_weak],
62 [^compare_exchange_strong]) for arbitrarily generic data types.
63 The default implementation uses locking as a fallback mechanism.
64 Implementors generally do not have to specialize at this level
65 (since these will not be used for the common integral type sizes
66 of 1, 2, 4 and 8 bytes), but if s/he can if s/he so wishes to
67 provide truly atomic operations for "odd" data type sizes.
68 Some amount of care must be taken as the "raw" data type
69 passed in from the user through [^boost::atomic<T>]
70 is visible here -- it thus needs to be type-punned or otherwise
71 manipulated byte-by-byte to avoid using overloaded assignment,
72 comparison operators and copy constructors.
73
74 [endsect]
75
76
77 [section:platform_atomic_implementation Implementing platform-specific atomic operations]
78
79 In principle implementors are responsible for providing the
80 full range of named member functions of an atomic object
81 (i.e. [^load], [^store], [^exchange],
82 [^compare_exchange_weak], [^compare_exchange_strong],
83 [^fetch_add], [^fetch_sub], [^fetch_and],
84 [^fetch_or], [^fetch_xor], [^is_lock_free]).
85 These must be implemented as partial template specializations for
86 [^boost::detail::atomic::platform_atomic_integral<T,S=sizeof(T)>]:
87
88 [c++]
89
90 template<typename T>
91 class platform_atomic_integral<T, 4>
92 {
93 public:
94 explicit platform_atomic_integral(T v) : i(v) {}
95 platform_atomic_integral(void) {}
96
97 T load(memory_order order=memory_order_seq_cst) const volatile
98 {
99 // platform-specific code
100 }
101 void store(T v, memory_order order=memory_order_seq_cst) volatile
102 {
103 // platform-specific code
104 }
105
106 private:
107 volatile T i;
108 };
109
110 As noted above, it will usually suffice to specialize on the second
111 template argument, indicating the size of the data type in bytes.
112
113 [section:automatic_buildup Templates for automatic build-up]
114
115 Often only a portion of the required operations can be
116 usefully mapped to machine instructions. Several helper template
117 classes are provided that can automatically synthesize missing methods to
118 complete an implementation.
119
120 At the minimum, an implementor must provide the
121 [^load], [^store],
122 [^compare_exchange_weak] and
123 [^is_lock_free] methods:
124
125 [c++]
126
127 template<typename T>
128 class my_atomic_32 {
129 public:
130 my_atomic_32() {}
131 my_atomic_32(T initial_value) : value(initial_value) {}
132
133 T load(memory_order order=memory_order_seq_cst) volatile const
134 {
135 // platform-specific code
136 }
137 void store(T new_value, memory_order order=memory_order_seq_cst) volatile
138 {
139 // platform-specific code
140 }
141 bool compare_exchange_weak(T &expected, T desired,
142 memory_order success_order,
143 memory_order_failure_order) volatile
144 {
145 // platform-specific code
146 }
147 bool is_lock_free() const volatile {return true;}
148 protected:
149 // typedef is required for classes inheriting from this
150 typedef T integral_type;
151 private:
152 T value;
153 };
154
155 The template [^boost::detail::atomic::build_atomic_from_minimal]
156 can then take care of the rest:
157
158 [c++]
159
160 template<typename T>
161 class platform_atomic_integral<T, 4>
162 : public boost::detail::atomic::build_atomic_from_minimal<my_atomic_32<T> >
163 {
164 public:
165 typedef build_atomic_from_minimal<my_atomic_32<T> > super;
166
167 explicit platform_atomic_integral(T v) : super(v) {}
168 platform_atomic_integral(void) {}
169 };
170
171 There are several helper classes to assist in building "complete"
172 atomic implementations from different starting points:
173
174 * [^build_atomic_from_minimal] requires
175 * [^load]
176 * [^store]
177 * [^compare_exchange_weak] (4-operand version)
178
179 * [^build_atomic_from_exchange] requires
180 * [^load]
181 * [^store]
182 * [^compare_exchange_weak] (4-operand version)
183 * [^compare_exchange_strong] (4-operand version)
184 * [^exchange]
185
186 * [^build_atomic_from_add] requires
187 * [^load]
188 * [^store]
189 * [^compare_exchange_weak] (4-operand version)
190 * [^compare_exchange_strong] (4-operand version)
191 * [^exchange]
192 * [^fetch_add]
193
194 * [^build_atomic_from_typical] (<I>supported on gcc only</I>) requires
195 * [^load]
196 * [^store]
197 * [^compare_exchange_weak] (4-operand version)
198 * [^compare_exchange_strong] (4-operand version)
199 * [^exchange]
200 * [^fetch_add_var] (protected method)
201 * [^fetch_inc] (protected method)
202 * [^fetch_dec] (protected method)
203
204 This will generate a [^fetch_add] method
205 that calls [^fetch_inc]/[^fetch_dec]
206 when the given parameter is a compile-time constant
207 equal to +1 or -1 respectively, and [^fetch_add_var]
208 in all other cases. This provides a mechanism for
209 optimizing the extremely common case of an atomic
210 variable being used as a counter.
211
212 The prototypes for these methods to be implemented is:
213 [c++]
214
215 template<typename T>
216 class my_atomic {
217 public:
218 T fetch_inc(memory_order order) volatile;
219 T fetch_dec(memory_order order) volatile;
220 T fetch_add_var(T counter, memory_order order) volatile;
221 };
222
223 These helper templates are defined in [^boost/atomic/detail/builder.hpp].
224
225 [endsect]
226
227 [section:automatic_buildup_small Build sub-word-sized atomic data types]
228
229 There is one other helper template that can build sub-word-sized
230 atomic data types even though the underlying architecture allows
231 only word-sized atomic operations:
232
233 [c++]
234
235 template<typename T>
236 class platform_atomic_integral<T, 1> :
237 public build_atomic_from_larger_type<my_atomic_32<uint32_t>, T>
238 {
239 public:
240 typedef build_atomic_from_larger_type<my_atomic_32<uint32_t>, T> super;
241
242 explicit platform_atomic_integral(T v) : super(v) {}
243 platform_atomic_integral(void) {}
244 };
245
246 The above would create an atomic data type of 1 byte size, and
247 use masking and shifts to map it to 32-bit atomic operations.
248 The base type must implement [^load], [^store]
249 and [^compare_exchange_weak] for this to work.
250
251 [endsect]
252
253 [section:other_sizes Atomic data types for unusual object sizes]
254
255 In unusual circumstances, an implementor may also opt to specialize
256 [^public boost::detail::atomic::platform_atomic<T,S=sizeof(T)>]
257 to provide support for atomic objects not fitting an integral size.
258 If you do that, keep the following things in mind:
259
260 * There is no reason to ever do this for object sizes
261 of 1, 2, 4 and 8
262 * Only the following methods need to be implemented:
263 * [^load]
264 * [^store]
265 * [^compare_exchange_weak] (4-operand version)
266 * [^compare_exchange_strong] (4-operand version)
267 * [^exchange]
268
269 The type of the data to be stored in the atomic
270 variable (template parameter [^T])
271 is exposed to this class, and the type may have
272 overloaded assignment and comparison operators --
273 using these overloaded operators however will result
274 in an error. The implementor is responsible for
275 accessing the objects in a way that does not
276 invoke either of these operators (using e.g.
277 [^memcpy] or type-casts).
278
279 [endsect]
280
281 [endsect]
282
283 [section:platform_atomic_fences Fences]
284
285 Platform implementors need to provide a function performing
286 the action required for [funcref boost::atomic_thread_fence atomic_thread_fence]
287 (the fallback implementation will just perform an atomic operation
288 on an integer object). This is achieved by specializing the
289 [^boost::detail::atomic::platform_atomic_thread_fence] template
290 function in the following way:
291
292 [c++]
293
294 template<>
295 void platform_atomic_thread_fence(memory_order order)
296 {
297 // platform-specific code here
298 }
299
300 [endsect]
301
302 [section:platform_atomic_puttogether Putting it altogether]
303
304 The template specializations should be put into a header file
305 in the [^boost/atomic/detail] directory, preferably
306 specifying supported compiler and architecture in its name.
307
308 The file [^boost/atomic/detail/platform.hpp] must
309 subsequently be modified to conditionally include the new
310 header.
311
312 [endsect]