platform.qbk 11 KB

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