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