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 
39 namespace boost
40 {
41     namespace detail
42     {
~thread_data_base()43         thread_data_base::~thread_data_base()
44         {
45             for (notify_list_t::iterator i = notify.begin(), e = notify.end();
46                     i != e; ++i)
47             {
48                 i->second->unlock();
49                 i->first->notify_all();
50             }
51             for (async_states_t::iterator i = async_states_.begin(), e = async_states_.end();
52                     i != e; ++i)
53             {
54                 (*i)->make_ready();
55             }
56         }
57 
58         struct thread_exit_callback_node
59         {
60             boost::detail::thread_exit_function_base* func;
61             thread_exit_callback_node* next;
62 
thread_exit_callback_nodeboost::detail::thread_exit_callback_node63             thread_exit_callback_node(boost::detail::thread_exit_function_base* func_,
64                                       thread_exit_callback_node* next_):
65                 func(func_),next(next_)
66             {}
67         };
68 
69         namespace
70         {
71 #ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11
72           boost::once_flag current_thread_tls_init_flag;
73 #else
74             boost::once_flag current_thread_tls_init_flag=BOOST_ONCE_INIT;
75 #endif
76             pthread_key_t current_thread_tls_key;
77 
78             extern "C"
79             {
tls_destructor(void * data)80                 static void tls_destructor(void* data)
81                 {
82                     boost::detail::thread_data_base* thread_info=static_cast<boost::detail::thread_data_base*>(data);
83                     if(thread_info)
84                     {
85                         while(!thread_info->tss_data.empty() || thread_info->thread_exit_callbacks)
86                         {
87 
88                             while(thread_info->thread_exit_callbacks)
89                             {
90                                 detail::thread_exit_callback_node* const current_node=thread_info->thread_exit_callbacks;
91                                 thread_info->thread_exit_callbacks=current_node->next;
92                                 if(current_node->func)
93                                 {
94                                     (*current_node->func)();
95                                     delete current_node->func;
96                                 }
97                                 delete current_node;
98                             }
99                             while (!thread_info->tss_data.empty())
100                             {
101                                 std::map<void const*,detail::tss_data_node>::iterator current
102                                     = thread_info->tss_data.begin();
103                                 if(current->second.func && (current->second.value!=0))
104                                 {
105                                     (*current->second.func)(current->second.value);
106                                 }
107                                 thread_info->tss_data.erase(current);
108                             }
109                         }
110                         if (thread_info) // fixme: should we test this?
111                         {
112                           thread_info->self.reset();
113                         }
114                     }
115                 }
116             }
117 
118 #if defined BOOST_THREAD_PATCH
119 
120             struct  delete_current_thread_tls_key_on_dlclose_t
121             {
delete_current_thread_tls_key_on_dlclose_tboost::detail::__anon49c42e810111::delete_current_thread_tls_key_on_dlclose_t122                 delete_current_thread_tls_key_on_dlclose_t()
123                 {
124                 }
~delete_current_thread_tls_key_on_dlclose_tboost::detail::__anon49c42e810111::delete_current_thread_tls_key_on_dlclose_t125                 ~delete_current_thread_tls_key_on_dlclose_t()
126                 {
127                     if (current_thread_tls_init_flag.epoch!=BOOST_ONCE_INITIAL_FLAG_VALUE)
128                     {
129                         pthread_key_delete(current_thread_tls_key);
130                     }
131                 }
132             };
133             delete_current_thread_tls_key_on_dlclose_t delete_current_thread_tls_key_on_dlclose;
134 #endif
135 
create_current_thread_tls_key()136             void create_current_thread_tls_key()
137             {
138                 BOOST_VERIFY(!pthread_key_create(&current_thread_tls_key,&tls_destructor));
139             }
140         }
141 
get_current_thread_data()142         boost::detail::thread_data_base* get_current_thread_data()
143         {
144             boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key);
145             return (boost::detail::thread_data_base*)pthread_getspecific(current_thread_tls_key);
146         }
147 
set_current_thread_data(detail::thread_data_base * new_data)148         void set_current_thread_data(detail::thread_data_base* new_data)
149         {
150             boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key);
151             BOOST_VERIFY(!pthread_setspecific(current_thread_tls_key,new_data));
152         }
153     }
154 
155     namespace
156     {
157         extern "C"
158         {
thread_proxy(void * param)159             static void* thread_proxy(void* param)
160             {
161                 boost::detail::thread_data_ptr thread_info = static_cast<boost::detail::thread_data_base*>(param)->self;
162                 //thread_info->self.reset();
163                 detail::set_current_thread_data(thread_info.get());
164 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
165                 BOOST_TRY
166                 {
167 #endif
168                     thread_info->run();
169 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
170 
171                 }
172                 BOOST_CATCH (thread_interrupted const&)
173                 {
174                 }
175 // Removed as it stops the debugger identifying the cause of the exception
176 // Unhandled exceptions still cause the application to terminate
177 //                 BOOST_CATCH(...)
178 //                 {
179 //                   throw;
180 //
181 //                     std::terminate();
182 //                 }
183                 BOOST_CATCH_END
184 #endif
185                 detail::tls_destructor(thread_info.get());
186                 detail::set_current_thread_data(0);
187                 boost::lock_guard<boost::mutex> lock(thread_info->data_mutex);
188                 thread_info->done=true;
189                 thread_info->done_condition.notify_all();
190 
191                 return 0;
192             }
193         }
194     }
195     namespace detail
196     {
197         struct externally_launched_thread:
198             detail::thread_data_base
199         {
externally_launched_threadboost::detail::externally_launched_thread200             externally_launched_thread()
201             {
202 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
203                 interrupt_enabled=false;
204 #endif
205             }
~externally_launched_threadboost::detail::externally_launched_thread206             ~externally_launched_thread() {
207               BOOST_ASSERT(notify.empty());
208               notify.clear();
209               BOOST_ASSERT(async_states_.empty());
210               async_states_.clear();
211             }
runboost::detail::externally_launched_thread212             void run()
213             {}
notify_all_at_thread_exitboost::detail::externally_launched_thread214             void notify_all_at_thread_exit(condition_variable*, mutex*)
215             {}
216 
217         private:
218             externally_launched_thread(externally_launched_thread&);
219             void operator=(externally_launched_thread&);
220         };
221 
make_external_thread_data()222         thread_data_base* make_external_thread_data()
223         {
224             thread_data_base* const me(detail::heap_new<externally_launched_thread>());
225             me->self.reset(me);
226             set_current_thread_data(me);
227             return me;
228         }
229 
230 
get_or_make_current_thread_data()231         thread_data_base* get_or_make_current_thread_data()
232         {
233             thread_data_base* current_thread_data(get_current_thread_data());
234             if(!current_thread_data)
235             {
236                 current_thread_data=make_external_thread_data();
237             }
238             return current_thread_data;
239         }
240 
241     }
242 
243 
thread()244     thread::thread() BOOST_NOEXCEPT
245     {}
246 
start_thread_noexcept()247     bool thread::start_thread_noexcept()
248     {
249         thread_info->self=thread_info;
250         int const res = pthread_create(&thread_info->thread_handle, 0, &thread_proxy, thread_info.get());
251         if (res != 0)
252         {
253             thread_info->self.reset();
254             return false;
255 //            boost::throw_exception(thread_resource_error(res, "boost thread: failed in pthread_create"));
256         }
257         return true;
258     }
259 
start_thread_noexcept(const attributes & attr)260     bool thread::start_thread_noexcept(const attributes& attr)
261     {
262         thread_info->self=thread_info;
263         const attributes::native_handle_type* h = attr.native_handle();
264         int res = pthread_create(&thread_info->thread_handle, h, &thread_proxy, thread_info.get());
265         if (res != 0)
266         {
267             thread_info->self.reset();
268             return false;
269 //            boost::throw_exception(thread_resource_error(res, "boost thread: failed in pthread_create"));
270         }
271         int detached_state;
272         res = pthread_attr_getdetachstate(h, &detached_state);
273         if (res != 0)
274         {
275             thread_info->self.reset();
276             return false;
277 //            boost::throw_exception(thread_resource_error(res, "boost thread: failed in pthread_attr_getdetachstate"));
278         }
279         if (PTHREAD_CREATE_DETACHED==detached_state)
280         {
281           detail::thread_data_ptr local_thread_info;
282           thread_info.swap(local_thread_info);
283 
284           if(local_thread_info)
285           {
286               //lock_guard<mutex> lock(local_thread_info->data_mutex);
287               if(!local_thread_info->join_started)
288               {
289                   //BOOST_VERIFY(!pthread_detach(local_thread_info->thread_handle));
290                   local_thread_info->join_started=true;
291                   local_thread_info->joined=true;
292               }
293           }
294         }
295         return true;
296     }
297 
298 
299 
BOOST_PREVENT_MACRO_SUBSTITUTION() const300     detail::thread_data_ptr thread::get_thread_info BOOST_PREVENT_MACRO_SUBSTITUTION () const
301     {
302         return thread_info;
303     }
304 
join_noexcept()305     bool thread::join_noexcept()
306     {
307         detail::thread_data_ptr const local_thread_info=(get_thread_info)();
308         if(local_thread_info)
309         {
310             bool do_join=false;
311 
312             {
313                 unique_lock<mutex> lock(local_thread_info->data_mutex);
314                 while(!local_thread_info->done)
315                 {
316                     local_thread_info->done_condition.wait(lock);
317                 }
318                 do_join=!local_thread_info->join_started;
319 
320                 if(do_join)
321                 {
322                     local_thread_info->join_started=true;
323                 }
324                 else
325                 {
326                     while(!local_thread_info->joined)
327                     {
328                         local_thread_info->done_condition.wait(lock);
329                     }
330                 }
331             }
332             if(do_join)
333             {
334                 void* result=0;
335                 BOOST_VERIFY(!pthread_join(local_thread_info->thread_handle,&result));
336                 lock_guard<mutex> lock(local_thread_info->data_mutex);
337                 local_thread_info->joined=true;
338                 local_thread_info->done_condition.notify_all();
339             }
340 
341             if(thread_info==local_thread_info)
342             {
343                 thread_info.reset();
344             }
345             return true;
346         }
347         else
348         {
349           return false;
350         }
351     }
352 
do_try_join_until_noexcept(struct timespec const & timeout,bool & res)353     bool thread::do_try_join_until_noexcept(struct timespec const &timeout, bool& res)
354     {
355         detail::thread_data_ptr const local_thread_info=(get_thread_info)();
356         if(local_thread_info)
357         {
358             bool do_join=false;
359 
360             {
361                 unique_lock<mutex> lock(local_thread_info->data_mutex);
362                 while(!local_thread_info->done)
363                 {
364                     if(!local_thread_info->done_condition.do_wait_until(lock,timeout))
365                     {
366                       res=false;
367                       return true;
368                     }
369                 }
370                 do_join=!local_thread_info->join_started;
371 
372                 if(do_join)
373                 {
374                     local_thread_info->join_started=true;
375                 }
376                 else
377                 {
378                     while(!local_thread_info->joined)
379                     {
380                         local_thread_info->done_condition.wait(lock);
381                     }
382                 }
383             }
384             if(do_join)
385             {
386                 void* result=0;
387                 BOOST_VERIFY(!pthread_join(local_thread_info->thread_handle,&result));
388                 lock_guard<mutex> lock(local_thread_info->data_mutex);
389                 local_thread_info->joined=true;
390                 local_thread_info->done_condition.notify_all();
391             }
392 
393             if(thread_info==local_thread_info)
394             {
395                 thread_info.reset();
396             }
397             res=true;
398             return true;
399         }
400         else
401         {
402           return false;
403         }
404     }
405 
joinable() const406     bool thread::joinable() const BOOST_NOEXCEPT
407     {
408         return (get_thread_info)()?true:false;
409     }
410 
411 
detach()412     void thread::detach()
413     {
414         detail::thread_data_ptr local_thread_info;
415         thread_info.swap(local_thread_info);
416 
417         if(local_thread_info)
418         {
419             lock_guard<mutex> lock(local_thread_info->data_mutex);
420             if(!local_thread_info->join_started)
421             {
422                 BOOST_VERIFY(!pthread_detach(local_thread_info->thread_handle));
423                 local_thread_info->join_started=true;
424                 local_thread_info->joined=true;
425             }
426         }
427     }
428 
429     namespace this_thread
430     {
431       namespace no_interruption_point
432       {
433         namespace hiden
434         {
sleep_for(const timespec & ts)435           void BOOST_THREAD_DECL sleep_for(const timespec& ts)
436           {
437 
438                 if (boost::detail::timespec_ge(ts, boost::detail::timespec_zero()))
439                 {
440 
441     #   if defined(BOOST_HAS_PTHREAD_DELAY_NP)
442     #     if defined(__IBMCPP__) ||  defined(_AIX)
443                   BOOST_VERIFY(!pthread_delay_np(const_cast<timespec*>(&ts)));
444     #     else
445                   BOOST_VERIFY(!pthread_delay_np(&ts));
446     #     endif
447     #   elif defined(BOOST_HAS_NANOSLEEP)
448                   //  nanosleep takes a timespec that is an offset, not
449                   //  an absolute time.
450                   nanosleep(&ts, 0);
451     #   else
452                   mutex mx;
453                   unique_lock<mutex> lock(mx);
454                   condition_variable cond;
455                   cond.do_wait_for(lock, ts);
456     #   endif
457                 }
458           }
459 
sleep_until(const timespec & ts)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 hiden
494       {
sleep_for(const timespec & ts)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::hiden::sleep_for(ts);
507             }
508         }
509 
sleep_until(const timespec & ts)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::hiden::sleep_until(ts);
522             }
523         }
524       } // hiden
525     } // this_thread
526 
527     namespace this_thread
528     {
yield()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             hiden::sleep_for(ts);
546 #   endif
547         }
548     }
hardware_concurrency()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 
physical_concurrency()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
interrupt()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 
interruption_requested() const641     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 
native_handle()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     {
interruption_point()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 
interruption_enabled()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 
interruption_requested()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 
disable_interruption()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 
~disable_interruption()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 
restore_interruption(disable_interruption & d)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 
~restore_interruption()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     {
add_thread_exit_function(thread_exit_function_base * func)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 
find_tss_data(void const * key)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 
get_tss_data(void const * key)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 
add_new_tss_node(void const * key,boost::shared_ptr<tss_cleanup_function> func,void * tss_data)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 
erase_tss_node(void const * key)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 
set_tss_data(void const * key,boost::shared_ptr<tss_cleanup_function> func,void * tss_data,bool cleanup_existing)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 
notify_all_at_thread_exit(condition_variable & cond,unique_lock<mutex> lk)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 
make_ready_at_thread_exit(shared_ptr<shared_state_base> as)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 }
847