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