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