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