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