]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/thread/src/pthread/thread.cpp
add subtree-ish sources for 12.0.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)->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
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(const timespec& ts)
461 {
462 timespec now = boost::detail::timespec_now();
463 if (boost::detail::timespec_gt(ts, now))
464 {
465 for (int foo=0; foo < 5; ++foo)
466 {
467
468 # if defined(BOOST_HAS_PTHREAD_DELAY_NP)
469 timespec d = boost::detail::timespec_minus(ts, now);
470 BOOST_VERIFY(!pthread_delay_np(&d));
471 # elif defined(BOOST_HAS_NANOSLEEP)
472 // nanosleep takes a timespec that is an offset, not
473 // an absolute time.
474 timespec d = boost::detail::timespec_minus(ts, now);
475 nanosleep(&d, 0);
476 # else
477 mutex mx;
478 unique_lock<mutex> lock(mx);
479 condition_variable cond;
480 cond.do_wait_until(lock, ts);
481 # endif
482 timespec now2 = boost::detail::timespec_now();
483 if (boost::detail::timespec_ge(now2, ts))
484 {
485 return;
486 }
487 }
488 }
489 }
490
491 }
492 }
493 namespace hidden
494 {
495 void BOOST_THREAD_DECL sleep_for(const timespec& ts)
496 {
497 boost::detail::thread_data_base* const thread_info=boost::detail::get_current_thread_data();
498
499 if(thread_info)
500 {
501 unique_lock<mutex> lk(thread_info->sleep_mutex);
502 while( thread_info->sleep_condition.do_wait_for(lk,ts)) {}
503 }
504 else
505 {
506 boost::this_thread::no_interruption_point::hidden::sleep_for(ts);
507 }
508 }
509
510 void BOOST_THREAD_DECL sleep_until(const timespec& ts)
511 {
512 boost::detail::thread_data_base* const thread_info=boost::detail::get_current_thread_data();
513
514 if(thread_info)
515 {
516 unique_lock<mutex> lk(thread_info->sleep_mutex);
517 while(thread_info->sleep_condition.do_wait_until(lk,ts)) {}
518 }
519 else
520 {
521 boost::this_thread::no_interruption_point::hidden::sleep_until(ts);
522 }
523 }
524 } // hidden
525 } // this_thread
526
527 namespace this_thread
528 {
529 void yield() BOOST_NOEXCEPT
530 {
531 # if defined(BOOST_HAS_SCHED_YIELD)
532 BOOST_VERIFY(!sched_yield());
533 # elif defined(BOOST_HAS_PTHREAD_YIELD)
534 BOOST_VERIFY(!pthread_yield());
535 //# elif defined BOOST_THREAD_USES_DATETIME
536 // xtime xt;
537 // xtime_get(&xt, TIME_UTC_);
538 // sleep(xt);
539 // sleep_for(chrono::milliseconds(0));
540 # else
541 #error
542 timespec ts;
543 ts.tv_sec= 0;
544 ts.tv_nsec= 0;
545 hidden::sleep_for(ts);
546 # endif
547 }
548 }
549 unsigned thread::hardware_concurrency() BOOST_NOEXCEPT
550 {
551 #if defined(PTW32_VERSION) || defined(__hpux)
552 return pthread_num_processors_np();
553 #elif defined(__APPLE__) || defined(__FreeBSD__)
554 int count;
555 size_t size=sizeof(count);
556 return sysctlbyname("hw.ncpu",&count,&size,NULL,0)?0:count;
557 #elif defined(BOOST_HAS_UNISTD_H) && defined(_SC_NPROCESSORS_ONLN)
558 int const count=sysconf(_SC_NPROCESSORS_ONLN);
559 return (count>0)?count:0;
560 #elif defined(__GLIBC__)
561 return get_nprocs();
562 #else
563 return 0;
564 #endif
565 }
566
567 unsigned thread::physical_concurrency() BOOST_NOEXCEPT
568 {
569 #ifdef __linux__
570 try {
571 using namespace std;
572
573 ifstream proc_cpuinfo ("/proc/cpuinfo");
574
575 const string physical_id("physical id"), core_id("core id");
576
577 typedef std::pair<unsigned, unsigned> core_entry; // [physical ID, core id]
578
579 std::set<core_entry> cores;
580
581 core_entry current_core_entry;
582
583 string line;
584 while ( getline(proc_cpuinfo, line) ) {
585 if (line.empty())
586 continue;
587
588 vector<string> key_val(2);
589 boost::split(key_val, line, boost::is_any_of(":"));
590
591 if (key_val.size() != 2)
592 return hardware_concurrency();
593
594 string key = key_val[0];
595 string value = key_val[1];
596 boost::trim(key);
597 boost::trim(value);
598
599 if (key == physical_id) {
600 current_core_entry.first = boost::lexical_cast<unsigned>(value);
601 continue;
602 }
603
604 if (key == core_id) {
605 current_core_entry.second = boost::lexical_cast<unsigned>(value);
606 cores.insert(current_core_entry);
607 continue;
608 }
609 }
610 // Fall back to hardware_concurrency() in case
611 // /proc/cpuinfo is formatted differently than we expect.
612 return cores.size() != 0 ? cores.size() : hardware_concurrency();
613 } catch(...) {
614 return hardware_concurrency();
615 }
616 #elif defined(__APPLE__)
617 int count;
618 size_t size=sizeof(count);
619 return sysctlbyname("hw.physicalcpu",&count,&size,NULL,0)?0:count;
620 #else
621 return hardware_concurrency();
622 #endif
623 }
624
625 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
626 void thread::interrupt()
627 {
628 detail::thread_data_ptr const local_thread_info=(get_thread_info)();
629 if(local_thread_info)
630 {
631 lock_guard<mutex> lk(local_thread_info->data_mutex);
632 local_thread_info->interrupt_requested=true;
633 if(local_thread_info->current_cond)
634 {
635 boost::pthread::pthread_mutex_scoped_lock internal_lock(local_thread_info->cond_mutex);
636 BOOST_VERIFY(!pthread_cond_broadcast(local_thread_info->current_cond));
637 }
638 }
639 }
640
641 bool thread::interruption_requested() const BOOST_NOEXCEPT
642 {
643 detail::thread_data_ptr const local_thread_info=(get_thread_info)();
644 if(local_thread_info)
645 {
646 lock_guard<mutex> lk(local_thread_info->data_mutex);
647 return local_thread_info->interrupt_requested;
648 }
649 else
650 {
651 return false;
652 }
653 }
654 #endif
655
656 thread::native_handle_type thread::native_handle()
657 {
658 detail::thread_data_ptr const local_thread_info=(get_thread_info)();
659 if(local_thread_info)
660 {
661 lock_guard<mutex> lk(local_thread_info->data_mutex);
662 return local_thread_info->thread_handle;
663 }
664 else
665 {
666 return pthread_t();
667 }
668 }
669
670
671
672 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
673 namespace this_thread
674 {
675 void interruption_point()
676 {
677 #ifndef BOOST_NO_EXCEPTIONS
678 boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data();
679 if(thread_info && thread_info->interrupt_enabled)
680 {
681 lock_guard<mutex> lg(thread_info->data_mutex);
682 if(thread_info->interrupt_requested)
683 {
684 thread_info->interrupt_requested=false;
685 throw thread_interrupted();
686 }
687 }
688 #endif
689 }
690
691 bool interruption_enabled() BOOST_NOEXCEPT
692 {
693 boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data();
694 return thread_info && thread_info->interrupt_enabled;
695 }
696
697 bool interruption_requested() BOOST_NOEXCEPT
698 {
699 boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data();
700 if(!thread_info)
701 {
702 return false;
703 }
704 else
705 {
706 lock_guard<mutex> lg(thread_info->data_mutex);
707 return thread_info->interrupt_requested;
708 }
709 }
710
711 disable_interruption::disable_interruption() BOOST_NOEXCEPT:
712 interruption_was_enabled(interruption_enabled())
713 {
714 if(interruption_was_enabled)
715 {
716 detail::get_current_thread_data()->interrupt_enabled=false;
717 }
718 }
719
720 disable_interruption::~disable_interruption() BOOST_NOEXCEPT
721 {
722 if(detail::get_current_thread_data())
723 {
724 detail::get_current_thread_data()->interrupt_enabled=interruption_was_enabled;
725 }
726 }
727
728 restore_interruption::restore_interruption(disable_interruption& d) BOOST_NOEXCEPT
729 {
730 if(d.interruption_was_enabled)
731 {
732 detail::get_current_thread_data()->interrupt_enabled=true;
733 }
734 }
735
736 restore_interruption::~restore_interruption() BOOST_NOEXCEPT
737 {
738 if(detail::get_current_thread_data())
739 {
740 detail::get_current_thread_data()->interrupt_enabled=false;
741 }
742 }
743 }
744 #endif
745
746 namespace detail
747 {
748 void add_thread_exit_function(thread_exit_function_base* func)
749 {
750 detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
751 thread_exit_callback_node* const new_node=
752 heap_new<thread_exit_callback_node>(func,current_thread_data->thread_exit_callbacks);
753 current_thread_data->thread_exit_callbacks=new_node;
754 }
755
756 tss_data_node* find_tss_data(void const* key)
757 {
758 detail::thread_data_base* const current_thread_data(get_current_thread_data());
759 if(current_thread_data)
760 {
761 std::map<void const*,tss_data_node>::iterator current_node=
762 current_thread_data->tss_data.find(key);
763 if(current_node!=current_thread_data->tss_data.end())
764 {
765 return &current_node->second;
766 }
767 }
768 return 0;
769 }
770
771 void* get_tss_data(void const* key)
772 {
773 if(tss_data_node* const current_node=find_tss_data(key))
774 {
775 return current_node->value;
776 }
777 return 0;
778 }
779
780 void add_new_tss_node(void const* key,
781 boost::shared_ptr<tss_cleanup_function> func,
782 void* tss_data)
783 {
784 detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
785 current_thread_data->tss_data.insert(std::make_pair(key,tss_data_node(func,tss_data)));
786 }
787
788 void erase_tss_node(void const* key)
789 {
790 detail::thread_data_base* const current_thread_data(get_current_thread_data());
791 if(current_thread_data)
792 {
793 current_thread_data->tss_data.erase(key);
794 }
795 }
796
797 void set_tss_data(void const* key,
798 boost::shared_ptr<tss_cleanup_function> func,
799 void* tss_data,bool cleanup_existing)
800 {
801 if(tss_data_node* const current_node=find_tss_data(key))
802 {
803 if(cleanup_existing && current_node->func && (current_node->value!=0))
804 {
805 (*current_node->func)(current_node->value);
806 }
807 if(func || (tss_data!=0))
808 {
809 current_node->func=func;
810 current_node->value=tss_data;
811 }
812 else
813 {
814 erase_tss_node(key);
815 }
816 }
817 else if(func || (tss_data!=0))
818 {
819 add_new_tss_node(key,func,tss_data);
820 }
821 }
822 }
823
824 BOOST_THREAD_DECL void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk)
825 {
826 detail::thread_data_base* const current_thread_data(detail::get_current_thread_data());
827 if(current_thread_data)
828 {
829 current_thread_data->notify_all_at_thread_exit(&cond, lk.release());
830 }
831 }
832 namespace detail {
833
834 void BOOST_THREAD_DECL make_ready_at_thread_exit(shared_ptr<shared_state_base> as)
835 {
836 detail::thread_data_base* const current_thread_data(detail::get_current_thread_data());
837 if(current_thread_data)
838 {
839 current_thread_data->make_ready_at_thread_exit(as);
840 }
841 }
842 }
843
844
845
846 }