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)->make_ready();
56             }
57         }
58 
59         struct thread_exit_callback_node
60         {
61             boost::detail::thread_exit_function_base* func;
62             thread_exit_callback_node* next;
63 
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 // MONGODB Modification - revert to Boost 1.59 behavior, and do not delete TLS keys.
120 // This prevents ASAN leaks in unit tests by giving us a chance to free the TLS slots on the main
121 // thread.
122 //
123 // Here is how the leak works:
124 // 1. create_current_thread_tls_key allocates a pthread key.
125 // 2. during process shutdown, libc calls atexit handlers.
126 //    a. delete_current_thread_tls_key_on_dlclose_t::~ delete_current_thread_tls_key_on_dlclose_t
127 //       is called, and deletes the pthread key.
128 //    b. thread_specific_ptr::~thread_specific_ptr is called which calls set_tss_data, and this
129 //       uses the pthread key to get the actual data to destroy. Since the pthread key has been
130 //       deallocated, pthread_getspecific returns null, and memory is leaked.
131 //
132 // See https://github.com/boostorg/thread/blob/boost-1.59.0/src/pthread/thread.cpp#L118-L134
133 // and https://github.com/boostorg/thread/commit/242cf35c519fc886c13789f1f9a049571fde4cdc#diff-d70e9675395ed66968d044fcfaa862b7
134             struct  delete_current_thread_tls_key_on_dlclose_t
135             {
delete_current_thread_tls_key_on_dlclose_tboost::detail::__anon8cc0c3df0111::delete_current_thread_tls_key_on_dlclose_t136                 delete_current_thread_tls_key_on_dlclose_t()
137                 {
138                 }
~delete_current_thread_tls_key_on_dlclose_tboost::detail::__anon8cc0c3df0111::delete_current_thread_tls_key_on_dlclose_t139                 ~delete_current_thread_tls_key_on_dlclose_t()
140                 {
141                     const boost::once_flag uninitialized = BOOST_ONCE_INIT;
142                     if (memcmp(&current_thread_tls_init_flag, &uninitialized, sizeof(boost::once_flag)))
143                     {
144                         pthread_key_delete(current_thread_tls_key);
145                     }
146                 }
147             };
148             delete_current_thread_tls_key_on_dlclose_t delete_current_thread_tls_key_on_dlclose;
149 #endif
150 
create_current_thread_tls_key()151             void create_current_thread_tls_key()
152             {
153                 BOOST_VERIFY(!pthread_key_create(&current_thread_tls_key,&tls_destructor));
154             }
155         }
156 
get_current_thread_data()157         boost::detail::thread_data_base* get_current_thread_data()
158         {
159             boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key);
160             return (boost::detail::thread_data_base*)pthread_getspecific(current_thread_tls_key);
161         }
162 
set_current_thread_data(detail::thread_data_base * new_data)163         void set_current_thread_data(detail::thread_data_base* new_data)
164         {
165             boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key);
166             BOOST_VERIFY(!pthread_setspecific(current_thread_tls_key,new_data));
167         }
168     }
169 
170     namespace
171     {
172         extern "C"
173         {
thread_proxy(void * param)174             static void* thread_proxy(void* param)
175             {
176                 //boost::detail::thread_data_ptr thread_info = static_cast<boost::detail::thread_data_base*>(param)->self;
177                 boost::detail::thread_data_ptr thread_info = static_cast<boost::detail::thread_data_base*>(param)->shared_from_this();
178                 thread_info->self.reset();
179                 detail::set_current_thread_data(thread_info.get());
180 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
181                 BOOST_TRY
182                 {
183 #endif
184                     thread_info->run();
185 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
186 
187                 }
188                 BOOST_CATCH (thread_interrupted const&)
189                 {
190                 }
191 // Removed as it stops the debugger identifying the cause of the exception
192 // Unhandled exceptions still cause the application to terminate
193 //                 BOOST_CATCH(...)
194 //                 {
195 //                   throw;
196 //
197 //                     std::terminate();
198 //                 }
199                 BOOST_CATCH_END
200 #endif
201                 detail::tls_destructor(thread_info.get());
202                 detail::set_current_thread_data(0);
203                 boost::lock_guard<boost::mutex> lock(thread_info->data_mutex);
204                 thread_info->done=true;
205                 thread_info->done_condition.notify_all();
206 
207                 return 0;
208             }
209         }
210     }
211     namespace detail
212     {
213         struct externally_launched_thread:
214             detail::thread_data_base
215         {
externally_launched_threadboost::detail::externally_launched_thread216             externally_launched_thread()
217             {
218 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
219                 interrupt_enabled=false;
220 #endif
221             }
~externally_launched_threadboost::detail::externally_launched_thread222             ~externally_launched_thread() {
223               BOOST_ASSERT(notify.empty());
224               notify.clear();
225               BOOST_ASSERT(async_states_.empty());
226               async_states_.clear();
227             }
runboost::detail::externally_launched_thread228             void run()
229             {}
notify_all_at_thread_exitboost::detail::externally_launched_thread230             void notify_all_at_thread_exit(condition_variable*, mutex*)
231             {}
232 
233         private:
234             externally_launched_thread(externally_launched_thread&);
235             void operator=(externally_launched_thread&);
236         };
237 
make_external_thread_data()238         thread_data_base* make_external_thread_data()
239         {
240             thread_data_base* const me(detail::heap_new<externally_launched_thread>());
241             me->self.reset(me);
242             set_current_thread_data(me);
243             return me;
244         }
245 
246 
get_or_make_current_thread_data()247         thread_data_base* get_or_make_current_thread_data()
248         {
249             thread_data_base* current_thread_data(get_current_thread_data());
250             if(!current_thread_data)
251             {
252                 current_thread_data=make_external_thread_data();
253             }
254             return current_thread_data;
255         }
256 
257     }
258 
259 
thread()260     thread::thread() BOOST_NOEXCEPT
261     {}
262 
start_thread_noexcept()263     bool thread::start_thread_noexcept()
264     {
265         thread_info->self=thread_info;
266         int const res = pthread_create(&thread_info->thread_handle, 0, &thread_proxy, thread_info.get());
267         if (res != 0)
268         {
269             thread_info->self.reset();
270             return false;
271         }
272         return true;
273     }
274 
start_thread_noexcept(const attributes & attr)275     bool thread::start_thread_noexcept(const attributes& attr)
276     {
277         thread_info->self=thread_info;
278         const attributes::native_handle_type* h = attr.native_handle();
279         int res = pthread_create(&thread_info->thread_handle, h, &thread_proxy, thread_info.get());
280         if (res != 0)
281         {
282             thread_info->self.reset();
283             return false;
284         }
285         int detached_state;
286         res = pthread_attr_getdetachstate(h, &detached_state);
287         if (res != 0)
288         {
289             thread_info->self.reset();
290             return false;
291         }
292         if (PTHREAD_CREATE_DETACHED==detached_state)
293         {
294           detail::thread_data_ptr local_thread_info;
295           thread_info.swap(local_thread_info);
296 
297           if(local_thread_info)
298           {
299               //lock_guard<mutex> lock(local_thread_info->data_mutex);
300               if(!local_thread_info->join_started)
301               {
302                   //BOOST_VERIFY(!pthread_detach(local_thread_info->thread_handle));
303                   local_thread_info->join_started=true;
304                   local_thread_info->joined=true;
305               }
306           }
307         }
308         return true;
309     }
310 
311 
312 
BOOST_PREVENT_MACRO_SUBSTITUTION() const313     detail::thread_data_ptr thread::get_thread_info BOOST_PREVENT_MACRO_SUBSTITUTION () const
314     {
315         return thread_info;
316     }
317 
join_noexcept()318     bool thread::join_noexcept()
319     {
320         detail::thread_data_ptr const local_thread_info=(get_thread_info)();
321         if(local_thread_info)
322         {
323             bool do_join=false;
324 
325             {
326                 unique_lock<mutex> lock(local_thread_info->data_mutex);
327                 while(!local_thread_info->done)
328                 {
329                     local_thread_info->done_condition.wait(lock);
330                 }
331                 do_join=!local_thread_info->join_started;
332 
333                 if(do_join)
334                 {
335                     local_thread_info->join_started=true;
336                 }
337                 else
338                 {
339                     while(!local_thread_info->joined)
340                     {
341                         local_thread_info->done_condition.wait(lock);
342                     }
343                 }
344             }
345             if(do_join)
346             {
347                 void* result=0;
348                 BOOST_VERIFY(!pthread_join(local_thread_info->thread_handle,&result));
349                 lock_guard<mutex> lock(local_thread_info->data_mutex);
350                 local_thread_info->joined=true;
351                 local_thread_info->done_condition.notify_all();
352             }
353 
354             if(thread_info==local_thread_info)
355             {
356                 thread_info.reset();
357             }
358             return true;
359         }
360         else
361         {
362           return false;
363         }
364     }
365 
do_try_join_until_noexcept(struct timespec const & timeout,bool & res)366     bool thread::do_try_join_until_noexcept(struct timespec const &timeout, bool& res)
367     {
368         detail::thread_data_ptr const local_thread_info=(get_thread_info)();
369         if(local_thread_info)
370         {
371             bool do_join=false;
372 
373             {
374                 unique_lock<mutex> lock(local_thread_info->data_mutex);
375                 while(!local_thread_info->done)
376                 {
377                     if(!local_thread_info->done_condition.do_wait_until(lock,timeout))
378                     {
379                       res=false;
380                       return true;
381                     }
382                 }
383                 do_join=!local_thread_info->join_started;
384 
385                 if(do_join)
386                 {
387                     local_thread_info->join_started=true;
388                 }
389                 else
390                 {
391                     while(!local_thread_info->joined)
392                     {
393                         local_thread_info->done_condition.wait(lock);
394                     }
395                 }
396             }
397             if(do_join)
398             {
399                 void* result=0;
400                 BOOST_VERIFY(!pthread_join(local_thread_info->thread_handle,&result));
401                 lock_guard<mutex> lock(local_thread_info->data_mutex);
402                 local_thread_info->joined=true;
403                 local_thread_info->done_condition.notify_all();
404             }
405 
406             if(thread_info==local_thread_info)
407             {
408                 thread_info.reset();
409             }
410             res=true;
411             return true;
412         }
413         else
414         {
415           return false;
416         }
417     }
418 
joinable() const419     bool thread::joinable() const BOOST_NOEXCEPT
420     {
421         return (get_thread_info)()?true:false;
422     }
423 
424 
detach()425     void thread::detach()
426     {
427         detail::thread_data_ptr local_thread_info;
428         thread_info.swap(local_thread_info);
429 
430         if(local_thread_info)
431         {
432             lock_guard<mutex> lock(local_thread_info->data_mutex);
433             if(!local_thread_info->join_started)
434             {
435                 BOOST_VERIFY(!pthread_detach(local_thread_info->thread_handle));
436                 local_thread_info->join_started=true;
437                 local_thread_info->joined=true;
438             }
439         }
440     }
441 
442     namespace this_thread
443     {
444       namespace no_interruption_point
445       {
446         namespace hiden
447         {
sleep_for(const timespec & ts)448           void BOOST_THREAD_DECL sleep_for(const timespec& ts)
449           {
450 
451                 if (boost::detail::timespec_ge(ts, boost::detail::timespec_zero()))
452                 {
453 
454     #   if defined(BOOST_HAS_PTHREAD_DELAY_NP)
455     #     if defined(__IBMCPP__) ||  defined(_AIX)
456                   BOOST_VERIFY(!pthread_delay_np(const_cast<timespec*>(&ts)));
457     #     else
458                   BOOST_VERIFY(!pthread_delay_np(&ts));
459     #     endif
460     #   elif defined(BOOST_HAS_NANOSLEEP)
461                   //  nanosleep takes a timespec that is an offset, not
462                   //  an absolute time.
463                   nanosleep(&ts, 0);
464     #   else
465                   mutex mx;
466                   unique_lock<mutex> lock(mx);
467                   condition_variable cond;
468                   cond.do_wait_for(lock, ts);
469     #   endif
470                 }
471           }
472 
sleep_until(const timespec & ts)473           void BOOST_THREAD_DECL sleep_until(const timespec& ts)
474           {
475                 timespec now = boost::detail::timespec_now();
476                 if (boost::detail::timespec_gt(ts, now))
477                 {
478                   for (int foo=0; foo < 5; ++foo)
479                   {
480 
481     #   if defined(BOOST_HAS_PTHREAD_DELAY_NP)
482                     timespec d = boost::detail::timespec_minus(ts, now);
483                     BOOST_VERIFY(!pthread_delay_np(&d));
484     #   elif defined(BOOST_HAS_NANOSLEEP)
485                     //  nanosleep takes a timespec that is an offset, not
486                     //  an absolute time.
487                     timespec d = boost::detail::timespec_minus(ts, now);
488                     nanosleep(&d, 0);
489     #   else
490                     mutex mx;
491                     unique_lock<mutex> lock(mx);
492                     condition_variable cond;
493                     cond.do_wait_until(lock, ts);
494     #   endif
495                     timespec now2 = boost::detail::timespec_now();
496                     if (boost::detail::timespec_ge(now2, ts))
497                     {
498                       return;
499                     }
500                   }
501                 }
502           }
503 
504         }
505       }
506       namespace hiden
507       {
sleep_for(const timespec & ts)508         void BOOST_THREAD_DECL sleep_for(const timespec& ts)
509         {
510             boost::detail::thread_data_base* const thread_info=boost::detail::get_current_thread_data();
511 
512             if(thread_info)
513             {
514               unique_lock<mutex> lk(thread_info->sleep_mutex);
515               while( thread_info->sleep_condition.do_wait_for(lk,ts)) {}
516             }
517             else
518             {
519               boost::this_thread::no_interruption_point::hiden::sleep_for(ts);
520             }
521         }
522 
sleep_until(const timespec & ts)523         void BOOST_THREAD_DECL sleep_until(const timespec& ts)
524         {
525             boost::detail::thread_data_base* const thread_info=boost::detail::get_current_thread_data();
526 
527             if(thread_info)
528             {
529               unique_lock<mutex> lk(thread_info->sleep_mutex);
530               while(thread_info->sleep_condition.do_wait_until(lk,ts)) {}
531             }
532             else
533             {
534               boost::this_thread::no_interruption_point::hiden::sleep_until(ts);
535             }
536         }
537       } // hiden
538     } // this_thread
539 
540     namespace this_thread
541     {
yield()542         void yield() BOOST_NOEXCEPT
543         {
544 #   if defined(BOOST_HAS_SCHED_YIELD)
545             BOOST_VERIFY(!sched_yield());
546 #   elif defined(BOOST_HAS_PTHREAD_YIELD)
547             BOOST_VERIFY(!pthread_yield());
548 //#   elif defined BOOST_THREAD_USES_DATETIME
549 //            xtime xt;
550 //            xtime_get(&xt, TIME_UTC_);
551 //            sleep(xt);
552 //            sleep_for(chrono::milliseconds(0));
553 #   else
554 #error
555             timespec ts;
556             ts.tv_sec= 0;
557             ts.tv_nsec= 0;
558             hiden::sleep_for(ts);
559 #   endif
560         }
561     }
hardware_concurrency()562     unsigned thread::hardware_concurrency() BOOST_NOEXCEPT
563     {
564 #if defined(PTW32_VERSION) || defined(__hpux)
565         return pthread_num_processors_np();
566 #elif defined(__APPLE__) || defined(__FreeBSD__)
567         int count;
568         size_t size=sizeof(count);
569         return sysctlbyname("hw.ncpu",&count,&size,NULL,0)?0:count;
570 #elif defined(BOOST_HAS_UNISTD_H) && defined(_SC_NPROCESSORS_ONLN)
571         int const count=sysconf(_SC_NPROCESSORS_ONLN);
572         return (count>0)?count:0;
573 #elif defined(__GLIBC__)
574         return get_nprocs();
575 #else
576         return 0;
577 #endif
578     }
579 
physical_concurrency()580     unsigned thread::physical_concurrency() BOOST_NOEXCEPT
581     {
582 #ifdef __linux__
583         try {
584             using namespace std;
585 
586             ifstream proc_cpuinfo ("/proc/cpuinfo");
587 
588             const string physical_id("physical id"), core_id("core id");
589 
590             typedef std::pair<unsigned, unsigned> core_entry; // [physical ID, core id]
591 
592             std::set<core_entry> cores;
593 
594             core_entry current_core_entry;
595 
596             string line;
597             while ( getline(proc_cpuinfo, line) ) {
598                 if (line.empty())
599                     continue;
600 
601                 vector<string> key_val(2);
602                 boost::split(key_val, line, boost::is_any_of(":"));
603 
604                 if (key_val.size() != 2)
605                   return hardware_concurrency();
606 
607                 string key   = key_val[0];
608                 string value = key_val[1];
609                 boost::trim(key);
610                 boost::trim(value);
611 
612                 if (key == physical_id) {
613                     current_core_entry.first = boost::lexical_cast<unsigned>(value);
614                     continue;
615                 }
616 
617                 if (key == core_id) {
618                     current_core_entry.second = boost::lexical_cast<unsigned>(value);
619                     cores.insert(current_core_entry);
620                     continue;
621                 }
622             }
623             // Fall back to hardware_concurrency() in case
624             // /proc/cpuinfo is formatted differently than we expect.
625             return cores.size() != 0 ? cores.size() : hardware_concurrency();
626         } catch(...) {
627           return hardware_concurrency();
628         }
629 #elif defined(__APPLE__)
630         int count;
631         size_t size=sizeof(count);
632         return sysctlbyname("hw.physicalcpu",&count,&size,NULL,0)?0:count;
633 #else
634         return hardware_concurrency();
635 #endif
636     }
637 
638 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
interrupt()639     void thread::interrupt()
640     {
641         detail::thread_data_ptr const local_thread_info=(get_thread_info)();
642         if(local_thread_info)
643         {
644             lock_guard<mutex> lk(local_thread_info->data_mutex);
645             local_thread_info->interrupt_requested=true;
646             if(local_thread_info->current_cond)
647             {
648                 boost::pthread::pthread_mutex_scoped_lock internal_lock(local_thread_info->cond_mutex);
649                 BOOST_VERIFY(!pthread_cond_broadcast(local_thread_info->current_cond));
650             }
651         }
652     }
653 
interruption_requested() const654     bool thread::interruption_requested() const BOOST_NOEXCEPT
655     {
656         detail::thread_data_ptr const local_thread_info=(get_thread_info)();
657         if(local_thread_info)
658         {
659             lock_guard<mutex> lk(local_thread_info->data_mutex);
660             return local_thread_info->interrupt_requested;
661         }
662         else
663         {
664             return false;
665         }
666     }
667 #endif
668 
native_handle()669     thread::native_handle_type thread::native_handle()
670     {
671         detail::thread_data_ptr const local_thread_info=(get_thread_info)();
672         if(local_thread_info)
673         {
674             lock_guard<mutex> lk(local_thread_info->data_mutex);
675             return local_thread_info->thread_handle;
676         }
677         else
678         {
679             return pthread_t();
680         }
681     }
682 
683 
684 
685 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
686     namespace this_thread
687     {
interruption_point()688         void interruption_point()
689         {
690 #ifndef BOOST_NO_EXCEPTIONS
691             boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data();
692             if(thread_info && thread_info->interrupt_enabled)
693             {
694                 lock_guard<mutex> lg(thread_info->data_mutex);
695                 if(thread_info->interrupt_requested)
696                 {
697                     thread_info->interrupt_requested=false;
698                     throw thread_interrupted();
699                 }
700             }
701 #endif
702         }
703 
interruption_enabled()704         bool interruption_enabled() BOOST_NOEXCEPT
705         {
706             boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data();
707             return thread_info && thread_info->interrupt_enabled;
708         }
709 
interruption_requested()710         bool interruption_requested() BOOST_NOEXCEPT
711         {
712             boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data();
713             if(!thread_info)
714             {
715                 return false;
716             }
717             else
718             {
719                 lock_guard<mutex> lg(thread_info->data_mutex);
720                 return thread_info->interrupt_requested;
721             }
722         }
723 
disable_interruption()724         disable_interruption::disable_interruption() BOOST_NOEXCEPT:
725             interruption_was_enabled(interruption_enabled())
726         {
727             if(interruption_was_enabled)
728             {
729                 detail::get_current_thread_data()->interrupt_enabled=false;
730             }
731         }
732 
~disable_interruption()733         disable_interruption::~disable_interruption() BOOST_NOEXCEPT
734         {
735             if(detail::get_current_thread_data())
736             {
737                 detail::get_current_thread_data()->interrupt_enabled=interruption_was_enabled;
738             }
739         }
740 
restore_interruption(disable_interruption & d)741         restore_interruption::restore_interruption(disable_interruption& d) BOOST_NOEXCEPT
742         {
743             if(d.interruption_was_enabled)
744             {
745                 detail::get_current_thread_data()->interrupt_enabled=true;
746             }
747         }
748 
~restore_interruption()749         restore_interruption::~restore_interruption() BOOST_NOEXCEPT
750         {
751             if(detail::get_current_thread_data())
752             {
753                 detail::get_current_thread_data()->interrupt_enabled=false;
754             }
755         }
756     }
757 #endif
758 
759     namespace detail
760     {
add_thread_exit_function(thread_exit_function_base * func)761         void add_thread_exit_function(thread_exit_function_base* func)
762         {
763             detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
764             thread_exit_callback_node* const new_node=
765                 heap_new<thread_exit_callback_node>(func,current_thread_data->thread_exit_callbacks);
766             current_thread_data->thread_exit_callbacks=new_node;
767         }
768 
find_tss_data(void const * key)769         tss_data_node* find_tss_data(void const* key)
770         {
771             detail::thread_data_base* const current_thread_data(get_current_thread_data());
772             if(current_thread_data)
773             {
774                 std::map<void const*,tss_data_node>::iterator current_node=
775                     current_thread_data->tss_data.find(key);
776                 if(current_node!=current_thread_data->tss_data.end())
777                 {
778                     return &current_node->second;
779                 }
780             }
781             return 0;
782         }
783 
get_tss_data(void const * key)784         void* get_tss_data(void const* key)
785         {
786             if(tss_data_node* const current_node=find_tss_data(key))
787             {
788                 return current_node->value;
789             }
790             return 0;
791         }
792 
add_new_tss_node(void const * key,boost::shared_ptr<tss_cleanup_function> func,void * tss_data)793         void add_new_tss_node(void const* key,
794                               boost::shared_ptr<tss_cleanup_function> func,
795                               void* tss_data)
796         {
797             detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
798             current_thread_data->tss_data.insert(std::make_pair(key,tss_data_node(func,tss_data)));
799         }
800 
erase_tss_node(void const * key)801         void erase_tss_node(void const* key)
802         {
803             detail::thread_data_base* const current_thread_data(get_current_thread_data());
804             if(current_thread_data)
805             {
806                 current_thread_data->tss_data.erase(key);
807             }
808         }
809 
set_tss_data(void const * key,boost::shared_ptr<tss_cleanup_function> func,void * tss_data,bool cleanup_existing)810         void set_tss_data(void const* key,
811                           boost::shared_ptr<tss_cleanup_function> func,
812                           void* tss_data,bool cleanup_existing)
813         {
814             if(tss_data_node* const current_node=find_tss_data(key))
815             {
816                 if(cleanup_existing && current_node->func && (current_node->value!=0))
817                 {
818                     (*current_node->func)(current_node->value);
819                 }
820                 if(func || (tss_data!=0))
821                 {
822                     current_node->func=func;
823                     current_node->value=tss_data;
824                 }
825                 else
826                 {
827                     erase_tss_node(key);
828                 }
829             }
830             else if(func || (tss_data!=0))
831             {
832                 add_new_tss_node(key,func,tss_data);
833             }
834         }
835     }
836 
notify_all_at_thread_exit(condition_variable & cond,unique_lock<mutex> lk)837     BOOST_THREAD_DECL void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk)
838     {
839       detail::thread_data_base* const current_thread_data(detail::get_current_thread_data());
840       if(current_thread_data)
841       {
842         current_thread_data->notify_all_at_thread_exit(&cond, lk.release());
843       }
844     }
845 namespace detail {
846 
make_ready_at_thread_exit(shared_ptr<shared_state_base> as)847     void BOOST_THREAD_DECL make_ready_at_thread_exit(shared_ptr<shared_state_base> as)
848     {
849       detail::thread_data_base* const current_thread_data(detail::get_current_thread_data());
850       if(current_thread_data)
851       {
852         current_thread_data->make_ready_at_thread_exit(as);
853       }
854     }
855 }
856 
857 
858 
859 }
860