]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/thread/src/pthread/thread.cpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / libs / thread / src / pthread / thread.cpp
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 {
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
64 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 {
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 {
121 delete_current_thread_tls_key_on_dlclose_t()
122 {
123 }
124 ~delete_current_thread_tls_key_on_dlclose_t()
125 {
126 const boost::once_flag uninitialized = BOOST_ONCE_INIT;
127 if (memcmp(&current_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
138 void create_current_thread_tls_key()
139 {
140 BOOST_VERIFY(!pthread_key_create(&current_thread_tls_key,&tls_destructor));
141 }
142 }
143
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
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 {
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 {
203 externally_launched_thread()
204 {
205 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
206 interrupt_enabled=false;
207 #endif
208 }
209 ~externally_launched_thread() {
210 BOOST_ASSERT(notify.empty());
211 notify.clear();
212 BOOST_ASSERT(async_states_.empty());
213 async_states_.clear();
214 }
215 void run()
216 {}
217 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
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
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
247 thread::thread() BOOST_NOEXCEPT
248 {}
249
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
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
300 detail::thread_data_ptr thread::get_thread_info BOOST_PREVENT_MACRO_SUBSTITUTION () const
301 {
302 return thread_info;
303 }
304
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
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
406 bool thread::joinable() const BOOST_NOEXCEPT
407 {
408 return (get_thread_info)()?true:false;
409 }
410
411
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 {
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
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 {
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
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 {
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 }
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
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
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
640 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
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 {
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
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
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
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
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
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
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 {
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
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 &current_node->second;
765 }
766 }
767 return 0;
768 }
769
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
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
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
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
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
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 }