1// Copyright (C) 2001-2003
2// William E. Kempf
3// Copyright (C) 2007-8 Anthony Williams
4// (C) Copyright 2011-2012 Vicente J. Botet Escriba
5//
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)
8
9#include <boost/thread/detail/config.hpp>
10
11#include <boost/thread/thread_only.hpp>
12#if defined BOOST_THREAD_USES_DATETIME
13#include <boost/thread/xtime.hpp>
14#endif
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>
20#include <boost/thread/pthread/pthread_helpers.hpp>
21#include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
22#include <boost/thread/detail/string_trim.hpp>
23#include <boost/thread/detail/string_to_unsigned.hpp>
24
25#ifdef __GLIBC__
26#include <sys/sysinfo.h>
27#elif defined(__APPLE__) || defined(__FreeBSD__)
28#include <sys/types.h>
29#include <sys/sysctl.h>
30#elif defined BOOST_HAS_UNISTD_H
31#include <unistd.h>
32#endif
33
34#if defined(__VXWORKS__)
35#include <vxCpuLib.h>
36#endif
37
38#include <fstream>
39#include <string>
40#include <set>
41#include <vector>
42#include <string.h> // memcmp.
43
44namespace boost
45{
46 namespace detail
47 {
48 thread_data_base::~thread_data_base()
49 {
50 for (notify_list_t::iterator i = notify.begin(), e = notify.end();
51 i != e; ++i)
52 {
53 i->second->unlock();
54 i->first->notify_all();
55 }
56//#ifndef BOOST_NO_EXCEPTIONS
57 for (async_states_t::iterator i = async_states_.begin(), e = async_states_.end();
58 i != e; ++i)
59 {
60 (*i)->notify_deferred();
61 }
62//#endif
63 }
64
65 struct thread_exit_callback_node
66 {
67 boost::detail::thread_exit_function_base* func;
68 thread_exit_callback_node* next;
69
70 thread_exit_callback_node(boost::detail::thread_exit_function_base* func_,
71 thread_exit_callback_node* next_):
72 func(func_),next(next_)
73 {}
74 };
75
76 namespace
77 {
78#ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11
79 boost::once_flag current_thread_tls_init_flag;
80#else
81 boost::once_flag current_thread_tls_init_flag=BOOST_ONCE_INIT;
82#endif
83 pthread_key_t current_thread_tls_key;
84
85 extern "C"
86 {
87 static void tls_destructor(void* data)
88 {
89 //boost::detail::thread_data_base* thread_info=static_cast<boost::detail::thread_data_base*>(data);
90 boost::detail::thread_data_ptr thread_info = static_cast<boost::detail::thread_data_base*>(data)->shared_from_this();
91
92 if(thread_info)
93 {
94 while(!thread_info->tss_data.empty() || thread_info->thread_exit_callbacks)
95 {
96
97 while(thread_info->thread_exit_callbacks)
98 {
99 detail::thread_exit_callback_node* const current_node=thread_info->thread_exit_callbacks;
100 thread_info->thread_exit_callbacks=current_node->next;
101 if(current_node->func)
102 {
103 (*current_node->func)();
104 delete current_node->func;
105 }
106 delete current_node;
107 }
108 while (!thread_info->tss_data.empty())
109 {
110 std::map<void const*,detail::tss_data_node>::iterator current
111 = thread_info->tss_data.begin();
112 if(current->second.func && (current->second.value!=0))
113 {
114 (*current->second.caller)(current->second.func,current->second.value);
115 }
116 thread_info->tss_data.erase(position: current);
117 }
118 }
119 thread_info->self.reset();
120 }
121 }
122 }
123
124#if defined BOOST_THREAD_PATCH
125 struct delete_current_thread_tls_key_on_dlclose_t
126 {
127 delete_current_thread_tls_key_on_dlclose_t()
128 {
129 }
130 ~delete_current_thread_tls_key_on_dlclose_t()
131 {
132 const boost::once_flag uninitialized = BOOST_ONCE_INIT;
133 if (memcmp(&current_thread_tls_init_flag, &uninitialized, sizeof(boost::once_flag)))
134 {
135 void* data = pthread_getspecific(current_thread_tls_key);
136 if (data)
137 tls_destructor(data);
138 pthread_key_delete(current_thread_tls_key);
139 }
140 }
141 };
142 delete_current_thread_tls_key_on_dlclose_t delete_current_thread_tls_key_on_dlclose;
143#endif
144 void create_current_thread_tls_key()
145 {
146 BOOST_VERIFY(!pthread_key_create(&current_thread_tls_key,&tls_destructor));
147 }
148 }
149
150 boost::detail::thread_data_base* get_current_thread_data()
151 {
152 boost::call_once(flag&: current_thread_tls_init_flag,f: &create_current_thread_tls_key);
153 return (boost::detail::thread_data_base*)pthread_getspecific(key: current_thread_tls_key);
154 }
155
156 void set_current_thread_data(detail::thread_data_base* new_data)
157 {
158 boost::call_once(flag&: current_thread_tls_init_flag,f&: create_current_thread_tls_key);
159 BOOST_VERIFY(!pthread_setspecific(current_thread_tls_key,new_data));
160 }
161 }
162
163 namespace
164 {
165 extern "C"
166 {
167 static void* thread_proxy(void* param)
168 {
169 //boost::detail::thread_data_ptr thread_info = static_cast<boost::detail::thread_data_base*>(param)->self;
170 boost::detail::thread_data_ptr thread_info = static_cast<boost::detail::thread_data_base*>(param)->shared_from_this();
171 thread_info->self.reset();
172 detail::set_current_thread_data(thread_info.get());
173#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
174 BOOST_TRY
175 {
176#endif
177 thread_info->run();
178#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
179
180 }
181 BOOST_CATCH (thread_interrupted const&)
182 {
183 }
184// Removed as it stops the debugger identifying the cause of the exception
185// Unhandled exceptions still cause the application to terminate
186// BOOST_CATCH(...)
187// {
188// throw;
189//
190// std::terminate();
191// }
192 BOOST_CATCH_END
193#endif
194 detail::tls_destructor(data: thread_info.get());
195 detail::set_current_thread_data(0);
196 boost::lock_guard<boost::mutex> lock(thread_info->data_mutex);
197 thread_info->done=true;
198 thread_info->done_condition.notify_all();
199
200 return 0;
201 }
202 }
203 }
204 namespace detail
205 {
206 struct externally_launched_thread:
207 detail::thread_data_base
208 {
209 externally_launched_thread()
210 {
211#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
212 interrupt_enabled=false;
213#endif
214 }
215 ~externally_launched_thread() {
216 BOOST_ASSERT(notify.empty());
217 notify.clear();
218//#ifndef BOOST_NO_EXCEPTIONS
219 BOOST_ASSERT(async_states_.empty());
220 async_states_.clear();
221//#endif
222 }
223 void run()
224 {}
225 void notify_all_at_thread_exit(condition_variable*, mutex*)
226 {}
227
228 private:
229 externally_launched_thread(externally_launched_thread&);
230 void operator=(externally_launched_thread&);
231 };
232
233 thread_data_base* make_external_thread_data()
234 {
235 thread_data_base* const me(detail::heap_new<externally_launched_thread>());
236 me->self.reset(p: me);
237 set_current_thread_data(me);
238 return me;
239 }
240
241
242 thread_data_base* get_or_make_current_thread_data()
243 {
244 thread_data_base* current_thread_data(get_current_thread_data());
245 if(!current_thread_data)
246 {
247 current_thread_data=make_external_thread_data();
248 }
249 return current_thread_data;
250 }
251
252 }
253
254
255 thread::thread() BOOST_NOEXCEPT
256 {}
257
258 bool thread::start_thread_noexcept()
259 {
260 thread_info->self=thread_info;
261 int const res = pthread_create(newthread: &thread_info->thread_handle, attr: 0, start_routine: &thread_proxy, arg: thread_info.get());
262 if (res != 0)
263 {
264 thread_info->self.reset();
265 return false;
266 }
267 return true;
268 }
269
270 bool thread::start_thread_noexcept(const attributes& attr)
271 {
272 thread_info->self=thread_info;
273 const attributes::native_handle_type* h = attr.native_handle();
274 int res = pthread_create(newthread: &thread_info->thread_handle, attr: h, start_routine: &thread_proxy, arg: thread_info.get());
275 if (res != 0)
276 {
277 thread_info->self.reset();
278 return false;
279 }
280 int detached_state;
281 res = pthread_attr_getdetachstate(attr: h, detachstate: &detached_state);
282 if (res != 0)
283 {
284 thread_info->self.reset();
285 return false;
286 }
287 if (PTHREAD_CREATE_DETACHED==detached_state)
288 {
289 detail::thread_data_ptr local_thread_info;
290 thread_info.swap(other&: local_thread_info);
291
292 if(local_thread_info)
293 {
294 //lock_guard<mutex> lock(local_thread_info->data_mutex);
295 if(!local_thread_info->join_started)
296 {
297 //BOOST_VERIFY(!pthread_detach(local_thread_info->thread_handle));
298 local_thread_info->join_started=true;
299 local_thread_info->joined=true;
300 }
301 }
302 }
303 return true;
304 }
305
306
307
308 detail::thread_data_ptr thread::get_thread_info BOOST_PREVENT_MACRO_SUBSTITUTION () const
309 {
310 return thread_info;
311 }
312
313 bool thread::join_noexcept()
314 {
315 detail::thread_data_ptr const local_thread_info=(get_thread_info)();
316 if(local_thread_info)
317 {
318 bool do_join=false;
319
320 {
321 unique_lock<mutex> lock(local_thread_info->data_mutex);
322 while(!local_thread_info->done)
323 {
324 local_thread_info->done_condition.wait(m&: lock);
325 }
326 do_join=!local_thread_info->join_started;
327
328 if(do_join)
329 {
330 local_thread_info->join_started=true;
331 }
332 else
333 {
334 while(!local_thread_info->joined)
335 {
336 local_thread_info->done_condition.wait(m&: lock);
337 }
338 }
339 }
340 if(do_join)
341 {
342 void* result=0;
343 BOOST_VERIFY(!pthread_join(local_thread_info->thread_handle,&result));
344 lock_guard<mutex> lock(local_thread_info->data_mutex);
345 local_thread_info->joined=true;
346 local_thread_info->done_condition.notify_all();
347 }
348
349 if(thread_info==local_thread_info)
350 {
351 thread_info.reset();
352 }
353 return true;
354 }
355 else
356 {
357 return false;
358 }
359 }
360
361 bool thread::do_try_join_until_noexcept(detail::internal_platform_timepoint const &timeout, bool& res)
362 {
363 detail::thread_data_ptr const local_thread_info=(get_thread_info)();
364 if(local_thread_info)
365 {
366 bool do_join=false;
367
368 {
369 unique_lock<mutex> lock(local_thread_info->data_mutex);
370 while(!local_thread_info->done)
371 {
372 if(!local_thread_info->done_condition.do_wait_until(m&: lock,timeout)) break; // timeout occurred
373 }
374 if(!local_thread_info->done)
375 {
376 res=false;
377 return true;
378 }
379 do_join=!local_thread_info->join_started;
380
381 if(do_join)
382 {
383 local_thread_info->join_started=true;
384 }
385 else
386 {
387 while(!local_thread_info->joined)
388 {
389 local_thread_info->done_condition.wait(m&: lock);
390 }
391 }
392 }
393 if(do_join)
394 {
395 void* result=0;
396 BOOST_VERIFY(!pthread_join(local_thread_info->thread_handle,&result));
397 lock_guard<mutex> lock(local_thread_info->data_mutex);
398 local_thread_info->joined=true;
399 local_thread_info->done_condition.notify_all();
400 }
401
402 if(thread_info==local_thread_info)
403 {
404 thread_info.reset();
405 }
406 res=true;
407 return true;
408 }
409 else
410 {
411 return false;
412 }
413 }
414
415 bool thread::joinable() const BOOST_NOEXCEPT
416 {
417 return (get_thread_info)()?true:false;
418 }
419
420
421 void thread::detach()
422 {
423 detail::thread_data_ptr local_thread_info;
424 thread_info.swap(other&: local_thread_info);
425
426 if(local_thread_info)
427 {
428 lock_guard<mutex> lock(local_thread_info->data_mutex);
429 if(!local_thread_info->join_started)
430 {
431 BOOST_VERIFY(!pthread_detach(local_thread_info->thread_handle));
432 local_thread_info->join_started=true;
433 local_thread_info->joined=true;
434 }
435 }
436 }
437
438 namespace this_thread
439 {
440 namespace no_interruption_point
441 {
442 namespace hidden
443 {
444 void BOOST_THREAD_DECL sleep_for_internal(const detail::platform_duration& ts)
445 {
446 if (ts > detail::platform_duration::zero())
447 {
448 // Use pthread_delay_np or nanosleep whenever possible here in the no_interruption_point
449 // namespace because they do not provide an interruption point.
450 # if defined(BOOST_HAS_PTHREAD_DELAY_NP)
451 # if defined(__IBMCPP__) || defined(_AIX)
452 BOOST_VERIFY(!pthread_delay_np(const_cast<timespec*>(&ts.getTs())));
453 # else
454 BOOST_VERIFY(!pthread_delay_np(&ts.getTs()));
455 # endif
456 # elif defined(BOOST_HAS_NANOSLEEP)
457 nanosleep(requested_time: &ts.getTs(), remaining: 0);
458 # else
459 // This should never be reached due to BOOST_THREAD_SLEEP_FOR_IS_STEADY
460 # endif
461 }
462 }
463 }
464 }
465
466 void yield() BOOST_NOEXCEPT
467 {
468# if defined(BOOST_HAS_SCHED_YIELD)
469 BOOST_VERIFY(!sched_yield());
470# elif defined(BOOST_HAS_PTHREAD_YIELD)
471 BOOST_VERIFY(!pthread_yield());
472//# elif defined BOOST_THREAD_USES_DATETIME
473// ::boost::xtime xt;
474// xtime_get(&xt, TIME_UTC_);
475// sleep(xt);
476// sleep_for(chrono::milliseconds(0));
477# else
478 mutex mx;
479 unique_lock<mutex> lock(mx);
480 condition_variable cond;
481 cond.do_wait_until(lock, detail::internal_platform_clock::now());
482# endif
483 }
484 }
485 unsigned thread::hardware_concurrency() BOOST_NOEXCEPT
486 {
487#if defined(PTW32_VERSION) || defined(__hpux)
488 return pthread_num_processors_np();
489#elif defined(__APPLE__) || defined(__FreeBSD__)
490 int count;
491 size_t size=sizeof(count);
492 return sysctlbyname("hw.ncpu",&count,&size,NULL,0)?0:count;
493#elif defined(BOOST_HAS_UNISTD_H) && defined(_SC_NPROCESSORS_ONLN)
494 int const count=sysconf(_SC_NPROCESSORS_ONLN);
495 return (count>0)?count:0;
496#elif defined(__VXWORKS__)
497 cpuset_t set = ::vxCpuEnabledGet();
498 #ifdef __DCC__
499 int i;
500 for( i = 0; set; ++i)
501 {
502 set &= set -1;
503 }
504 return(i);
505 #else
506 return (__builtin_popcount(set) );
507 #endif
508#elif defined(__GLIBC__)
509 return get_nprocs();
510#else
511 return 0;
512#endif
513 }
514
515 unsigned thread::physical_concurrency() BOOST_NOEXCEPT
516 {
517#ifdef __linux__
518 try {
519 using namespace std;
520
521 ifstream proc_cpuinfo ("/proc/cpuinfo");
522
523 const string physical_id("physical id"), core_id("core id");
524
525 typedef std::pair<unsigned, unsigned> core_entry; // [physical ID, core id]
526
527 std::set<core_entry> cores;
528
529 core_entry current_core_entry;
530
531 string line;
532 while ( getline(is&: proc_cpuinfo, str&: line) ) {
533 if (line.empty())
534 continue;
535
536 std::size_t i = line.find( c: ':' );
537
538 if( i == std::string::npos )
539 {
540 return hardware_concurrency();
541 }
542
543 std::string key = line.substr( pos: 0, n: i );
544 std::string value = line.substr( pos: i+1 );
545
546 key = thread_detail::string_trim( s: key );
547 value = thread_detail::string_trim( s: value );
548
549 if (key == physical_id) {
550
551 if( !thread_detail::string_to_unsigned( s: value, v&: current_core_entry.first ) )
552 {
553 return hardware_concurrency();
554 }
555
556 continue;
557 }
558
559 if (key == core_id) {
560
561 if( !thread_detail::string_to_unsigned( s: value, v&: current_core_entry.second ) )
562 {
563 return hardware_concurrency();
564 }
565
566 cores.insert(x: current_core_entry);
567 continue;
568 }
569 }
570 // Fall back to hardware_concurrency() in case
571 // /proc/cpuinfo is formatted differently than we expect.
572 return cores.size() != 0 ? cores.size() : hardware_concurrency();
573 } catch(...) {
574 return hardware_concurrency();
575 }
576#elif defined(__APPLE__)
577 int count;
578 size_t size=sizeof(count);
579 return sysctlbyname("hw.physicalcpu",&count,&size,NULL,0)?0:count;
580#else
581 return hardware_concurrency();
582#endif
583 }
584
585#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
586 void thread::interrupt()
587 {
588 detail::thread_data_ptr const local_thread_info=(get_thread_info)();
589 if(local_thread_info)
590 {
591 lock_guard<mutex> lk(local_thread_info->data_mutex);
592 local_thread_info->interrupt_requested=true;
593 if(local_thread_info->current_cond)
594 {
595 boost::pthread::pthread_mutex_scoped_lock internal_lock(local_thread_info->cond_mutex);
596 BOOST_VERIFY(!posix::pthread_cond_broadcast(local_thread_info->current_cond));
597 }
598 }
599 }
600
601 bool thread::interruption_requested() const BOOST_NOEXCEPT
602 {
603 detail::thread_data_ptr const local_thread_info=(get_thread_info)();
604 if(local_thread_info)
605 {
606 lock_guard<mutex> lk(local_thread_info->data_mutex);
607 return local_thread_info->interrupt_requested;
608 }
609 else
610 {
611 return false;
612 }
613 }
614#endif
615
616 thread::native_handle_type thread::native_handle()
617 {
618 detail::thread_data_ptr const local_thread_info=(get_thread_info)();
619 if(local_thread_info)
620 {
621 lock_guard<mutex> lk(local_thread_info->data_mutex);
622 return local_thread_info->thread_handle;
623 }
624 else
625 {
626 return pthread_t();
627 }
628 }
629
630
631
632#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
633 namespace this_thread
634 {
635 void interruption_point()
636 {
637#ifndef BOOST_NO_EXCEPTIONS
638 boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data();
639 if(thread_info && thread_info->interrupt_enabled)
640 {
641 lock_guard<mutex> lg(thread_info->data_mutex);
642 if(thread_info->interrupt_requested)
643 {
644 thread_info->interrupt_requested=false;
645 throw thread_interrupted();
646 }
647 }
648#endif
649 }
650
651 bool interruption_enabled() BOOST_NOEXCEPT
652 {
653 boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data();
654 return thread_info && thread_info->interrupt_enabled;
655 }
656
657 bool interruption_requested() BOOST_NOEXCEPT
658 {
659 boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data();
660 if(!thread_info)
661 {
662 return false;
663 }
664 else
665 {
666 lock_guard<mutex> lg(thread_info->data_mutex);
667 return thread_info->interrupt_requested;
668 }
669 }
670
671 disable_interruption::disable_interruption() BOOST_NOEXCEPT:
672 interruption_was_enabled(interruption_enabled())
673 {
674 if(interruption_was_enabled)
675 {
676 detail::get_current_thread_data()->interrupt_enabled=false;
677 }
678 }
679
680 disable_interruption::~disable_interruption() BOOST_NOEXCEPT
681 {
682 if(detail::get_current_thread_data())
683 {
684 detail::get_current_thread_data()->interrupt_enabled=interruption_was_enabled;
685 }
686 }
687
688 restore_interruption::restore_interruption(disable_interruption& d) BOOST_NOEXCEPT
689 {
690 if(d.interruption_was_enabled)
691 {
692 detail::get_current_thread_data()->interrupt_enabled=true;
693 }
694 }
695
696 restore_interruption::~restore_interruption() BOOST_NOEXCEPT
697 {
698 if(detail::get_current_thread_data())
699 {
700 detail::get_current_thread_data()->interrupt_enabled=false;
701 }
702 }
703 }
704#endif
705
706 namespace detail
707 {
708 void add_thread_exit_function(thread_exit_function_base* func)
709 {
710 detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
711 thread_exit_callback_node* const new_node=
712 heap_new<thread_exit_callback_node>(a1&: func,a2&: current_thread_data->thread_exit_callbacks);
713 current_thread_data->thread_exit_callbacks=new_node;
714 }
715
716 tss_data_node* find_tss_data(void const* key)
717 {
718 detail::thread_data_base* const current_thread_data(get_current_thread_data());
719 if(current_thread_data)
720 {
721 std::map<void const*,tss_data_node>::iterator current_node=
722 current_thread_data->tss_data.find(x: key);
723 if(current_node!=current_thread_data->tss_data.end())
724 {
725 return &current_node->second;
726 }
727 }
728 return 0;
729 }
730
731 void* get_tss_data(void const* key)
732 {
733 if(tss_data_node* const current_node=find_tss_data(key))
734 {
735 return current_node->value;
736 }
737 return 0;
738 }
739
740 void add_new_tss_node(void const* key,
741 detail::tss_data_node::cleanup_caller_t caller,
742 detail::tss_data_node::cleanup_func_t func,
743 void* tss_data)
744 {
745 detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
746 current_thread_data->tss_data.insert(x: std::make_pair(x&: key,y: tss_data_node(caller,func,tss_data)));
747 }
748
749 void erase_tss_node(void const* key)
750 {
751 detail::thread_data_base* const current_thread_data(get_current_thread_data());
752 if(current_thread_data)
753 {
754 current_thread_data->tss_data.erase(x: key);
755 }
756 }
757
758 void set_tss_data(void const* key,
759 detail::tss_data_node::cleanup_caller_t caller,
760 detail::tss_data_node::cleanup_func_t func,
761 void* tss_data,bool cleanup_existing)
762 {
763 if(tss_data_node* const current_node=find_tss_data(key))
764 {
765 if(cleanup_existing && current_node->func && (current_node->value!=0))
766 {
767 (*current_node->caller)(current_node->func,current_node->value);
768 }
769 if(func || (tss_data!=0))
770 {
771 current_node->caller=caller;
772 current_node->func=func;
773 current_node->value=tss_data;
774 }
775 else
776 {
777 erase_tss_node(key);
778 }
779 }
780 else if(func || (tss_data!=0))
781 {
782 add_new_tss_node(key,caller,func,tss_data);
783 }
784 }
785 }
786
787 BOOST_THREAD_DECL void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk)
788 {
789 detail::thread_data_base* const current_thread_data(detail::get_current_thread_data());
790 if(current_thread_data)
791 {
792 current_thread_data->notify_all_at_thread_exit(cv: &cond, m: lk.release());
793 }
794 }
795
796//#ifndef BOOST_NO_EXCEPTIONS
797namespace detail {
798
799 void BOOST_THREAD_DECL make_ready_at_thread_exit(shared_ptr<shared_state_base> as)
800 {
801 detail::thread_data_base* const current_thread_data(detail::get_current_thread_data());
802 if(current_thread_data)
803 {
804 current_thread_data->make_ready_at_thread_exit(as);
805 }
806 }
807}
808//#endif
809
810
811}
812

source code of boost/libs/thread/src/pthread/thread.cpp