]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 |