1 | #ifndef BOOST_THREAD_THREAD_COMMON_HPP |
2 | #define BOOST_THREAD_THREAD_COMMON_HPP |
3 | // Distributed under the Boost Software License, Version 1.0. (See |
4 | // accompanying file LICENSE_1_0.txt or copy at |
5 | // http://www.boost.org/LICENSE_1_0.txt) |
6 | // (C) Copyright 2007-2010 Anthony Williams |
7 | // (C) Copyright 2011-2012 Vicente J. Botet Escriba |
8 | |
9 | #include <boost/thread/detail/config.hpp> |
10 | #include <boost/predef/platform.h> |
11 | |
12 | #include <boost/thread/exceptions.hpp> |
13 | #ifndef BOOST_NO_IOSTREAM |
14 | #include <ostream> |
15 | #endif |
16 | #include <boost/thread/detail/move.hpp> |
17 | #include <boost/thread/mutex.hpp> |
18 | #if defined BOOST_THREAD_USES_DATETIME |
19 | #include <boost/thread/xtime.hpp> |
20 | #endif |
21 | #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS |
22 | #include <boost/thread/interruption.hpp> |
23 | #endif |
24 | #include <boost/thread/detail/thread_heap_alloc.hpp> |
25 | #include <boost/thread/detail/make_tuple_indices.hpp> |
26 | #include <boost/thread/detail/invoke.hpp> |
27 | #include <boost/thread/detail/is_convertible.hpp> |
28 | #include <boost/assert.hpp> |
29 | #include <list> |
30 | #include <algorithm> |
31 | #include <boost/core/ref.hpp> |
32 | #include <boost/cstdint.hpp> |
33 | #include <boost/bind/bind.hpp> |
34 | #include <stdlib.h> |
35 | #include <memory> |
36 | #include <boost/core/enable_if.hpp> |
37 | #include <boost/type_traits/remove_reference.hpp> |
38 | #include <boost/io/ios_state.hpp> |
39 | #include <boost/type_traits/is_same.hpp> |
40 | #include <boost/type_traits/decay.hpp> |
41 | #include <boost/functional/hash.hpp> |
42 | #include <boost/thread/detail/platform_time.hpp> |
43 | #ifdef BOOST_THREAD_USES_CHRONO |
44 | #include <boost/chrono/system_clocks.hpp> |
45 | #include <boost/chrono/ceil.hpp> |
46 | #endif |
47 | |
48 | #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) |
49 | #include <tuple> |
50 | #endif |
51 | #include <boost/config/abi_prefix.hpp> |
52 | |
53 | #ifdef BOOST_MSVC |
54 | #pragma warning(push) |
55 | #pragma warning(disable:4251) |
56 | #endif |
57 | |
58 | namespace boost |
59 | { |
60 | |
61 | namespace detail |
62 | { |
63 | |
64 | #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) |
65 | |
66 | template<typename F, class ...ArgTypes> |
67 | class thread_data: |
68 | public detail::thread_data_base |
69 | { |
70 | public: |
71 | BOOST_THREAD_NO_COPYABLE(thread_data) |
72 | thread_data(BOOST_THREAD_RV_REF(F) f_, BOOST_THREAD_RV_REF(ArgTypes)... args_): |
73 | fp(boost::forward<F>(f_), boost::forward<ArgTypes>(args_)...) |
74 | {} |
75 | template <std::size_t ...Indices> |
76 | void run2(tuple_indices<Indices...>) |
77 | { |
78 | |
79 | detail::invoke(std::move(std::get<0>(fp)), std::move(std::get<Indices>(fp))...); |
80 | } |
81 | void run() |
82 | { |
83 | typedef typename make_tuple_indices<std::tuple_size<std::tuple<F, ArgTypes...> >::value, 1>::type index_type; |
84 | |
85 | run2(index_type()); |
86 | } |
87 | |
88 | private: |
89 | std::tuple<typename decay<F>::type, typename decay<ArgTypes>::type...> fp; |
90 | }; |
91 | #else // defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) |
92 | |
93 | template<typename F> |
94 | class thread_data: |
95 | public detail::thread_data_base |
96 | { |
97 | public: |
98 | BOOST_THREAD_NO_COPYABLE(thread_data) |
99 | #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES |
100 | thread_data(BOOST_THREAD_RV_REF(F) f_): |
101 | f(boost::forward<F>(f_)) |
102 | {} |
103 | // This overloading must be removed if we want the packaged_task's tests to pass. |
104 | // thread_data(F& f_): |
105 | // f(f_) |
106 | // {} |
107 | #else |
108 | |
109 | thread_data(BOOST_THREAD_RV_REF(F) f_): |
110 | f(f_) |
111 | {} |
112 | thread_data(F f_): |
113 | f(f_) |
114 | {} |
115 | #endif |
116 | //thread_data() {} |
117 | |
118 | void run() |
119 | { |
120 | f(); |
121 | } |
122 | |
123 | private: |
124 | F f; |
125 | }; |
126 | |
127 | template<typename F> |
128 | class thread_data<boost::reference_wrapper<F> >: |
129 | public detail::thread_data_base |
130 | { |
131 | private: |
132 | F& f; |
133 | public: |
134 | BOOST_THREAD_NO_COPYABLE(thread_data) |
135 | thread_data(boost::reference_wrapper<F> f_): |
136 | f(f_) |
137 | {} |
138 | void run() |
139 | { |
140 | f(); |
141 | } |
142 | }; |
143 | |
144 | template<typename F> |
145 | class thread_data<const boost::reference_wrapper<F> >: |
146 | public detail::thread_data_base |
147 | { |
148 | private: |
149 | F& f; |
150 | public: |
151 | BOOST_THREAD_NO_COPYABLE(thread_data) |
152 | thread_data(const boost::reference_wrapper<F> f_): |
153 | f(f_) |
154 | {} |
155 | void run() |
156 | { |
157 | f(); |
158 | } |
159 | }; |
160 | #endif |
161 | } |
162 | |
163 | class BOOST_THREAD_DECL thread |
164 | { |
165 | public: |
166 | typedef thread_attributes attributes; |
167 | |
168 | BOOST_THREAD_MOVABLE_ONLY(thread) |
169 | private: |
170 | |
171 | struct dummy; |
172 | |
173 | void release_handle(); |
174 | |
175 | detail::thread_data_ptr thread_info; |
176 | |
177 | private: |
178 | bool start_thread_noexcept(); |
179 | bool start_thread_noexcept(const attributes& attr); |
180 | void start_thread() |
181 | { |
182 | if (!start_thread_noexcept()) |
183 | { |
184 | boost::throw_exception(e: thread_resource_error()); |
185 | } |
186 | } |
187 | void start_thread(const attributes& attr) |
188 | { |
189 | if (!start_thread_noexcept(attr)) |
190 | { |
191 | boost::throw_exception(e: thread_resource_error()); |
192 | } |
193 | } |
194 | |
195 | explicit thread(detail::thread_data_ptr data); |
196 | |
197 | detail::thread_data_ptr get_thread_info BOOST_PREVENT_MACRO_SUBSTITUTION () const; |
198 | |
199 | #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES |
200 | #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) |
201 | template<typename F, class ...ArgTypes> |
202 | static inline detail::thread_data_ptr make_thread_info(BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_RV_REF(ArgTypes)... args) |
203 | { |
204 | return detail::thread_data_ptr(detail::heap_new< |
205 | detail::thread_data<typename boost::remove_reference<F>::type, ArgTypes...> |
206 | >( |
207 | boost::forward<F>(f), boost::forward<ArgTypes>(args)... |
208 | ) |
209 | ); |
210 | } |
211 | #else |
212 | template<typename F> |
213 | static inline detail::thread_data_ptr make_thread_info(BOOST_THREAD_RV_REF(F) f) |
214 | { |
215 | return detail::thread_data_ptr(detail::heap_new<detail::thread_data<typename boost::remove_reference<F>::type> >( |
216 | boost::forward<F>(f))); |
217 | } |
218 | #endif |
219 | static inline detail::thread_data_ptr make_thread_info(void (*f)()) |
220 | { |
221 | return detail::thread_data_ptr(detail::heap_new<detail::thread_data<void(*)()> >( |
222 | a1: boost::forward<void(*)()>(t&: f))); |
223 | } |
224 | #else |
225 | template<typename F> |
226 | static inline detail::thread_data_ptr make_thread_info(F f |
227 | , typename disable_if_c< |
228 | //boost::thread_detail::is_convertible<F&,BOOST_THREAD_RV_REF(F)>::value || |
229 | is_same<typename decay<F>::type, thread>::value, |
230 | dummy* >::type=0 |
231 | ) |
232 | { |
233 | return detail::thread_data_ptr(detail::heap_new<detail::thread_data<F> >(f)); |
234 | } |
235 | template<typename F> |
236 | static inline detail::thread_data_ptr make_thread_info(BOOST_THREAD_RV_REF(F) f) |
237 | { |
238 | return detail::thread_data_ptr(detail::heap_new<detail::thread_data<F> >(f)); |
239 | } |
240 | |
241 | #endif |
242 | public: |
243 | #if 0 // This should not be needed anymore. Use instead BOOST_THREAD_MAKE_RV_REF. |
244 | #if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100) |
245 | thread(const volatile thread&); |
246 | #endif |
247 | #endif |
248 | thread() BOOST_NOEXCEPT; |
249 | ~thread() |
250 | { |
251 | |
252 | #if defined BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE |
253 | if (joinable()) { |
254 | std::terminate(); |
255 | } |
256 | #else |
257 | detach(); |
258 | #endif |
259 | } |
260 | #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES |
261 | template < |
262 | class F |
263 | > |
264 | explicit thread(BOOST_THREAD_RV_REF(F) f |
265 | //, typename disable_if<is_same<typename decay<F>::type, thread>, dummy* >::type=0 |
266 | ): |
267 | thread_info(make_thread_info(thread_detail::decay_copy(boost::forward<F>(f)))) |
268 | { |
269 | start_thread(); |
270 | } |
271 | template < |
272 | class F |
273 | > |
274 | thread(attributes const& attrs, BOOST_THREAD_RV_REF(F) f): |
275 | thread_info(make_thread_info(thread_detail::decay_copy(boost::forward<F>(f)))) |
276 | { |
277 | start_thread(attr: attrs); |
278 | } |
279 | |
280 | #else |
281 | #ifdef BOOST_NO_SFINAE |
282 | template <class F> |
283 | explicit thread(F f): |
284 | thread_info(make_thread_info(f)) |
285 | { |
286 | start_thread(); |
287 | } |
288 | template <class F> |
289 | thread(attributes const& attrs, F f): |
290 | thread_info(make_thread_info(f)) |
291 | { |
292 | start_thread(attrs); |
293 | } |
294 | #else |
295 | template <class F> |
296 | explicit thread(F f |
297 | , typename disable_if_c< |
298 | boost::thread_detail::is_rv<F>::value // todo as a thread_detail::is_rv |
299 | //boost::thread_detail::is_convertible<F&,BOOST_THREAD_RV_REF(F)>::value |
300 | //|| is_same<typename decay<F>::type, thread>::value |
301 | , dummy* >::type=0 |
302 | ): |
303 | thread_info(make_thread_info(f)) |
304 | { |
305 | start_thread(); |
306 | } |
307 | template <class F> |
308 | thread(attributes const& attrs, F f |
309 | , typename disable_if<boost::thread_detail::is_rv<F>, dummy* >::type=0 |
310 | //, typename disable_if<boost::thread_detail::is_convertible<F&,BOOST_THREAD_RV_REF(F) >, dummy* >::type=0 |
311 | ): |
312 | thread_info(make_thread_info(f)) |
313 | { |
314 | start_thread(attrs); |
315 | } |
316 | #endif |
317 | template <class F> |
318 | explicit thread(BOOST_THREAD_RV_REF(F) f |
319 | , typename disable_if<is_same<typename decay<F>::type, thread>, dummy* >::type=0 |
320 | ): |
321 | #ifdef BOOST_THREAD_USES_MOVE |
322 | thread_info(make_thread_info(boost::move<F>(f))) // todo : Add forward |
323 | #else |
324 | thread_info(make_thread_info(f)) // todo : Add forward |
325 | #endif |
326 | { |
327 | start_thread(); |
328 | } |
329 | |
330 | template <class F> |
331 | thread(attributes const& attrs, BOOST_THREAD_RV_REF(F) f): |
332 | #ifdef BOOST_THREAD_USES_MOVE |
333 | thread_info(make_thread_info(boost::move<F>(f))) // todo : Add forward |
334 | #else |
335 | thread_info(make_thread_info(f)) // todo : Add forward |
336 | #endif |
337 | { |
338 | start_thread(attrs); |
339 | } |
340 | #endif |
341 | thread(BOOST_THREAD_RV_REF(thread) x) BOOST_NOEXCEPT |
342 | { |
343 | thread_info=BOOST_THREAD_RV(x).thread_info; |
344 | BOOST_THREAD_RV(x).thread_info.reset(); |
345 | } |
346 | #if 0 // This should not be needed anymore. Use instead BOOST_THREAD_MAKE_RV_REF. |
347 | #if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100) |
348 | thread& operator=(thread x) |
349 | { |
350 | swap(x); |
351 | return *this; |
352 | } |
353 | #endif |
354 | #endif |
355 | |
356 | thread& operator=(BOOST_THREAD_RV_REF(thread) other) BOOST_NOEXCEPT |
357 | { |
358 | |
359 | #if defined BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE |
360 | if (joinable()) std::terminate(); |
361 | #else |
362 | detach(); |
363 | #endif |
364 | thread_info=BOOST_THREAD_RV(other).thread_info; |
365 | BOOST_THREAD_RV(other).thread_info.reset(); |
366 | return *this; |
367 | } |
368 | |
369 | #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) |
370 | template <class F, class Arg, class ...Args> |
371 | thread(F&& f, Arg&& arg, Args&&... args) : |
372 | thread_info(make_thread_info( |
373 | thread_detail::decay_copy(boost::forward<F>(f)), |
374 | thread_detail::decay_copy(boost::forward<Arg>(arg)), |
375 | thread_detail::decay_copy(boost::forward<Args>(args))...) |
376 | ) |
377 | |
378 | { |
379 | start_thread(); |
380 | } |
381 | template <class F, class Arg, class ...Args> |
382 | thread(attributes const& attrs, F&& f, Arg&& arg, Args&&... args) : |
383 | thread_info(make_thread_info( |
384 | thread_detail::decay_copy(boost::forward<F>(f)), |
385 | thread_detail::decay_copy(boost::forward<Arg>(arg)), |
386 | thread_detail::decay_copy(boost::forward<Args>(args))...) |
387 | ) |
388 | |
389 | { |
390 | start_thread(attrs); |
391 | } |
392 | #else |
393 | template <class F,class A1> |
394 | thread(F f,A1 a1,typename disable_if<boost::thread_detail::is_convertible<F&,thread_attributes >, dummy* >::type=0): |
395 | thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1))) |
396 | { |
397 | start_thread(); |
398 | } |
399 | template <class F,class A1,class A2> |
400 | thread(F f,A1 a1,A2 a2): |
401 | thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2))) |
402 | { |
403 | start_thread(); |
404 | } |
405 | |
406 | template <class F,class A1,class A2,class A3> |
407 | thread(F f,A1 a1,A2 a2,A3 a3): |
408 | thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3))) |
409 | { |
410 | start_thread(); |
411 | } |
412 | |
413 | template <class F,class A1,class A2,class A3,class A4> |
414 | thread(F f,A1 a1,A2 a2,A3 a3,A4 a4): |
415 | thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4))) |
416 | { |
417 | start_thread(); |
418 | } |
419 | |
420 | template <class F,class A1,class A2,class A3,class A4,class A5> |
421 | thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5): |
422 | thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5))) |
423 | { |
424 | start_thread(); |
425 | } |
426 | |
427 | template <class F,class A1,class A2,class A3,class A4,class A5,class A6> |
428 | thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6): |
429 | thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5,a6))) |
430 | { |
431 | start_thread(); |
432 | } |
433 | |
434 | template <class F,class A1,class A2,class A3,class A4,class A5,class A6,class A7> |
435 | thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7): |
436 | thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5,a6,a7))) |
437 | { |
438 | start_thread(); |
439 | } |
440 | |
441 | template <class F,class A1,class A2,class A3,class A4,class A5,class A6,class A7,class A8> |
442 | thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7,A8 a8): |
443 | thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5,a6,a7,a8))) |
444 | { |
445 | start_thread(); |
446 | } |
447 | |
448 | template <class F,class A1,class A2,class A3,class A4,class A5,class A6,class A7,class A8,class A9> |
449 | thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7,A8 a8,A9 a9): |
450 | thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5,a6,a7,a8,a9))) |
451 | { |
452 | start_thread(); |
453 | } |
454 | #endif |
455 | void swap(thread& x) BOOST_NOEXCEPT |
456 | { |
457 | thread_info.swap(other&: x.thread_info); |
458 | } |
459 | |
460 | class id; |
461 | id get_id() const BOOST_NOEXCEPT; |
462 | |
463 | bool joinable() const BOOST_NOEXCEPT; |
464 | private: |
465 | bool join_noexcept(); |
466 | bool do_try_join_until_noexcept(detail::internal_platform_timepoint const &timeout, bool& res); |
467 | bool do_try_join_until(detail::internal_platform_timepoint const &timeout); |
468 | public: |
469 | void join(); |
470 | |
471 | #ifdef BOOST_THREAD_USES_CHRONO |
472 | template <class Duration> |
473 | bool try_join_until(const chrono::time_point<detail::internal_chrono_clock, Duration>& t) |
474 | { |
475 | return do_try_join_until(timeout: boost::detail::internal_platform_timepoint(t)); |
476 | } |
477 | |
478 | template <class Clock, class Duration> |
479 | bool try_join_until(const chrono::time_point<Clock, Duration>& t) |
480 | { |
481 | typedef typename common_type<Duration, typename Clock::duration>::type common_duration; |
482 | common_duration d(t - Clock::now()); |
483 | d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS))); |
484 | while ( ! try_join_until(detail::internal_chrono_clock::now() + d) ) |
485 | { |
486 | d = t - Clock::now(); |
487 | if ( d <= common_duration::zero() ) return false; // timeout occurred |
488 | d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS))); |
489 | } |
490 | return true; |
491 | } |
492 | |
493 | template <class Rep, class Period> |
494 | bool try_join_for(const chrono::duration<Rep, Period>& rel_time) |
495 | { |
496 | return try_join_until(chrono::steady_clock::now() + rel_time); |
497 | } |
498 | #endif |
499 | #if defined BOOST_THREAD_USES_DATETIME |
500 | bool timed_join(const system_time& abs_time) |
501 | { |
502 | const detail::real_platform_timepoint ts(abs_time); |
503 | #if defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO |
504 | detail::platform_duration d(ts - detail::real_platform_clock::now()); |
505 | d = (std::min)(a: d, b: detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); |
506 | while ( ! do_try_join_until(timeout: detail::internal_platform_clock::now() + d) ) |
507 | { |
508 | d = ts - detail::real_platform_clock::now(); |
509 | if ( d <= detail::platform_duration::zero() ) return false; // timeout occurred |
510 | d = (std::min)(a: d, b: detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); |
511 | } |
512 | return true; |
513 | #else |
514 | return do_try_join_until(ts); |
515 | #endif |
516 | } |
517 | |
518 | template<typename TimeDuration> |
519 | bool timed_join(TimeDuration const& rel_time) |
520 | { |
521 | detail::platform_duration d(rel_time); |
522 | #if defined(BOOST_THREAD_HAS_MONO_CLOCK) && !defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO) |
523 | const detail::mono_platform_timepoint ts(detail::mono_platform_clock::now() + d); |
524 | d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); |
525 | while ( ! do_try_join_until(detail::internal_platform_clock::now() + d) ) |
526 | { |
527 | d = ts - detail::mono_platform_clock::now(); |
528 | if ( d <= detail::platform_duration::zero() ) return false; // timeout occurred |
529 | d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); |
530 | } |
531 | return true; |
532 | #else |
533 | return do_try_join_until(timeout: detail::internal_platform_clock::now() + d); |
534 | #endif |
535 | } |
536 | #endif |
537 | void detach(); |
538 | |
539 | static unsigned hardware_concurrency() BOOST_NOEXCEPT; |
540 | static unsigned physical_concurrency() BOOST_NOEXCEPT; |
541 | |
542 | #define BOOST_THREAD_DEFINES_THREAD_NATIVE_HANDLE |
543 | typedef detail::thread_data_base::native_handle_type native_handle_type; |
544 | native_handle_type native_handle(); |
545 | |
546 | #if defined BOOST_THREAD_PROVIDES_THREAD_EQ |
547 | // Use thread::id when comparisions are needed |
548 | // backwards compatibility |
549 | bool operator==(const thread& other) const; |
550 | bool operator!=(const thread& other) const; |
551 | #endif |
552 | #if defined BOOST_THREAD_USES_DATETIME |
553 | static inline void yield() BOOST_NOEXCEPT |
554 | { |
555 | this_thread::yield(); |
556 | } |
557 | |
558 | static inline void sleep(const system_time& xt) |
559 | { |
560 | this_thread::sleep(abs_time: xt); |
561 | } |
562 | #endif |
563 | |
564 | #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS |
565 | // extensions |
566 | void interrupt(); |
567 | bool interruption_requested() const BOOST_NOEXCEPT; |
568 | #endif |
569 | }; |
570 | |
571 | inline void swap(thread& lhs,thread& rhs) BOOST_NOEXCEPT |
572 | { |
573 | return lhs.swap(x&: rhs); |
574 | } |
575 | |
576 | #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES |
577 | inline thread&& move(thread& t) BOOST_NOEXCEPT |
578 | { |
579 | return static_cast<thread&&>(t); |
580 | } |
581 | #endif |
582 | |
583 | BOOST_THREAD_DCL_MOVABLE(thread) |
584 | |
585 | namespace this_thread |
586 | { |
587 | #ifdef BOOST_THREAD_PLATFORM_PTHREAD |
588 | thread::id get_id() BOOST_NOEXCEPT; |
589 | #else |
590 | thread::id BOOST_THREAD_DECL get_id() BOOST_NOEXCEPT; |
591 | #endif |
592 | |
593 | #if defined BOOST_THREAD_USES_DATETIME |
594 | inline BOOST_SYMBOL_VISIBLE void sleep(::boost::xtime const& abs_time) |
595 | { |
596 | sleep(abs_time: system_time(abs_time)); |
597 | } |
598 | #endif |
599 | } |
600 | |
601 | class BOOST_SYMBOL_VISIBLE thread::id |
602 | { |
603 | private: |
604 | |
605 | #if !defined(BOOST_EMBTC) |
606 | |
607 | friend inline |
608 | std::size_t |
609 | hash_value(const thread::id &v) |
610 | { |
611 | #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID |
612 | return hash_value(v: v.thread_data); |
613 | #else |
614 | return hash_value(v.thread_data.get()); |
615 | #endif |
616 | } |
617 | |
618 | #else |
619 | |
620 | friend |
621 | std::size_t |
622 | hash_value(const thread::id &v); |
623 | |
624 | #endif |
625 | |
626 | #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID |
627 | #if defined(BOOST_THREAD_PLATFORM_WIN32) |
628 | typedef unsigned int data; |
629 | #else |
630 | typedef thread::native_handle_type data; |
631 | #endif |
632 | #else |
633 | typedef detail::thread_data_ptr data; |
634 | #endif |
635 | data thread_data; |
636 | |
637 | id(data thread_data_): |
638 | thread_data(thread_data_) |
639 | {} |
640 | friend class thread; |
641 | friend id BOOST_THREAD_DECL this_thread::get_id() BOOST_NOEXCEPT; |
642 | public: |
643 | id() BOOST_NOEXCEPT: |
644 | #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID |
645 | thread_data(0) |
646 | #else |
647 | thread_data() |
648 | #endif |
649 | {} |
650 | |
651 | bool operator==(const id& y) const BOOST_NOEXCEPT |
652 | { |
653 | return thread_data==y.thread_data; |
654 | } |
655 | |
656 | bool operator!=(const id& y) const BOOST_NOEXCEPT |
657 | { |
658 | return thread_data!=y.thread_data; |
659 | } |
660 | |
661 | bool operator<(const id& y) const BOOST_NOEXCEPT |
662 | { |
663 | return thread_data<y.thread_data; |
664 | } |
665 | |
666 | bool operator>(const id& y) const BOOST_NOEXCEPT |
667 | { |
668 | return y.thread_data<thread_data; |
669 | } |
670 | |
671 | bool operator<=(const id& y) const BOOST_NOEXCEPT |
672 | { |
673 | return !(y.thread_data<thread_data); |
674 | } |
675 | |
676 | bool operator>=(const id& y) const BOOST_NOEXCEPT |
677 | { |
678 | return !(thread_data<y.thread_data); |
679 | } |
680 | |
681 | #ifndef BOOST_NO_IOSTREAM |
682 | #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS |
683 | template<class charT, class traits> |
684 | friend BOOST_SYMBOL_VISIBLE |
685 | std::basic_ostream<charT, traits>& |
686 | operator<<(std::basic_ostream<charT, traits>& os, const id& x) |
687 | { |
688 | if(x.thread_data) |
689 | { |
690 | io::ios_flags_saver ifs( os ); |
691 | return os<< std::hex << x.thread_data; |
692 | } |
693 | else |
694 | { |
695 | return os<<"{Not-any-thread}" ; |
696 | } |
697 | } |
698 | #else |
699 | template<class charT, class traits> |
700 | BOOST_SYMBOL_VISIBLE |
701 | std::basic_ostream<charT, traits>& |
702 | print(std::basic_ostream<charT, traits>& os) const |
703 | { |
704 | if(thread_data) |
705 | { |
706 | io::ios_flags_saver ifs( os ); |
707 | return os<< std::hex << thread_data; |
708 | } |
709 | else |
710 | { |
711 | return os<<"{Not-any-thread}" ; |
712 | } |
713 | } |
714 | |
715 | #endif |
716 | #endif |
717 | }; |
718 | |
719 | #if defined(BOOST_EMBTC) |
720 | |
721 | inline |
722 | std::size_t |
723 | hash_value(const thread::id &v) |
724 | { |
725 | #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID |
726 | return hash_value(v.thread_data); |
727 | #else |
728 | return hash_value(v.thread_data.get()); |
729 | #endif |
730 | } |
731 | |
732 | #endif |
733 | |
734 | #ifdef BOOST_THREAD_PLATFORM_PTHREAD |
735 | inline thread::id thread::get_id() const BOOST_NOEXCEPT |
736 | { |
737 | #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID |
738 | return const_cast<thread*>(this)->native_handle(); |
739 | #else |
740 | detail::thread_data_ptr const local_thread_info=(get_thread_info)(); |
741 | return (local_thread_info? id(local_thread_info) : id()); |
742 | #endif |
743 | } |
744 | |
745 | namespace this_thread |
746 | { |
747 | inline thread::id get_id() BOOST_NOEXCEPT |
748 | { |
749 | #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID |
750 | return pthread_self(); |
751 | #else |
752 | boost::detail::thread_data_base* const thread_info=get_or_make_current_thread_data(); |
753 | return (thread_info?thread::id(thread_info->shared_from_this()):thread::id()); |
754 | #endif |
755 | } |
756 | } |
757 | #endif |
758 | inline void thread::join() { |
759 | if (this_thread::get_id() == get_id()) |
760 | boost::throw_exception(e: thread_resource_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost thread: trying joining itself" )); |
761 | |
762 | BOOST_THREAD_VERIFY_PRECONDITION( join_noexcept(), |
763 | thread_resource_error(static_cast<int>(system::errc::invalid_argument), "boost thread: thread not joinable" ) |
764 | ); |
765 | } |
766 | |
767 | inline bool thread::do_try_join_until(detail::internal_platform_timepoint const &timeout) |
768 | { |
769 | if (this_thread::get_id() == get_id()) |
770 | boost::throw_exception(e: thread_resource_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost thread: trying joining itself" )); |
771 | bool res; |
772 | if (do_try_join_until_noexcept(timeout, res)) |
773 | { |
774 | return res; |
775 | } |
776 | else |
777 | { |
778 | BOOST_THREAD_THROW_ELSE_RETURN( |
779 | (thread_resource_error(static_cast<int>(system::errc::invalid_argument), "boost thread: thread not joinable" )), |
780 | false |
781 | ); |
782 | } |
783 | } |
784 | |
785 | #if !defined(BOOST_NO_IOSTREAM) && defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) |
786 | template<class charT, class traits> |
787 | BOOST_SYMBOL_VISIBLE |
788 | std::basic_ostream<charT, traits>& |
789 | operator<<(std::basic_ostream<charT, traits>& os, const thread::id& x) |
790 | { |
791 | return x.print(os); |
792 | } |
793 | #endif |
794 | |
795 | #if defined BOOST_THREAD_PROVIDES_THREAD_EQ |
796 | inline bool thread::operator==(const thread& other) const |
797 | { |
798 | return get_id()==other.get_id(); |
799 | } |
800 | |
801 | inline bool thread::operator!=(const thread& other) const |
802 | { |
803 | return get_id()!=other.get_id(); |
804 | } |
805 | #endif |
806 | |
807 | namespace detail |
808 | { |
809 | struct thread_exit_function_base |
810 | { |
811 | virtual ~thread_exit_function_base() |
812 | {} |
813 | virtual void operator()()=0; |
814 | }; |
815 | |
816 | template<typename F> |
817 | struct thread_exit_function: |
818 | thread_exit_function_base |
819 | { |
820 | F f; |
821 | |
822 | thread_exit_function(F f_): |
823 | f(f_) |
824 | {} |
825 | |
826 | void operator()() |
827 | { |
828 | f(); |
829 | } |
830 | }; |
831 | |
832 | void BOOST_THREAD_DECL add_thread_exit_function(thread_exit_function_base*); |
833 | //#ifndef BOOST_NO_EXCEPTIONS |
834 | struct shared_state_base; |
835 | #if defined(BOOST_THREAD_PLATFORM_WIN32) |
836 | inline void make_ready_at_thread_exit(shared_ptr<shared_state_base> as) |
837 | { |
838 | detail::thread_data_base* const current_thread_data(detail::get_current_thread_data()); |
839 | if(current_thread_data) |
840 | { |
841 | current_thread_data->make_ready_at_thread_exit(as); |
842 | } |
843 | } |
844 | #else |
845 | void BOOST_THREAD_DECL make_ready_at_thread_exit(shared_ptr<shared_state_base> as); |
846 | #endif |
847 | //#endif |
848 | } |
849 | |
850 | namespace this_thread |
851 | { |
852 | template<typename F> |
853 | void at_thread_exit(F f) |
854 | { |
855 | detail::thread_exit_function_base* const thread_exit_func=detail::heap_new<detail::thread_exit_function<F> >(f); |
856 | detail::add_thread_exit_function(thread_exit_func); |
857 | } |
858 | } |
859 | } |
860 | |
861 | #ifdef BOOST_MSVC |
862 | #pragma warning(pop) |
863 | #endif |
864 | |
865 | #include <boost/config/abi_suffix.hpp> |
866 | |
867 | #endif |
868 | |