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