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