1 // Copyright (C) 2001-2003
3 // Copyright (C) 2007-8 Anthony Williams
4 // (C) Copyright 2011-2012 Vicente J. Botet Escriba
6 // Distributed under the Boost Software License, Version 1.0. (See accompanying
7 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 #include <boost/thread/detail/config.hpp>
11 #include <boost/thread/thread_only.hpp>
12 #if defined BOOST_THREAD_USES_DATETIME
13 #include <boost/thread/xtime.hpp>
15 #include <boost/thread/condition_variable.hpp>
16 #include <boost/thread/locks.hpp>
17 #include <boost/thread/once.hpp>
18 #include <boost/thread/tss.hpp>
19 #include <boost/thread/future.hpp>
22 #include <sys/sysinfo.h>
23 #elif defined(__APPLE__) || defined(__FreeBSD__)
24 #include <sys/types.h>
25 #include <sys/sysctl.h>
26 #elif defined BOOST_HAS_UNISTD_H
30 #include <boost/algorithm/string/split.hpp>
31 #include <boost/algorithm/string/trim.hpp>
32 #include <boost/lexical_cast.hpp>
38 #include <string.h> // memcmp.
44 thread_data_base::~thread_data_base()
46 for (notify_list_t::iterator i
= notify
.begin(), e
= notify
.end();
50 i
->first
->notify_all();
52 for (async_states_t::iterator i
= async_states_
.begin(), e
= async_states_
.end();
55 (*i
)->notify_deferred();
59 struct thread_exit_callback_node
61 boost::detail::thread_exit_function_base
* func
;
62 thread_exit_callback_node
* next
;
64 thread_exit_callback_node(boost::detail::thread_exit_function_base
* func_
,
65 thread_exit_callback_node
* next_
):
66 func(func_
),next(next_
)
72 #ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11
73 boost::once_flag current_thread_tls_init_flag
;
75 boost::once_flag current_thread_tls_init_flag
=BOOST_ONCE_INIT
;
77 pthread_key_t current_thread_tls_key
;
81 static void tls_destructor(void* data
)
83 //boost::detail::thread_data_base* thread_info=static_cast<boost::detail::thread_data_base*>(data);
84 boost::detail::thread_data_ptr thread_info
= static_cast<boost::detail::thread_data_base
*>(data
)->shared_from_this();
88 while(!thread_info
->tss_data
.empty() || thread_info
->thread_exit_callbacks
)
91 while(thread_info
->thread_exit_callbacks
)
93 detail::thread_exit_callback_node
* const current_node
=thread_info
->thread_exit_callbacks
;
94 thread_info
->thread_exit_callbacks
=current_node
->next
;
95 if(current_node
->func
)
97 (*current_node
->func
)();
98 delete current_node
->func
;
102 while (!thread_info
->tss_data
.empty())
104 std::map
<void const*,detail::tss_data_node
>::iterator current
105 = thread_info
->tss_data
.begin();
106 if(current
->second
.func
&& (current
->second
.value
!=0))
108 (*current
->second
.func
)(current
->second
.value
);
110 thread_info
->tss_data
.erase(current
);
113 thread_info
->self
.reset();
118 #if defined BOOST_THREAD_PATCH
119 struct delete_current_thread_tls_key_on_dlclose_t
121 delete_current_thread_tls_key_on_dlclose_t()
124 ~delete_current_thread_tls_key_on_dlclose_t()
126 const boost::once_flag uninitialized
= BOOST_ONCE_INIT
;
127 if (memcmp(¤t_thread_tls_init_flag
, &uninitialized
, sizeof(boost::once_flag
)))
129 void* data
= pthread_getspecific(current_thread_tls_key
);
131 tls_destructor(data
);
132 pthread_key_delete(current_thread_tls_key
);
136 delete_current_thread_tls_key_on_dlclose_t delete_current_thread_tls_key_on_dlclose
;
138 void create_current_thread_tls_key()
140 BOOST_VERIFY(!pthread_key_create(¤t_thread_tls_key
,&tls_destructor
));
144 boost::detail::thread_data_base
* get_current_thread_data()
146 boost::call_once(current_thread_tls_init_flag
,create_current_thread_tls_key
);
147 return (boost::detail::thread_data_base
*)pthread_getspecific(current_thread_tls_key
);
150 void set_current_thread_data(detail::thread_data_base
* new_data
)
152 boost::call_once(current_thread_tls_init_flag
,create_current_thread_tls_key
);
153 BOOST_VERIFY(!pthread_setspecific(current_thread_tls_key
,new_data
));
161 static void* thread_proxy(void* param
)
163 //boost::detail::thread_data_ptr thread_info = static_cast<boost::detail::thread_data_base*>(param)->self;
164 boost::detail::thread_data_ptr thread_info
= static_cast<boost::detail::thread_data_base
*>(param
)->shared_from_this();
165 thread_info
->self
.reset();
166 detail::set_current_thread_data(thread_info
.get());
167 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
172 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
175 BOOST_CATCH (thread_interrupted
const&)
178 // Removed as it stops the debugger identifying the cause of the exception
179 // Unhandled exceptions still cause the application to terminate
188 detail::tls_destructor(thread_info
.get());
189 detail::set_current_thread_data(0);
190 boost::lock_guard
<boost::mutex
> lock(thread_info
->data_mutex
);
191 thread_info
->done
=true;
192 thread_info
->done_condition
.notify_all();
200 struct externally_launched_thread
:
201 detail::thread_data_base
203 externally_launched_thread()
205 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
206 interrupt_enabled
=false;
209 ~externally_launched_thread() {
210 BOOST_ASSERT(notify
.empty());
212 BOOST_ASSERT(async_states_
.empty());
213 async_states_
.clear();
217 void notify_all_at_thread_exit(condition_variable
*, mutex
*)
221 externally_launched_thread(externally_launched_thread
&);
222 void operator=(externally_launched_thread
&);
225 thread_data_base
* make_external_thread_data()
227 thread_data_base
* const me(detail::heap_new
<externally_launched_thread
>());
229 set_current_thread_data(me
);
234 thread_data_base
* get_or_make_current_thread_data()
236 thread_data_base
* current_thread_data(get_current_thread_data());
237 if(!current_thread_data
)
239 current_thread_data
=make_external_thread_data();
241 return current_thread_data
;
247 thread::thread() BOOST_NOEXCEPT
250 bool thread::start_thread_noexcept()
252 thread_info
->self
=thread_info
;
253 int const res
= pthread_create(&thread_info
->thread_handle
, 0, &thread_proxy
, thread_info
.get());
256 thread_info
->self
.reset();
262 bool thread::start_thread_noexcept(const attributes
& attr
)
264 thread_info
->self
=thread_info
;
265 const attributes::native_handle_type
* h
= attr
.native_handle();
266 int res
= pthread_create(&thread_info
->thread_handle
, h
, &thread_proxy
, thread_info
.get());
269 thread_info
->self
.reset();
273 res
= pthread_attr_getdetachstate(h
, &detached_state
);
276 thread_info
->self
.reset();
279 if (PTHREAD_CREATE_DETACHED
==detached_state
)
281 detail::thread_data_ptr local_thread_info
;
282 thread_info
.swap(local_thread_info
);
284 if(local_thread_info
)
286 //lock_guard<mutex> lock(local_thread_info->data_mutex);
287 if(!local_thread_info
->join_started
)
289 //BOOST_VERIFY(!pthread_detach(local_thread_info->thread_handle));
290 local_thread_info
->join_started
=true;
291 local_thread_info
->joined
=true;
300 detail::thread_data_ptr
thread::get_thread_info
BOOST_PREVENT_MACRO_SUBSTITUTION () const
305 bool thread::join_noexcept()
307 detail::thread_data_ptr
const local_thread_info
=(get_thread_info
)();
308 if(local_thread_info
)
313 unique_lock
<mutex
> lock(local_thread_info
->data_mutex
);
314 while(!local_thread_info
->done
)
316 local_thread_info
->done_condition
.wait(lock
);
318 do_join
=!local_thread_info
->join_started
;
322 local_thread_info
->join_started
=true;
326 while(!local_thread_info
->joined
)
328 local_thread_info
->done_condition
.wait(lock
);
335 BOOST_VERIFY(!pthread_join(local_thread_info
->thread_handle
,&result
));
336 lock_guard
<mutex
> lock(local_thread_info
->data_mutex
);
337 local_thread_info
->joined
=true;
338 local_thread_info
->done_condition
.notify_all();
341 if(thread_info
==local_thread_info
)
353 bool thread::do_try_join_until_noexcept(struct timespec
const &timeout
, bool& res
)
355 detail::thread_data_ptr
const local_thread_info
=(get_thread_info
)();
356 if(local_thread_info
)
361 unique_lock
<mutex
> lock(local_thread_info
->data_mutex
);
362 while(!local_thread_info
->done
)
364 if(!local_thread_info
->done_condition
.do_wait_until(lock
,timeout
))
370 do_join
=!local_thread_info
->join_started
;
374 local_thread_info
->join_started
=true;
378 while(!local_thread_info
->joined
)
380 local_thread_info
->done_condition
.wait(lock
);
387 BOOST_VERIFY(!pthread_join(local_thread_info
->thread_handle
,&result
));
388 lock_guard
<mutex
> lock(local_thread_info
->data_mutex
);
389 local_thread_info
->joined
=true;
390 local_thread_info
->done_condition
.notify_all();
393 if(thread_info
==local_thread_info
)
406 bool thread::joinable() const BOOST_NOEXCEPT
408 return (get_thread_info
)()?true:false;
412 void thread::detach()
414 detail::thread_data_ptr local_thread_info
;
415 thread_info
.swap(local_thread_info
);
417 if(local_thread_info
)
419 lock_guard
<mutex
> lock(local_thread_info
->data_mutex
);
420 if(!local_thread_info
->join_started
)
422 BOOST_VERIFY(!pthread_detach(local_thread_info
->thread_handle
));
423 local_thread_info
->join_started
=true;
424 local_thread_info
->joined
=true;
429 namespace this_thread
431 namespace no_interruption_point
435 void BOOST_THREAD_DECL
sleep_for(const timespec
& ts
)
438 if (boost::detail::timespec_ge(ts
, boost::detail::timespec_zero()))
441 # if defined(BOOST_HAS_PTHREAD_DELAY_NP)
442 # if defined(__IBMCPP__) || defined(_AIX)
443 BOOST_VERIFY(!pthread_delay_np(const_cast<timespec
*>(&ts
)));
445 BOOST_VERIFY(!pthread_delay_np(&ts
));
447 # elif defined(BOOST_HAS_NANOSLEEP)
448 // nanosleep takes a timespec that is an offset, not
453 unique_lock
<mutex
> lock(mx
);
454 condition_variable cond
;
455 cond
.do_wait_for(lock
, ts
);
460 void BOOST_THREAD_DECL
sleep_until_realtime(const timespec
& ts
)
462 timespec now
= boost::detail::timespec_now_realtime();
463 if (boost::detail::timespec_gt(ts
, now
))
465 for (int foo
=0; foo
< 5; ++foo
)
468 # if defined(BOOST_HAS_PTHREAD_DELAY_NP)
469 timespec d
= boost::detail::timespec_minus(ts
, now
);
470 BOOST_VERIFY(!pthread_delay_np(&d
));
471 # elif defined(BOOST_HAS_NANOSLEEP)
472 // nanosleep takes a timespec that is an offset, not
474 timespec d
= boost::detail::timespec_minus(ts
, now
);
478 unique_lock
<mutex
> lock(mx
);
479 condition_variable cond
;
480 cond
.do_wait_until(lock
, ts
);
482 timespec now2
= boost::detail::timespec_now_realtime();
483 if (boost::detail::timespec_ge(now2
, ts
))
494 void BOOST_THREAD_DECL
sleep_for(const timespec
& ts
)
496 boost::detail::thread_data_base
* const thread_info
=boost::detail::get_current_thread_data();
500 unique_lock
<mutex
> lk(thread_info
->sleep_mutex
);
501 while( thread_info
->sleep_condition
.do_wait_for(lk
,ts
)) {}
505 boost::this_thread::no_interruption_point::hidden::sleep_for(ts
);
509 void BOOST_THREAD_DECL
sleep_until_realtime(const timespec
& ts
)
511 boost::detail::thread_data_base
* const thread_info
=boost::detail::get_current_thread_data();
515 unique_lock
<mutex
> lk(thread_info
->sleep_mutex
);
516 while(thread_info
->sleep_condition
.do_wait_until(lk
,ts
)) {}
520 boost::this_thread::no_interruption_point::hidden::sleep_until_realtime(ts
);
526 namespace this_thread
528 void yield() BOOST_NOEXCEPT
530 # if defined(BOOST_HAS_SCHED_YIELD)
531 BOOST_VERIFY(!sched_yield());
532 # elif defined(BOOST_HAS_PTHREAD_YIELD)
533 BOOST_VERIFY(!pthread_yield());
534 //# elif defined BOOST_THREAD_USES_DATETIME
536 // xtime_get(&xt, TIME_UTC_);
538 // sleep_for(chrono::milliseconds(0));
544 hidden::sleep_for(ts
);
548 unsigned thread::hardware_concurrency() BOOST_NOEXCEPT
550 #if defined(PTW32_VERSION) || defined(__hpux)
551 return pthread_num_processors_np();
552 #elif defined(__APPLE__) || defined(__FreeBSD__)
554 size_t size
=sizeof(count
);
555 return sysctlbyname("hw.ncpu",&count
,&size
,NULL
,0)?0:count
;
556 #elif defined(BOOST_HAS_UNISTD_H) && defined(_SC_NPROCESSORS_ONLN)
557 int const count
=sysconf(_SC_NPROCESSORS_ONLN
);
558 return (count
>0)?count
:0;
559 #elif defined(__GLIBC__)
566 unsigned thread::physical_concurrency() BOOST_NOEXCEPT
572 ifstream
proc_cpuinfo ("/proc/cpuinfo");
574 const string
physical_id("physical id"), core_id("core id");
576 typedef std::pair
<unsigned, unsigned> core_entry
; // [physical ID, core id]
578 std::set
<core_entry
> cores
;
580 core_entry current_core_entry
;
583 while ( getline(proc_cpuinfo
, line
) ) {
587 vector
<string
> key_val(2);
588 boost::split(key_val
, line
, boost::is_any_of(":"));
590 if (key_val
.size() != 2)
591 return hardware_concurrency();
593 string key
= key_val
[0];
594 string value
= key_val
[1];
598 if (key
== physical_id
) {
599 current_core_entry
.first
= boost::lexical_cast
<unsigned>(value
);
603 if (key
== core_id
) {
604 current_core_entry
.second
= boost::lexical_cast
<unsigned>(value
);
605 cores
.insert(current_core_entry
);
609 // Fall back to hardware_concurrency() in case
610 // /proc/cpuinfo is formatted differently than we expect.
611 return cores
.size() != 0 ? cores
.size() : hardware_concurrency();
613 return hardware_concurrency();
615 #elif defined(__APPLE__)
617 size_t size
=sizeof(count
);
618 return sysctlbyname("hw.physicalcpu",&count
,&size
,NULL
,0)?0:count
;
620 return hardware_concurrency();
624 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
625 void thread::interrupt()
627 detail::thread_data_ptr
const local_thread_info
=(get_thread_info
)();
628 if(local_thread_info
)
630 lock_guard
<mutex
> lk(local_thread_info
->data_mutex
);
631 local_thread_info
->interrupt_requested
=true;
632 if(local_thread_info
->current_cond
)
634 boost::pthread::pthread_mutex_scoped_lock
internal_lock(local_thread_info
->cond_mutex
);
635 BOOST_VERIFY(!pthread_cond_broadcast(local_thread_info
->current_cond
));
640 bool thread::interruption_requested() const BOOST_NOEXCEPT
642 detail::thread_data_ptr
const local_thread_info
=(get_thread_info
)();
643 if(local_thread_info
)
645 lock_guard
<mutex
> lk(local_thread_info
->data_mutex
);
646 return local_thread_info
->interrupt_requested
;
655 thread::native_handle_type
thread::native_handle()
657 detail::thread_data_ptr
const local_thread_info
=(get_thread_info
)();
658 if(local_thread_info
)
660 lock_guard
<mutex
> lk(local_thread_info
->data_mutex
);
661 return local_thread_info
->thread_handle
;
671 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
672 namespace this_thread
674 void interruption_point()
676 #ifndef BOOST_NO_EXCEPTIONS
677 boost::detail::thread_data_base
* const thread_info
=detail::get_current_thread_data();
678 if(thread_info
&& thread_info
->interrupt_enabled
)
680 lock_guard
<mutex
> lg(thread_info
->data_mutex
);
681 if(thread_info
->interrupt_requested
)
683 thread_info
->interrupt_requested
=false;
684 throw thread_interrupted();
690 bool interruption_enabled() BOOST_NOEXCEPT
692 boost::detail::thread_data_base
* const thread_info
=detail::get_current_thread_data();
693 return thread_info
&& thread_info
->interrupt_enabled
;
696 bool interruption_requested() BOOST_NOEXCEPT
698 boost::detail::thread_data_base
* const thread_info
=detail::get_current_thread_data();
705 lock_guard
<mutex
> lg(thread_info
->data_mutex
);
706 return thread_info
->interrupt_requested
;
710 disable_interruption::disable_interruption() BOOST_NOEXCEPT
:
711 interruption_was_enabled(interruption_enabled())
713 if(interruption_was_enabled
)
715 detail::get_current_thread_data()->interrupt_enabled
=false;
719 disable_interruption::~disable_interruption() BOOST_NOEXCEPT
721 if(detail::get_current_thread_data())
723 detail::get_current_thread_data()->interrupt_enabled
=interruption_was_enabled
;
727 restore_interruption::restore_interruption(disable_interruption
& d
) BOOST_NOEXCEPT
729 if(d
.interruption_was_enabled
)
731 detail::get_current_thread_data()->interrupt_enabled
=true;
735 restore_interruption::~restore_interruption() BOOST_NOEXCEPT
737 if(detail::get_current_thread_data())
739 detail::get_current_thread_data()->interrupt_enabled
=false;
747 void add_thread_exit_function(thread_exit_function_base
* func
)
749 detail::thread_data_base
* const current_thread_data(get_or_make_current_thread_data());
750 thread_exit_callback_node
* const new_node
=
751 heap_new
<thread_exit_callback_node
>(func
,current_thread_data
->thread_exit_callbacks
);
752 current_thread_data
->thread_exit_callbacks
=new_node
;
755 tss_data_node
* find_tss_data(void const* key
)
757 detail::thread_data_base
* const current_thread_data(get_current_thread_data());
758 if(current_thread_data
)
760 std::map
<void const*,tss_data_node
>::iterator current_node
=
761 current_thread_data
->tss_data
.find(key
);
762 if(current_node
!=current_thread_data
->tss_data
.end())
764 return ¤t_node
->second
;
770 void* get_tss_data(void const* key
)
772 if(tss_data_node
* const current_node
=find_tss_data(key
))
774 return current_node
->value
;
779 void add_new_tss_node(void const* key
,
780 boost::shared_ptr
<tss_cleanup_function
> func
,
783 detail::thread_data_base
* const current_thread_data(get_or_make_current_thread_data());
784 current_thread_data
->tss_data
.insert(std::make_pair(key
,tss_data_node(func
,tss_data
)));
787 void erase_tss_node(void const* key
)
789 detail::thread_data_base
* const current_thread_data(get_current_thread_data());
790 if(current_thread_data
)
792 current_thread_data
->tss_data
.erase(key
);
796 void set_tss_data(void const* key
,
797 boost::shared_ptr
<tss_cleanup_function
> func
,
798 void* tss_data
,bool cleanup_existing
)
800 if(tss_data_node
* const current_node
=find_tss_data(key
))
802 if(cleanup_existing
&& current_node
->func
&& (current_node
->value
!=0))
804 (*current_node
->func
)(current_node
->value
);
806 if(func
|| (tss_data
!=0))
808 current_node
->func
=func
;
809 current_node
->value
=tss_data
;
816 else if(func
|| (tss_data
!=0))
818 add_new_tss_node(key
,func
,tss_data
);
823 BOOST_THREAD_DECL
void notify_all_at_thread_exit(condition_variable
& cond
, unique_lock
<mutex
> lk
)
825 detail::thread_data_base
* const current_thread_data(detail::get_current_thread_data());
826 if(current_thread_data
)
828 current_thread_data
->notify_all_at_thread_exit(&cond
, lk
.release());
833 void BOOST_THREAD_DECL
make_ready_at_thread_exit(shared_ptr
<shared_state_base
> as
)
835 detail::thread_data_base
* const current_thread_data(detail::get_current_thread_data());
836 if(current_thread_data
)
838 current_thread_data
->make_ready_at_thread_exit(as
);