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 #include <boost/thread/pthread/pthread_helpers.hpp>
21 #include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
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 
32 #if defined(__VXWORKS__)
33 #include <vxCpuLib.h>
34 #endif
35 
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 
46 namespace boost
47 {
48     namespace detail
49     {
~thread_data_base()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             }
58 //#ifndef BOOST_NO_EXCEPTIONS
59             for (async_states_t::iterator i = async_states_.begin(), e = async_states_.end();
60                     i != e; ++i)
61             {
62                 (*i)->notify_deferred();
63             }
64 //#endif
65         }
66 
67         struct thread_exit_callback_node
68         {
69             boost::detail::thread_exit_function_base* func;
70             thread_exit_callback_node* next;
71 
thread_exit_callback_nodeboost::detail::thread_exit_callback_node72             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             {
tls_destructor(void * data)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                                 {
116                                     (*current->second.caller)(current->second.func,current->second.value);
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             {
delete_current_thread_tls_key_on_dlclose_tboost::detail::__anonb9b8fcaa0111::delete_current_thread_tls_key_on_dlclose_t129                 delete_current_thread_tls_key_on_dlclose_t()
130                 {
131                 }
~delete_current_thread_tls_key_on_dlclose_tboost::detail::__anonb9b8fcaa0111::delete_current_thread_tls_key_on_dlclose_t132                 ~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
create_current_thread_tls_key()146             void create_current_thread_tls_key()
147             {
148                 BOOST_VERIFY(!pthread_key_create(&current_thread_tls_key,&tls_destructor));
149             }
150         }
151 
get_current_thread_data()152         boost::detail::thread_data_base* get_current_thread_data()
153         {
154             boost::call_once(current_thread_tls_init_flag,&create_current_thread_tls_key);
155             return (boost::detail::thread_data_base*)pthread_getspecific(current_thread_tls_key);
156         }
157 
set_current_thread_data(detail::thread_data_base * new_data)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         {
thread_proxy(void * param)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         {
externally_launched_threadboost::detail::externally_launched_thread211             externally_launched_thread()
212             {
213 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
214                 interrupt_enabled=false;
215 #endif
216             }
~externally_launched_threadboost::detail::externally_launched_thread217             ~externally_launched_thread() {
218               BOOST_ASSERT(notify.empty());
219               notify.clear();
220 //#ifndef BOOST_NO_EXCEPTIONS
221               BOOST_ASSERT(async_states_.empty());
222               async_states_.clear();
223 //#endif
224             }
runboost::detail::externally_launched_thread225             void run()
226             {}
notify_all_at_thread_exitboost::detail::externally_launched_thread227             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 
make_external_thread_data()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 
get_or_make_current_thread_data()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 
thread()257     thread::thread() BOOST_NOEXCEPT
258     {}
259 
start_thread_noexcept()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 
start_thread_noexcept(const attributes & attr)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 
BOOST_PREVENT_MACRO_SUBSTITUTION() const310     detail::thread_data_ptr thread::get_thread_info BOOST_PREVENT_MACRO_SUBSTITUTION () const
311     {
312         return thread_info;
313     }
314 
join_noexcept()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 
do_try_join_until_noexcept(detail::internal_platform_timepoint const & timeout,bool & res)363     bool thread::do_try_join_until_noexcept(detail::internal_platform_timepoint const &timeout, bool& res)
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                 {
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;
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 
joinable() const417     bool thread::joinable() const BOOST_NOEXCEPT
418     {
419         return (get_thread_info)()?true:false;
420     }
421 
422 
detach()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         {
sleep_for_internal(const detail::platform_duration & ts)446           void BOOST_THREAD_DECL sleep_for_internal(const detail::platform_duration& ts)
447           {
448                 if (ts > detail::platform_duration::zero())
449                 {
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.
452     #   if defined(BOOST_HAS_PTHREAD_DELAY_NP)
453     #     if defined(__IBMCPP__) ||  defined(_AIX)
454                   BOOST_VERIFY(!pthread_delay_np(const_cast<timespec*>(&ts.getTs())));
455     #     else
456                   BOOST_VERIFY(!pthread_delay_np(&ts.getTs()));
457     #     endif
458     #   elif defined(BOOST_HAS_NANOSLEEP)
459                   nanosleep(&ts.getTs(), 0);
460     #   else
461                   // This should never be reached due to BOOST_THREAD_SLEEP_FOR_IS_STEADY
462     #   endif
463                 }
464           }
465         }
466       }
467 
yield()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
475 //            ::boost::xtime xt;
476 //            xtime_get(&xt, TIME_UTC_);
477 //            sleep(xt);
478 //            sleep_for(chrono::milliseconds(0));
479 #   else
480             mutex mx;
481             unique_lock<mutex> lock(mx);
482             condition_variable cond;
483             cond.do_wait_until(lock, detail::internal_platform_clock::now());
484 #   endif
485         }
486     }
hardware_concurrency()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;
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);
507   #else
508         return (__builtin_popcount(set) );
509   #endif
510 #elif defined(__GLIBC__)
511         return get_nprocs();
512 #else
513         return 0;
514 #endif
515     }
516 
physical_concurrency()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
interrupt()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);
586                 BOOST_VERIFY(!posix::pthread_cond_broadcast(local_thread_info->current_cond));
587             }
588         }
589     }
590 
interruption_requested() const591     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 
native_handle()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     {
interruption_point()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 
interruption_enabled()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 
interruption_requested()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 
disable_interruption()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 
~disable_interruption()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 
restore_interruption(disable_interruption & d)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 
~restore_interruption()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     {
add_thread_exit_function(thread_exit_function_base * func)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 
find_tss_data(void const * key)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 
get_tss_data(void const * key)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 
add_new_tss_node(void const * key,detail::tss_data_node::cleanup_caller_t caller,detail::tss_data_node::cleanup_func_t func,void * tss_data)730         void add_new_tss_node(void const* key,
731                               detail::tss_data_node::cleanup_caller_t caller,
732                               detail::tss_data_node::cleanup_func_t func,
733                               void* tss_data)
734         {
735             detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
736             current_thread_data->tss_data.insert(std::make_pair(key,tss_data_node(caller,func,tss_data)));
737         }
738 
erase_tss_node(void const * key)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 
set_tss_data(void const * key,detail::tss_data_node::cleanup_caller_t caller,detail::tss_data_node::cleanup_func_t func,void * tss_data,bool cleanup_existing)748         void set_tss_data(void const* key,
749                           detail::tss_data_node::cleanup_caller_t caller,
750                           detail::tss_data_node::cleanup_func_t func,
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                 {
757                     (*current_node->caller)(current_node->func,current_node->value);
758                 }
759                 if(func || (tss_data!=0))
760                 {
761                     current_node->caller=caller;
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             {
772                 add_new_tss_node(key,caller,func,tss_data);
773             }
774         }
775     }
776 
notify_all_at_thread_exit(condition_variable & cond,unique_lock<mutex> lk)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     }
785 
786 //#ifndef BOOST_NO_EXCEPTIONS
787 namespace detail {
788 
make_ready_at_thread_exit(shared_ptr<shared_state_base> as)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 }
798 //#endif
799 
800 
801 }
802