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)->notify_deferred(); 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 struct delete_current_thread_tls_key_on_dlclose_t 120 { delete_current_thread_tls_key_on_dlclose_tboost::detail::__anon4295b5aa0111::delete_current_thread_tls_key_on_dlclose_t121 delete_current_thread_tls_key_on_dlclose_t() 122 { 123 } ~delete_current_thread_tls_key_on_dlclose_tboost::detail::__anon4295b5aa0111::delete_current_thread_tls_key_on_dlclose_t124 ~delete_current_thread_tls_key_on_dlclose_t() 125 { 126 const boost::once_flag uninitialized = BOOST_ONCE_INIT; 127 if (memcmp(¤t_thread_tls_init_flag, &uninitialized, sizeof(boost::once_flag))) 128 { 129 void* data = pthread_getspecific(current_thread_tls_key); 130 if (data) 131 tls_destructor(data); 132 pthread_key_delete(current_thread_tls_key); 133 } 134 } 135 }; 136 delete_current_thread_tls_key_on_dlclose_t delete_current_thread_tls_key_on_dlclose; 137 #endif create_current_thread_tls_key()138 void create_current_thread_tls_key() 139 { 140 BOOST_VERIFY(!pthread_key_create(¤t_thread_tls_key,&tls_destructor)); 141 } 142 } 143 get_current_thread_data()144 boost::detail::thread_data_base* get_current_thread_data() 145 { 146 boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key); 147 return (boost::detail::thread_data_base*)pthread_getspecific(current_thread_tls_key); 148 } 149 set_current_thread_data(detail::thread_data_base * new_data)150 void set_current_thread_data(detail::thread_data_base* new_data) 151 { 152 boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key); 153 BOOST_VERIFY(!pthread_setspecific(current_thread_tls_key,new_data)); 154 } 155 } 156 157 namespace 158 { 159 extern "C" 160 { thread_proxy(void * param)161 static void* thread_proxy(void* param) 162 { 163 //boost::detail::thread_data_ptr thread_info = static_cast<boost::detail::thread_data_base*>(param)->self; 164 boost::detail::thread_data_ptr thread_info = static_cast<boost::detail::thread_data_base*>(param)->shared_from_this(); 165 thread_info->self.reset(); 166 detail::set_current_thread_data(thread_info.get()); 167 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS 168 BOOST_TRY 169 { 170 #endif 171 thread_info->run(); 172 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS 173 174 } 175 BOOST_CATCH (thread_interrupted const&) 176 { 177 } 178 // Removed as it stops the debugger identifying the cause of the exception 179 // Unhandled exceptions still cause the application to terminate 180 // BOOST_CATCH(...) 181 // { 182 // throw; 183 // 184 // std::terminate(); 185 // } 186 BOOST_CATCH_END 187 #endif 188 detail::tls_destructor(thread_info.get()); 189 detail::set_current_thread_data(0); 190 boost::lock_guard<boost::mutex> lock(thread_info->data_mutex); 191 thread_info->done=true; 192 thread_info->done_condition.notify_all(); 193 194 return 0; 195 } 196 } 197 } 198 namespace detail 199 { 200 struct externally_launched_thread: 201 detail::thread_data_base 202 { externally_launched_threadboost::detail::externally_launched_thread203 externally_launched_thread() 204 { 205 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS 206 interrupt_enabled=false; 207 #endif 208 } ~externally_launched_threadboost::detail::externally_launched_thread209 ~externally_launched_thread() { 210 BOOST_ASSERT(notify.empty()); 211 notify.clear(); 212 BOOST_ASSERT(async_states_.empty()); 213 async_states_.clear(); 214 } runboost::detail::externally_launched_thread215 void run() 216 {} notify_all_at_thread_exitboost::detail::externally_launched_thread217 void notify_all_at_thread_exit(condition_variable*, mutex*) 218 {} 219 220 private: 221 externally_launched_thread(externally_launched_thread&); 222 void operator=(externally_launched_thread&); 223 }; 224 make_external_thread_data()225 thread_data_base* make_external_thread_data() 226 { 227 thread_data_base* const me(detail::heap_new<externally_launched_thread>()); 228 me->self.reset(me); 229 set_current_thread_data(me); 230 return me; 231 } 232 233 get_or_make_current_thread_data()234 thread_data_base* get_or_make_current_thread_data() 235 { 236 thread_data_base* current_thread_data(get_current_thread_data()); 237 if(!current_thread_data) 238 { 239 current_thread_data=make_external_thread_data(); 240 } 241 return current_thread_data; 242 } 243 244 } 245 246 thread()247 thread::thread() BOOST_NOEXCEPT 248 {} 249 start_thread_noexcept()250 bool thread::start_thread_noexcept() 251 { 252 thread_info->self=thread_info; 253 int const res = pthread_create(&thread_info->thread_handle, 0, &thread_proxy, thread_info.get()); 254 if (res != 0) 255 { 256 thread_info->self.reset(); 257 return false; 258 } 259 return true; 260 } 261 start_thread_noexcept(const attributes & attr)262 bool thread::start_thread_noexcept(const attributes& attr) 263 { 264 thread_info->self=thread_info; 265 const attributes::native_handle_type* h = attr.native_handle(); 266 int res = pthread_create(&thread_info->thread_handle, h, &thread_proxy, thread_info.get()); 267 if (res != 0) 268 { 269 thread_info->self.reset(); 270 return false; 271 } 272 int detached_state; 273 res = pthread_attr_getdetachstate(h, &detached_state); 274 if (res != 0) 275 { 276 thread_info->self.reset(); 277 return false; 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 hidden 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_realtime(const timespec & ts)460 void BOOST_THREAD_DECL sleep_until_realtime(const timespec& ts) 461 { 462 timespec now = boost::detail::timespec_now_realtime(); 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_realtime(); 483 if (boost::detail::timespec_ge(now2, ts)) 484 { 485 return; 486 } 487 } 488 } 489 } 490 } 491 } 492 namespace hidden 493 { sleep_for(const timespec & ts)494 void BOOST_THREAD_DECL sleep_for(const timespec& ts) 495 { 496 boost::detail::thread_data_base* const thread_info=boost::detail::get_current_thread_data(); 497 498 if(thread_info) 499 { 500 unique_lock<mutex> lk(thread_info->sleep_mutex); 501 while( thread_info->sleep_condition.do_wait_for(lk,ts)) {} 502 } 503 else 504 { 505 boost::this_thread::no_interruption_point::hidden::sleep_for(ts); 506 } 507 } 508 sleep_until_realtime(const timespec & ts)509 void BOOST_THREAD_DECL sleep_until_realtime(const timespec& ts) 510 { 511 boost::detail::thread_data_base* const thread_info=boost::detail::get_current_thread_data(); 512 513 if(thread_info) 514 { 515 unique_lock<mutex> lk(thread_info->sleep_mutex); 516 while(thread_info->sleep_condition.do_wait_until(lk,ts)) {} 517 } 518 else 519 { 520 boost::this_thread::no_interruption_point::hidden::sleep_until_realtime(ts); 521 } 522 } 523 } // hidden 524 } // this_thread 525 526 namespace this_thread 527 { yield()528 void yield() BOOST_NOEXCEPT 529 { 530 # if defined(BOOST_HAS_SCHED_YIELD) 531 BOOST_VERIFY(!sched_yield()); 532 # elif defined(BOOST_HAS_PTHREAD_YIELD) 533 BOOST_VERIFY(!pthread_yield()); 534 //# elif defined BOOST_THREAD_USES_DATETIME 535 // xtime xt; 536 // xtime_get(&xt, TIME_UTC_); 537 // sleep(xt); 538 // sleep_for(chrono::milliseconds(0)); 539 # else 540 #error 541 timespec ts; 542 ts.tv_sec= 0; 543 ts.tv_nsec= 0; 544 hidden::sleep_for(ts); 545 # endif 546 } 547 } hardware_concurrency()548 unsigned thread::hardware_concurrency() BOOST_NOEXCEPT 549 { 550 #if defined(PTW32_VERSION) || defined(__hpux) 551 return pthread_num_processors_np(); 552 #elif defined(__APPLE__) || defined(__FreeBSD__) 553 int count; 554 size_t size=sizeof(count); 555 return sysctlbyname("hw.ncpu",&count,&size,NULL,0)?0:count; 556 #elif defined(BOOST_HAS_UNISTD_H) && defined(_SC_NPROCESSORS_ONLN) 557 int const count=sysconf(_SC_NPROCESSORS_ONLN); 558 return (count>0)?count:0; 559 #elif defined(__GLIBC__) 560 return get_nprocs(); 561 #else 562 return 0; 563 #endif 564 } 565 physical_concurrency()566 unsigned thread::physical_concurrency() BOOST_NOEXCEPT 567 { 568 #ifdef __linux__ 569 try { 570 using namespace std; 571 572 ifstream proc_cpuinfo ("/proc/cpuinfo"); 573 574 const string physical_id("physical id"), core_id("core id"); 575 576 typedef std::pair<unsigned, unsigned> core_entry; // [physical ID, core id] 577 578 std::set<core_entry> cores; 579 580 core_entry current_core_entry; 581 582 string line; 583 while ( getline(proc_cpuinfo, line) ) { 584 if (line.empty()) 585 continue; 586 587 vector<string> key_val(2); 588 boost::split(key_val, line, boost::is_any_of(":")); 589 590 if (key_val.size() != 2) 591 return hardware_concurrency(); 592 593 string key = key_val[0]; 594 string value = key_val[1]; 595 boost::trim(key); 596 boost::trim(value); 597 598 if (key == physical_id) { 599 current_core_entry.first = boost::lexical_cast<unsigned>(value); 600 continue; 601 } 602 603 if (key == core_id) { 604 current_core_entry.second = boost::lexical_cast<unsigned>(value); 605 cores.insert(current_core_entry); 606 continue; 607 } 608 } 609 // Fall back to hardware_concurrency() in case 610 // /proc/cpuinfo is formatted differently than we expect. 611 return cores.size() != 0 ? cores.size() : hardware_concurrency(); 612 } catch(...) { 613 return hardware_concurrency(); 614 } 615 #elif defined(__APPLE__) 616 int count; 617 size_t size=sizeof(count); 618 return sysctlbyname("hw.physicalcpu",&count,&size,NULL,0)?0:count; 619 #else 620 return hardware_concurrency(); 621 #endif 622 } 623 624 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS interrupt()625 void thread::interrupt() 626 { 627 detail::thread_data_ptr const local_thread_info=(get_thread_info)(); 628 if(local_thread_info) 629 { 630 lock_guard<mutex> lk(local_thread_info->data_mutex); 631 local_thread_info->interrupt_requested=true; 632 if(local_thread_info->current_cond) 633 { 634 boost::pthread::pthread_mutex_scoped_lock internal_lock(local_thread_info->cond_mutex); 635 BOOST_VERIFY(!pthread_cond_broadcast(local_thread_info->current_cond)); 636 } 637 } 638 } 639 interruption_requested() const640 bool thread::interruption_requested() const BOOST_NOEXCEPT 641 { 642 detail::thread_data_ptr const local_thread_info=(get_thread_info)(); 643 if(local_thread_info) 644 { 645 lock_guard<mutex> lk(local_thread_info->data_mutex); 646 return local_thread_info->interrupt_requested; 647 } 648 else 649 { 650 return false; 651 } 652 } 653 #endif 654 native_handle()655 thread::native_handle_type thread::native_handle() 656 { 657 detail::thread_data_ptr const local_thread_info=(get_thread_info)(); 658 if(local_thread_info) 659 { 660 lock_guard<mutex> lk(local_thread_info->data_mutex); 661 return local_thread_info->thread_handle; 662 } 663 else 664 { 665 return pthread_t(); 666 } 667 } 668 669 670 671 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS 672 namespace this_thread 673 { interruption_point()674 void interruption_point() 675 { 676 #ifndef BOOST_NO_EXCEPTIONS 677 boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data(); 678 if(thread_info && thread_info->interrupt_enabled) 679 { 680 lock_guard<mutex> lg(thread_info->data_mutex); 681 if(thread_info->interrupt_requested) 682 { 683 thread_info->interrupt_requested=false; 684 throw thread_interrupted(); 685 } 686 } 687 #endif 688 } 689 interruption_enabled()690 bool interruption_enabled() BOOST_NOEXCEPT 691 { 692 boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data(); 693 return thread_info && thread_info->interrupt_enabled; 694 } 695 interruption_requested()696 bool interruption_requested() BOOST_NOEXCEPT 697 { 698 boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data(); 699 if(!thread_info) 700 { 701 return false; 702 } 703 else 704 { 705 lock_guard<mutex> lg(thread_info->data_mutex); 706 return thread_info->interrupt_requested; 707 } 708 } 709 disable_interruption()710 disable_interruption::disable_interruption() BOOST_NOEXCEPT: 711 interruption_was_enabled(interruption_enabled()) 712 { 713 if(interruption_was_enabled) 714 { 715 detail::get_current_thread_data()->interrupt_enabled=false; 716 } 717 } 718 ~disable_interruption()719 disable_interruption::~disable_interruption() BOOST_NOEXCEPT 720 { 721 if(detail::get_current_thread_data()) 722 { 723 detail::get_current_thread_data()->interrupt_enabled=interruption_was_enabled; 724 } 725 } 726 restore_interruption(disable_interruption & d)727 restore_interruption::restore_interruption(disable_interruption& d) BOOST_NOEXCEPT 728 { 729 if(d.interruption_was_enabled) 730 { 731 detail::get_current_thread_data()->interrupt_enabled=true; 732 } 733 } 734 ~restore_interruption()735 restore_interruption::~restore_interruption() BOOST_NOEXCEPT 736 { 737 if(detail::get_current_thread_data()) 738 { 739 detail::get_current_thread_data()->interrupt_enabled=false; 740 } 741 } 742 } 743 #endif 744 745 namespace detail 746 { add_thread_exit_function(thread_exit_function_base * func)747 void add_thread_exit_function(thread_exit_function_base* func) 748 { 749 detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data()); 750 thread_exit_callback_node* const new_node= 751 heap_new<thread_exit_callback_node>(func,current_thread_data->thread_exit_callbacks); 752 current_thread_data->thread_exit_callbacks=new_node; 753 } 754 find_tss_data(void const * key)755 tss_data_node* find_tss_data(void const* key) 756 { 757 detail::thread_data_base* const current_thread_data(get_current_thread_data()); 758 if(current_thread_data) 759 { 760 std::map<void const*,tss_data_node>::iterator current_node= 761 current_thread_data->tss_data.find(key); 762 if(current_node!=current_thread_data->tss_data.end()) 763 { 764 return ¤t_node->second; 765 } 766 } 767 return 0; 768 } 769 get_tss_data(void const * key)770 void* get_tss_data(void const* key) 771 { 772 if(tss_data_node* const current_node=find_tss_data(key)) 773 { 774 return current_node->value; 775 } 776 return 0; 777 } 778 add_new_tss_node(void const * key,boost::shared_ptr<tss_cleanup_function> func,void * tss_data)779 void add_new_tss_node(void const* key, 780 boost::shared_ptr<tss_cleanup_function> func, 781 void* tss_data) 782 { 783 detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data()); 784 current_thread_data->tss_data.insert(std::make_pair(key,tss_data_node(func,tss_data))); 785 } 786 erase_tss_node(void const * key)787 void erase_tss_node(void const* key) 788 { 789 detail::thread_data_base* const current_thread_data(get_current_thread_data()); 790 if(current_thread_data) 791 { 792 current_thread_data->tss_data.erase(key); 793 } 794 } 795 set_tss_data(void const * key,boost::shared_ptr<tss_cleanup_function> func,void * tss_data,bool cleanup_existing)796 void set_tss_data(void const* key, 797 boost::shared_ptr<tss_cleanup_function> func, 798 void* tss_data,bool cleanup_existing) 799 { 800 if(tss_data_node* const current_node=find_tss_data(key)) 801 { 802 if(cleanup_existing && current_node->func && (current_node->value!=0)) 803 { 804 (*current_node->func)(current_node->value); 805 } 806 if(func || (tss_data!=0)) 807 { 808 current_node->func=func; 809 current_node->value=tss_data; 810 } 811 else 812 { 813 erase_tss_node(key); 814 } 815 } 816 else if(func || (tss_data!=0)) 817 { 818 add_new_tss_node(key,func,tss_data); 819 } 820 } 821 } 822 notify_all_at_thread_exit(condition_variable & cond,unique_lock<mutex> lk)823 BOOST_THREAD_DECL void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk) 824 { 825 detail::thread_data_base* const current_thread_data(detail::get_current_thread_data()); 826 if(current_thread_data) 827 { 828 current_thread_data->notify_all_at_thread_exit(&cond, lk.release()); 829 } 830 } 831 namespace detail { 832 make_ready_at_thread_exit(shared_ptr<shared_state_base> as)833 void BOOST_THREAD_DECL make_ready_at_thread_exit(shared_ptr<shared_state_base> as) 834 { 835 detail::thread_data_base* const current_thread_data(detail::get_current_thread_data()); 836 if(current_thread_data) 837 { 838 current_thread_data->make_ready_at_thread_exit(as); 839 } 840 } 841 } 842 843 844 845 } 846