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