once_atomic.hpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. #ifndef BOOST_THREAD_PTHREAD_ONCE_ATOMIC_HPP
  2. #define BOOST_THREAD_PTHREAD_ONCE_ATOMIC_HPP
  3. // once.hpp
  4. //
  5. // (C) Copyright 2013 Andrey Semashev
  6. // (C) Copyright 2013 Vicente J. Botet Escriba
  7. //
  8. // Distributed under the Boost Software License, Version 1.0. (See
  9. // accompanying file LICENSE_1_0.txt or copy at
  10. // http://www.boost.org/LICENSE_1_0.txt)
  11. #include <boost/thread/detail/config.hpp>
  12. #include <boost/cstdint.hpp>
  13. #include <boost/thread/detail/move.hpp>
  14. #include <boost/thread/detail/invoke.hpp>
  15. #include <boost/core/no_exceptions_support.hpp>
  16. #include <boost/bind/bind.hpp>
  17. #include <boost/atomic.hpp>
  18. #include <boost/config/abi_prefix.hpp>
  19. namespace boost
  20. {
  21. struct once_flag;
  22. namespace thread_detail
  23. {
  24. #if BOOST_ATOMIC_INT_LOCK_FREE == 2
  25. typedef unsigned int atomic_int_type;
  26. #elif BOOST_ATOMIC_SHORT_LOCK_FREE == 2
  27. typedef unsigned short atomic_int_type;
  28. #elif BOOST_ATOMIC_CHAR_LOCK_FREE == 2
  29. typedef unsigned char atomic_int_type;
  30. #elif BOOST_ATOMIC_LONG_LOCK_FREE == 2
  31. typedef unsigned long atomic_int_type;
  32. #elif defined(BOOST_HAS_LONG_LONG) && BOOST_ATOMIC_LLONG_LOCK_FREE == 2
  33. typedef ulong_long_type atomic_int_type;
  34. #else
  35. // All tested integer types are not atomic, the spinlock pool will be used
  36. typedef unsigned int atomic_int_type;
  37. #endif
  38. typedef boost::atomic<atomic_int_type> atomic_type;
  39. BOOST_THREAD_DECL bool enter_once_region(once_flag& flag) BOOST_NOEXCEPT;
  40. BOOST_THREAD_DECL void commit_once_region(once_flag& flag) BOOST_NOEXCEPT;
  41. BOOST_THREAD_DECL void rollback_once_region(once_flag& flag) BOOST_NOEXCEPT;
  42. inline atomic_type& get_atomic_storage(once_flag& flag) BOOST_NOEXCEPT;
  43. }
  44. #ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11
  45. struct once_flag
  46. {
  47. BOOST_THREAD_NO_COPYABLE(once_flag)
  48. BOOST_CONSTEXPR once_flag() BOOST_NOEXCEPT : storage(0)
  49. {
  50. }
  51. private:
  52. thread_detail::atomic_type storage;
  53. friend BOOST_THREAD_DECL bool thread_detail::enter_once_region(once_flag& flag) BOOST_NOEXCEPT;
  54. friend BOOST_THREAD_DECL void thread_detail::commit_once_region(once_flag& flag) BOOST_NOEXCEPT;
  55. friend BOOST_THREAD_DECL void thread_detail::rollback_once_region(once_flag& flag) BOOST_NOEXCEPT;
  56. friend thread_detail::atomic_type& thread_detail::get_atomic_storage(once_flag& flag) BOOST_NOEXCEPT;
  57. };
  58. #define BOOST_ONCE_INIT boost::once_flag()
  59. namespace thread_detail
  60. {
  61. inline atomic_type& get_atomic_storage(once_flag& flag) BOOST_NOEXCEPT
  62. {
  63. //return reinterpret_cast< atomic_type& >(flag.storage);
  64. return flag.storage;
  65. }
  66. }
  67. #else // BOOST_THREAD_PROVIDES_ONCE_CXX11
  68. struct once_flag
  69. {
  70. // The thread_detail::atomic_int_type storage is marked
  71. // with this attribute in order to let the compiler know that it will alias this member
  72. // and silence compilation warnings.
  73. BOOST_THREAD_ATTRIBUTE_MAY_ALIAS thread_detail::atomic_int_type storage;
  74. };
  75. #define BOOST_ONCE_INIT {0}
  76. namespace thread_detail
  77. {
  78. inline atomic_type& get_atomic_storage(once_flag& flag) BOOST_NOEXCEPT
  79. {
  80. return reinterpret_cast< atomic_type& >(flag.storage);
  81. }
  82. }
  83. #endif // BOOST_THREAD_PROVIDES_ONCE_CXX11
  84. #if defined BOOST_THREAD_PROVIDES_INVOKE
  85. #define BOOST_THREAD_INVOKE_RET_VOID detail::invoke
  86. #define BOOST_THREAD_INVOKE_RET_VOID_CALL
  87. #elif defined BOOST_THREAD_PROVIDES_INVOKE_RET
  88. #define BOOST_THREAD_INVOKE_RET_VOID detail::invoke<void>
  89. #define BOOST_THREAD_INVOKE_RET_VOID_CALL
  90. #else
  91. #define BOOST_THREAD_INVOKE_RET_VOID boost::bind
  92. #define BOOST_THREAD_INVOKE_RET_VOID_CALL ()
  93. #endif
  94. #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
  95. template<typename Function, class ...ArgTypes>
  96. inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(ArgTypes)... args)
  97. {
  98. if (thread_detail::enter_once_region(flag))
  99. {
  100. BOOST_TRY
  101. {
  102. BOOST_THREAD_INVOKE_RET_VOID(
  103. thread_detail::decay_copy(boost::forward<Function>(f)),
  104. thread_detail::decay_copy(boost::forward<ArgTypes>(args))...
  105. ) BOOST_THREAD_INVOKE_RET_VOID_CALL;
  106. }
  107. BOOST_CATCH (...)
  108. {
  109. thread_detail::rollback_once_region(flag);
  110. BOOST_RETHROW
  111. }
  112. BOOST_CATCH_END
  113. thread_detail::commit_once_region(flag);
  114. }
  115. }
  116. #else
  117. template<typename Function>
  118. inline void call_once(once_flag& flag, Function f)
  119. {
  120. if (thread_detail::enter_once_region(flag))
  121. {
  122. BOOST_TRY
  123. {
  124. f();
  125. }
  126. BOOST_CATCH (...)
  127. {
  128. thread_detail::rollback_once_region(flag);
  129. BOOST_RETHROW
  130. }
  131. BOOST_CATCH_END
  132. thread_detail::commit_once_region(flag);
  133. }
  134. }
  135. template<typename Function, typename T1>
  136. inline void call_once(once_flag& flag, Function f, T1 p1)
  137. {
  138. if (thread_detail::enter_once_region(flag))
  139. {
  140. BOOST_TRY
  141. {
  142. BOOST_THREAD_INVOKE_RET_VOID(f, p1) BOOST_THREAD_INVOKE_RET_VOID_CALL;
  143. }
  144. BOOST_CATCH (...)
  145. {
  146. thread_detail::rollback_once_region(flag);
  147. BOOST_RETHROW
  148. }
  149. BOOST_CATCH_END
  150. thread_detail::commit_once_region(flag);
  151. }
  152. }
  153. template<typename Function, typename T1, typename T2>
  154. inline void call_once(once_flag& flag, Function f, T1 p1, T2 p2)
  155. {
  156. if (thread_detail::enter_once_region(flag))
  157. {
  158. BOOST_TRY
  159. {
  160. BOOST_THREAD_INVOKE_RET_VOID(f, p1, p2) BOOST_THREAD_INVOKE_RET_VOID_CALL;
  161. }
  162. BOOST_CATCH (...)
  163. {
  164. thread_detail::rollback_once_region(flag);
  165. BOOST_RETHROW
  166. }
  167. BOOST_CATCH_END
  168. thread_detail::commit_once_region(flag);
  169. }
  170. }
  171. template<typename Function, typename T1, typename T2, typename T3>
  172. inline void call_once(once_flag& flag, Function f, T1 p1, T2 p2, T3 p3)
  173. {
  174. if (thread_detail::enter_once_region(flag))
  175. {
  176. BOOST_TRY
  177. {
  178. BOOST_THREAD_INVOKE_RET_VOID(f, p1, p2, p3) BOOST_THREAD_INVOKE_RET_VOID_CALL;
  179. }
  180. BOOST_CATCH (...)
  181. {
  182. thread_detail::rollback_once_region(flag);
  183. BOOST_RETHROW
  184. }
  185. BOOST_CATCH_END
  186. thread_detail::commit_once_region(flag);
  187. }
  188. }
  189. #if !(defined(__SUNPRO_CC) && BOOST_WORKAROUND(__SUNPRO_CC, <= 0x5130))
  190. template<typename Function>
  191. inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f)
  192. {
  193. if (thread_detail::enter_once_region(flag))
  194. {
  195. BOOST_TRY
  196. {
  197. f();
  198. }
  199. BOOST_CATCH (...)
  200. {
  201. thread_detail::rollback_once_region(flag);
  202. BOOST_RETHROW
  203. }
  204. BOOST_CATCH_END
  205. thread_detail::commit_once_region(flag);
  206. }
  207. }
  208. template<typename Function, typename T1>
  209. inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(T1) p1)
  210. {
  211. if (thread_detail::enter_once_region(flag))
  212. {
  213. BOOST_TRY
  214. {
  215. BOOST_THREAD_INVOKE_RET_VOID(
  216. thread_detail::decay_copy(boost::forward<Function>(f)),
  217. thread_detail::decay_copy(boost::forward<T1>(p1))
  218. ) BOOST_THREAD_INVOKE_RET_VOID_CALL;
  219. }
  220. BOOST_CATCH (...)
  221. {
  222. thread_detail::rollback_once_region(flag);
  223. BOOST_RETHROW
  224. }
  225. BOOST_CATCH_END
  226. thread_detail::commit_once_region(flag);
  227. }
  228. }
  229. template<typename Function, typename T1, typename T2>
  230. inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(T1) p1, BOOST_THREAD_RV_REF(T2) p2)
  231. {
  232. if (thread_detail::enter_once_region(flag))
  233. {
  234. BOOST_TRY
  235. {
  236. BOOST_THREAD_INVOKE_RET_VOID(
  237. thread_detail::decay_copy(boost::forward<Function>(f)),
  238. thread_detail::decay_copy(boost::forward<T1>(p1)),
  239. thread_detail::decay_copy(boost::forward<T1>(p2))
  240. ) BOOST_THREAD_INVOKE_RET_VOID_CALL;
  241. }
  242. BOOST_CATCH (...)
  243. {
  244. thread_detail::rollback_once_region(flag);
  245. BOOST_RETHROW
  246. }
  247. BOOST_CATCH_END
  248. thread_detail::commit_once_region(flag);
  249. }
  250. }
  251. template<typename Function, typename T1, typename T2, typename T3>
  252. inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(T1) p1, BOOST_THREAD_RV_REF(T2) p2, BOOST_THREAD_RV_REF(T3) p3)
  253. {
  254. if (thread_detail::enter_once_region(flag))
  255. {
  256. BOOST_TRY
  257. {
  258. BOOST_THREAD_INVOKE_RET_VOID(
  259. thread_detail::decay_copy(boost::forward<Function>(f)),
  260. thread_detail::decay_copy(boost::forward<T1>(p1)),
  261. thread_detail::decay_copy(boost::forward<T1>(p2)),
  262. thread_detail::decay_copy(boost::forward<T1>(p3))
  263. ) BOOST_THREAD_INVOKE_RET_VOID_CALL;
  264. }
  265. BOOST_CATCH (...)
  266. {
  267. thread_detail::rollback_once_region(flag);
  268. BOOST_RETHROW
  269. }
  270. BOOST_CATCH_END
  271. thread_detail::commit_once_region(flag);
  272. }
  273. }
  274. #endif // __SUNPRO_CC
  275. #endif
  276. }
  277. #include <boost/config/abi_suffix.hpp>
  278. #endif