Pastebin launched a little side project called HostCabi.net, check it out ;-)Don't like ads? PRO users don't see any ads ;-)
Guest

thread_src/src/win32/thread.cpp

By: aj3423 on Oct 23rd, 2012  |  syntax: C++  |  size: 24.47 KB  |  hits: 36  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. // Distributed under the Boost Software License, Version 1.0. (See
  2. // accompanying file LICENSE_1_0.txt or copy at
  3. // http://www.boost.org/LICENSE_1_0.txt)
  4. // (C) Copyright 2007 Anthony Williams
  5. // (C) Copyright 2007 David Deakins
  6.  
  7. #ifndef _WIN32_WINNT
  8. #define _WIN32_WINNT 0x400
  9. #endif
  10.  
  11. #ifndef WINVER
  12. #define WINVER 0x400
  13. #endif
  14.  
  15. #include <boost/thread/thread.hpp>
  16. #include <algorithm>
  17. #ifndef UNDER_CE
  18. #include <process.h>
  19. #endif
  20. #include <stdio.h>
  21. #include <boost/thread/once.hpp>
  22. #include <boost/thread/tss.hpp>
  23. #include <boost/assert.hpp>
  24. #include <boost/throw_exception.hpp>
  25. #include <boost/thread/detail/tss_hooks.hpp>
  26. #include <boost/date_time/posix_time/conversion.hpp>
  27. #include <windows.h>
  28. #include <memory>
  29.  
  30. namespace boost
  31. {
  32.     namespace
  33.     {
  34. #ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11
  35.         boost::once_flag current_thread_tls_init_flag;
  36. #else
  37.         boost::once_flag current_thread_tls_init_flag=BOOST_ONCE_INIT;
  38. #endif
  39. #if defined(UNDER_CE)
  40.         // Windows CE does not define the TLS_OUT_OF_INDEXES constant.
  41. #define TLS_OUT_OF_INDEXES 0xFFFFFFFF
  42. #endif
  43.         DWORD current_thread_tls_key=TLS_OUT_OF_INDEXES;
  44.  
  45.         void create_current_thread_tls_key()
  46.         {
  47.             tss_cleanup_implemented(); // if anyone uses TSS, we need the cleanup linked in
  48.             current_thread_tls_key=TlsAlloc();
  49.             BOOST_ASSERT(current_thread_tls_key!=TLS_OUT_OF_INDEXES);
  50.         }
  51.  
  52.         void cleanup_tls_key()
  53.         {
  54.             if(current_thread_tls_key!=TLS_OUT_OF_INDEXES)
  55.             {
  56.                 TlsFree(current_thread_tls_key);
  57.                 current_thread_tls_key=TLS_OUT_OF_INDEXES;
  58.             }
  59.         }
  60.  
  61.         detail::thread_data_base* get_current_thread_data()
  62.         {
  63.             if(current_thread_tls_key==TLS_OUT_OF_INDEXES)
  64.             {
  65.                 return 0;
  66.             }
  67.             return (detail::thread_data_base*)TlsGetValue(current_thread_tls_key);
  68.         }
  69.  
  70.         void set_current_thread_data(detail::thread_data_base* new_data)
  71.         {
  72.             boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key);
  73.             if(current_thread_tls_key!=TLS_OUT_OF_INDEXES)
  74.                 BOOST_VERIFY(TlsSetValue(current_thread_tls_key,new_data));
  75.             else
  76.                 boost::throw_exception(thread_resource_error());
  77.         }
  78.  
  79. #ifndef BOOST_HAS_THREADEX
  80. // Windows CE doesn't define _beginthreadex
  81.  
  82.         struct ThreadProxyData
  83.         {
  84.             typedef unsigned (__stdcall* func)(void*);
  85.             func start_address_;
  86.             void* arglist_;
  87.             ThreadProxyData(func start_address,void* arglist) : start_address_(start_address), arglist_(arglist) {}
  88.         };
  89.  
  90.         DWORD WINAPI ThreadProxy(LPVOID args)
  91.         {
  92.             std::auto_ptr<ThreadProxyData> data(reinterpret_cast<ThreadProxyData*>(args));
  93.             DWORD ret=data->start_address_(data->arglist_);
  94.             return ret;
  95.         }
  96.  
  97.         typedef void* uintptr_t;
  98.  
  99.         inline uintptr_t _beginthreadex(void* security, unsigned stack_size, unsigned (__stdcall* start_address)(void*),
  100.                                               void* arglist, unsigned initflag, unsigned* thrdaddr)
  101.         {
  102.             DWORD threadID;
  103.             ThreadProxyData* data = new ThreadProxyData(start_address,arglist);
  104.             HANDLE hthread=CreateThread(static_cast<LPSECURITY_ATTRIBUTES>(security),stack_size,ThreadProxy,
  105.                                         data,initflag,&threadID);
  106.             if (hthread==0) {
  107.               delete data;
  108.               return 0;
  109.             }
  110.             *thrdaddr=threadID;
  111.             return reinterpret_cast<uintptr_t const>(hthread);
  112.         }
  113.  
  114. #endif
  115.  
  116.     }
  117.  
  118.     namespace detail
  119.     {
  120.         struct thread_exit_callback_node
  121.         {
  122.             boost::detail::thread_exit_function_base* func;
  123.             thread_exit_callback_node* next;
  124.  
  125.             thread_exit_callback_node(boost::detail::thread_exit_function_base* func_,
  126.                                       thread_exit_callback_node* next_):
  127.                 func(func_),next(next_)
  128.             {}
  129.         };
  130.  
  131.         struct tss_data_node
  132.         {
  133.             void const* key;
  134.             boost::shared_ptr<boost::detail::tss_cleanup_function> func;
  135.             void* value;
  136.             tss_data_node* next;
  137.  
  138.             tss_data_node(void const* key_,boost::shared_ptr<boost::detail::tss_cleanup_function> func_,void* value_,
  139.                           tss_data_node* next_):
  140.                 key(key_),func(func_),value(value_),next(next_)
  141.             {}
  142.         };
  143.  
  144.     }
  145.  
  146.     namespace
  147.     {
  148.         void run_thread_exit_callbacks()
  149.         {
  150.             detail::thread_data_ptr current_thread_data(get_current_thread_data(),false);
  151.             if(current_thread_data)
  152.             {
  153.                 while(current_thread_data->tss_data || current_thread_data->thread_exit_callbacks)
  154.                 {
  155.                     while(current_thread_data->thread_exit_callbacks)
  156.                     {
  157.                         detail::thread_exit_callback_node* const current_node=current_thread_data->thread_exit_callbacks;
  158.                         current_thread_data->thread_exit_callbacks=current_node->next;
  159.                         if(current_node->func)
  160.                         {
  161.                             (*current_node->func)();
  162.                             boost::detail::heap_delete(current_node->func);
  163.                         }
  164.                         boost::detail::heap_delete(current_node);
  165.                     }
  166.                     while(current_thread_data->tss_data)
  167.                     {
  168.                         detail::tss_data_node* const current_node=current_thread_data->tss_data;
  169.                         current_thread_data->tss_data=current_node->next;
  170.                         if(current_node->func)
  171.                         {
  172.                             (*current_node->func)(current_node->value);
  173.                         }
  174.                         boost::detail::heap_delete(current_node);
  175.                     }
  176.                 }
  177.  
  178.                 set_current_thread_data(0);
  179.             }
  180.         }
  181.  
  182.         unsigned __stdcall thread_start_function(void* param)
  183.         {
  184.             detail::thread_data_base* const thread_info(reinterpret_cast<detail::thread_data_base*>(param));
  185.             set_current_thread_data(thread_info);
  186. #ifndef BOOST_NO_EXCEPTIONS
  187.             try // BOOST_NO_EXCEPTIONS protected
  188. #endif
  189.             {
  190.                 thread_info->run();
  191.             }
  192. #ifndef BOOST_NO_EXCEPTIONS
  193.             catch(thread_interrupted const&) // BOOST_NO_EXCEPTIONS protected
  194.             {
  195.             }
  196. #endif
  197. // Removed as it stops the debugger identifying the cause of the exception
  198. // Unhandled exceptions still cause the application to terminate
  199. //             catch(...) // BOOST_NO_EXCEPTIONS protected
  200. //             {
  201. //                 std::terminate();
  202. //             }
  203.             run_thread_exit_callbacks();
  204.             return 0;
  205.         }
  206.     }
  207.  
  208.     thread::thread() BOOST_NOEXCEPT
  209.     {}
  210.  
  211.     void thread::start_thread()
  212.     {
  213.         uintptr_t const new_thread=_beginthreadex(0,0,&thread_start_function,thread_info.get(),CREATE_SUSPENDED,&thread_info->id);
  214.         if(!new_thread)
  215.         {
  216.             boost::throw_exception(thread_resource_error());
  217.         }
  218.         intrusive_ptr_add_ref(thread_info.get());
  219.         thread_info->thread_handle=(detail::win32::handle)(new_thread);
  220.         ResumeThread(thread_info->thread_handle);
  221.     }
  222.  
  223.     void thread::start_thread(const attributes& attr)
  224.     {
  225.       //uintptr_t const new_thread=_beginthreadex(attr.get_security(),attr.get_stack_size(),&thread_start_function,thread_info.get(),CREATE_SUSPENDED,&thread_info->id);
  226.       uintptr_t const new_thread=_beginthreadex(0,static_cast<unsigned int>(attr.get_stack_size()),&thread_start_function,thread_info.get(),CREATE_SUSPENDED,&thread_info->id);
  227.       if(!new_thread)
  228.       {
  229.           boost::throw_exception(thread_resource_error());
  230.       }
  231.       intrusive_ptr_add_ref(thread_info.get());
  232.       thread_info->thread_handle=(detail::win32::handle)(new_thread);
  233.       ResumeThread(thread_info->thread_handle);
  234.     }
  235.  
  236.     thread::thread(detail::thread_data_ptr data):
  237.         thread_info(data)
  238.     {}
  239.  
  240.     namespace
  241.     {
  242.         struct externally_launched_thread:
  243.             detail::thread_data_base
  244.         {
  245.             externally_launched_thread()
  246.             {
  247.                 ++count;
  248.                 interruption_enabled=false;
  249.             }
  250.  
  251.             void run()
  252.             {}
  253.         private:
  254.             externally_launched_thread(externally_launched_thread&);
  255.             void operator=(externally_launched_thread&);
  256.         };
  257.  
  258.         void make_external_thread_data()
  259.         {
  260.             externally_launched_thread* me=detail::heap_new<externally_launched_thread>();
  261. #ifndef BOOST_NO_EXCEPTIONS
  262.             try // BOOST_NO_EXCEPTIONS protected
  263. #endif
  264.             {
  265.                 set_current_thread_data(me);
  266.             }
  267. #ifndef BOOST_NO_EXCEPTIONS
  268.             catch(...) // BOOST_NO_EXCEPTIONS protected
  269.             {
  270.                 detail::heap_delete(me);
  271.                 throw; // BOOST_NO_EXCEPTIONS protected
  272.             }
  273. #endif
  274.         }
  275.  
  276.         detail::thread_data_base* get_or_make_current_thread_data()
  277.         {
  278.             detail::thread_data_base* current_thread_data(get_current_thread_data());
  279.             if(!current_thread_data)
  280.             {
  281.                 make_external_thread_data();
  282.                 current_thread_data=get_current_thread_data();
  283.             }
  284.             return current_thread_data;
  285.         }
  286.  
  287.     }
  288.  
  289.     thread::id thread::get_id() const BOOST_NOEXCEPT
  290.     {
  291.     #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
  292.       detail::thread_data_ptr local_thread_info=(get_thread_info)();
  293.       return local_thread_info?local_thread_info->id:0;
  294.       //return const_cast<thread*>(this)->native_handle();
  295.     #else
  296.         return thread::id((get_thread_info)());
  297.     #endif
  298.     }
  299.  
  300.     bool thread::joinable() const BOOST_NOEXCEPT
  301.     {
  302.         return (get_thread_info)();
  303.     }
  304.  
  305.     void thread::join()
  306.     {
  307.         if (this_thread::get_id() == get_id())
  308.         {
  309.             boost::throw_exception(thread_resource_error(system::errc::resource_deadlock_would_occur, "boost thread: trying joining itself"));
  310.         }
  311.         detail::thread_data_ptr local_thread_info=(get_thread_info)();
  312.         if(local_thread_info)
  313.         {
  314.             this_thread::interruptible_wait(local_thread_info->thread_handle,detail::timeout::sentinel());
  315.             release_handle();
  316.         }
  317.     }
  318.  
  319.     bool thread::timed_join(boost::system_time const& wait_until)
  320.     {
  321.         if (this_thread::get_id() == get_id())
  322.         {
  323.             boost::throw_exception(thread_resource_error(system::errc::resource_deadlock_would_occur, "boost thread: trying joining itself"));
  324.         }
  325.         detail::thread_data_ptr local_thread_info=(get_thread_info)();
  326.         if(local_thread_info)
  327.         {
  328.             if(!this_thread::interruptible_wait(local_thread_info->thread_handle,get_milliseconds_until(wait_until)))
  329.             {
  330.                 return false;
  331.             }
  332.             release_handle();
  333.         }
  334.         return true;
  335.     }
  336.  
  337. #ifdef BOOST_THREAD_USES_CHRONO
  338.  
  339.     bool thread::try_join_until(const chrono::time_point<chrono::system_clock, chrono::nanoseconds>& tp)
  340.     {
  341.       if (this_thread::get_id() == get_id())
  342.       {
  343.         boost::throw_exception(thread_resource_error(system::errc::resource_deadlock_would_occur, "boost thread: trying joining itself"));
  344.       }
  345.       detail::thread_data_ptr local_thread_info=(get_thread_info)();
  346.       if(local_thread_info)
  347.       {
  348.         chrono::milliseconds rel_time= chrono::ceil<chrono::milliseconds>(tp-chrono::system_clock::now());
  349.         if(!this_thread::interruptible_wait(local_thread_info->thread_handle,rel_time.count()))
  350.         {
  351.             return false;
  352.         }
  353.         release_handle();
  354.       }
  355.       return true;
  356.     }
  357.  
  358. #endif
  359.  
  360.     void thread::detach() BOOST_NOEXCEPT
  361.     {
  362.         release_handle();
  363.     }
  364.  
  365.     void thread::release_handle()
  366.     {
  367.         thread_info=0;
  368.     }
  369.  
  370.     void thread::interrupt()
  371.     {
  372.         detail::thread_data_ptr local_thread_info=(get_thread_info)();
  373.         if(local_thread_info)
  374.         {
  375.             local_thread_info->interrupt();
  376.         }
  377.     }
  378.  
  379.     bool thread::interruption_requested() const BOOST_NOEXCEPT
  380.     {
  381.         detail::thread_data_ptr local_thread_info=(get_thread_info)();
  382.         return local_thread_info.get() && (detail::win32::WaitForSingleObject(local_thread_info->interruption_handle,0)==0);
  383.     }
  384.  
  385.     unsigned thread::hardware_concurrency() BOOST_NOEXCEPT
  386.     {
  387.         SYSTEM_INFO info={{0}};
  388.         GetSystemInfo(&info);
  389.         return info.dwNumberOfProcessors;
  390.     }
  391.  
  392.     thread::native_handle_type thread::native_handle()
  393.     {
  394.         detail::thread_data_ptr local_thread_info=(get_thread_info)();
  395.         return local_thread_info?(detail::win32::handle)local_thread_info->thread_handle:detail::win32::invalid_handle_value;
  396.     }
  397.  
  398.     detail::thread_data_ptr thread::get_thread_info BOOST_PREVENT_MACRO_SUBSTITUTION () const
  399.     {
  400.         return thread_info;
  401.     }
  402.  
  403.     namespace this_thread
  404.     {
  405.         namespace
  406.         {
  407.             LARGE_INTEGER get_due_time(detail::timeout const&  target_time)
  408.             {
  409.                 LARGE_INTEGER due_time={{0}};
  410.                 if(target_time.relative)
  411.                 {
  412.                     unsigned long const elapsed_milliseconds=GetTickCount()-target_time.start;
  413.                     LONGLONG const remaining_milliseconds=(target_time.milliseconds-elapsed_milliseconds);
  414.                     LONGLONG const hundred_nanoseconds_in_one_millisecond=10000;
  415.  
  416.                     if(remaining_milliseconds>0)
  417.                     {
  418.                         due_time.QuadPart=-(remaining_milliseconds*hundred_nanoseconds_in_one_millisecond);
  419.                     }
  420.                 }
  421.                 else
  422.                 {
  423.                     SYSTEMTIME target_system_time={0};
  424.                     target_system_time.wYear=target_time.abs_time.date().year();
  425.                     target_system_time.wMonth=target_time.abs_time.date().month();
  426.                     target_system_time.wDay=target_time.abs_time.date().day();
  427.                     target_system_time.wHour=(WORD)target_time.abs_time.time_of_day().hours();
  428.                     target_system_time.wMinute=(WORD)target_time.abs_time.time_of_day().minutes();
  429.                     target_system_time.wSecond=(WORD)target_time.abs_time.time_of_day().seconds();
  430.  
  431.                     if(!SystemTimeToFileTime(&target_system_time,((FILETIME*)&due_time)))
  432.                     {
  433.                         due_time.QuadPart=0;
  434.                     }
  435.                     else
  436.                     {
  437.                         long const hundred_nanoseconds_in_one_second=10000000;
  438.                         posix_time::time_duration::tick_type const ticks_per_second=
  439.                             target_time.abs_time.time_of_day().ticks_per_second();
  440.                         if(ticks_per_second>hundred_nanoseconds_in_one_second)
  441.                         {
  442.                             posix_time::time_duration::tick_type const
  443.                                 ticks_per_hundred_nanoseconds=
  444.                                 ticks_per_second/hundred_nanoseconds_in_one_second;
  445.                             due_time.QuadPart+=
  446.                                 target_time.abs_time.time_of_day().fractional_seconds()/
  447.                                 ticks_per_hundred_nanoseconds;
  448.                         }
  449.                         else
  450.                         {
  451.                             due_time.QuadPart+=
  452.                                 target_time.abs_time.time_of_day().fractional_seconds()*
  453.                                 (hundred_nanoseconds_in_one_second/ticks_per_second);
  454.                         }
  455.                     }
  456.                 }
  457.                 return due_time;
  458.             }
  459.         }
  460.  
  461.  
  462.         bool interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time)
  463.         {
  464.             detail::win32::handle handles[3]={0};
  465.             unsigned handle_count=0;
  466.             unsigned wait_handle_index=~0U;
  467.             unsigned interruption_index=~0U;
  468.             unsigned timeout_index=~0U;
  469.             if(handle_to_wait_for!=detail::win32::invalid_handle_value)
  470.             {
  471.                 wait_handle_index=handle_count;
  472.                 handles[handle_count++]=handle_to_wait_for;
  473.             }
  474.             if(get_current_thread_data() && get_current_thread_data()->interruption_enabled)
  475.             {
  476.                 interruption_index=handle_count;
  477.                 handles[handle_count++]=get_current_thread_data()->interruption_handle;
  478.             }
  479.  
  480.             detail::win32::handle_manager timer_handle;
  481.  
  482. #ifndef UNDER_CE
  483.             unsigned const min_timer_wait_period=20;
  484.  
  485.             if(!target_time.is_sentinel())
  486.             {
  487.                 detail::timeout::remaining_time const time_left=target_time.remaining_milliseconds();
  488.                 if(time_left.milliseconds > min_timer_wait_period)
  489.                 {
  490.                     // for a long-enough timeout, use a waitable timer (which tracks clock changes)
  491.                     timer_handle=CreateWaitableTimer(NULL,false,NULL);
  492.                     if(timer_handle!=0)
  493.                     {
  494.                         LARGE_INTEGER due_time=get_due_time(target_time);
  495.  
  496.                         bool const set_time_succeeded=SetWaitableTimer(timer_handle,&due_time,0,0,0,false)!=0;
  497.                         if(set_time_succeeded)
  498.                         {
  499.                             timeout_index=handle_count;
  500.                             handles[handle_count++]=timer_handle;
  501.                         }
  502.                     }
  503.                 }
  504.                 else if(!target_time.relative)
  505.                 {
  506.                     // convert short absolute-time timeouts into relative ones, so we don't race against clock changes
  507.                     target_time=detail::timeout(time_left.milliseconds);
  508.                 }
  509.             }
  510. #endif
  511.  
  512.             bool const using_timer=timeout_index!=~0u;
  513.             detail::timeout::remaining_time time_left(0);
  514.  
  515.             do
  516.             {
  517.                 if(!using_timer)
  518.                 {
  519.                     time_left=target_time.remaining_milliseconds();
  520.                 }
  521.  
  522.                 if(handle_count)
  523.                 {
  524.                     unsigned long const notified_index=detail::win32::WaitForMultipleObjects(handle_count,handles,false,using_timer?INFINITE:time_left.milliseconds);
  525.                     if(notified_index<handle_count)
  526.                     {
  527.                         if(notified_index==wait_handle_index)
  528.                         {
  529.                             return true;
  530.                         }
  531.                         else if(notified_index==interruption_index)
  532.                         {
  533.                             detail::win32::ResetEvent(get_current_thread_data()->interruption_handle);
  534.                             throw thread_interrupted();
  535.                         }
  536.                         else if(notified_index==timeout_index)
  537.                         {
  538.                             return false;
  539.                         }
  540.                     }
  541.                 }
  542.                 else
  543.                 {
  544.                     detail::win32::Sleep(time_left.milliseconds);
  545.                 }
  546.                 if(target_time.relative)
  547.                 {
  548.                     target_time.milliseconds-=detail::timeout::max_non_infinite_wait;
  549.                 }
  550.             }
  551.             while(time_left.more);
  552.             return false;
  553.         }
  554.  
  555.         thread::id get_id() BOOST_NOEXCEPT
  556.         {
  557.         #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
  558.           //return detail::win32::GetCurrentThread();
  559.           return detail::win32::GetCurrentThreadId();
  560.         #else
  561.             return thread::id(get_or_make_current_thread_data());
  562.         #endif
  563.         }
  564.  
  565.         void interruption_point()
  566.         {
  567.             if(interruption_enabled() && interruption_requested())
  568.             {
  569.                 detail::win32::ResetEvent(get_current_thread_data()->interruption_handle);
  570.                 throw thread_interrupted();
  571.             }
  572.         }
  573.  
  574.         bool interruption_enabled() BOOST_NOEXCEPT
  575.         {
  576.             return get_current_thread_data() && get_current_thread_data()->interruption_enabled;
  577.         }
  578.  
  579.         bool interruption_requested() BOOST_NOEXCEPT
  580.         {
  581.             return get_current_thread_data() && (detail::win32::WaitForSingleObject(get_current_thread_data()->interruption_handle,0)==0);
  582.         }
  583.  
  584.         void yield() BOOST_NOEXCEPT
  585.         {
  586.             detail::win32::Sleep(0);
  587.         }
  588.  
  589.         disable_interruption::disable_interruption() BOOST_NOEXCEPT:
  590.             interruption_was_enabled(interruption_enabled())
  591.         {
  592.             if(interruption_was_enabled)
  593.             {
  594.                 get_current_thread_data()->interruption_enabled=false;
  595.             }
  596.         }
  597.  
  598.         disable_interruption::~disable_interruption() BOOST_NOEXCEPT
  599.         {
  600.             if(get_current_thread_data())
  601.             {
  602.                 get_current_thread_data()->interruption_enabled=interruption_was_enabled;
  603.             }
  604.         }
  605.  
  606.         restore_interruption::restore_interruption(disable_interruption& d) BOOST_NOEXCEPT
  607.         {
  608.             if(d.interruption_was_enabled)
  609.             {
  610.                 get_current_thread_data()->interruption_enabled=true;
  611.             }
  612.         }
  613.  
  614.         restore_interruption::~restore_interruption() BOOST_NOEXCEPT
  615.         {
  616.             if(get_current_thread_data())
  617.             {
  618.                 get_current_thread_data()->interruption_enabled=false;
  619.             }
  620.         }
  621.     }
  622.  
  623.     namespace detail
  624.     {
  625.         void add_thread_exit_function(thread_exit_function_base* func)
  626.         {
  627.             detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
  628.             thread_exit_callback_node* const new_node=
  629.                 heap_new<thread_exit_callback_node>(
  630.                     func,current_thread_data->thread_exit_callbacks);
  631.             current_thread_data->thread_exit_callbacks=new_node;
  632.         }
  633.  
  634.         tss_data_node* find_tss_data(void const* key)
  635.         {
  636.             detail::thread_data_base* const current_thread_data(get_current_thread_data());
  637.             if(current_thread_data)
  638.             {
  639.                 detail::tss_data_node* current_node=current_thread_data->tss_data;
  640.                 while(current_node)
  641.                 {
  642.                     if(current_node->key==key)
  643.                     {
  644.                         return current_node;
  645.                     }
  646.                     current_node=current_node->next;
  647.                 }
  648.             }
  649.             return NULL;
  650.         }
  651.  
  652.         void* get_tss_data(void const* key)
  653.         {
  654.             if(tss_data_node* const current_node=find_tss_data(key))
  655.             {
  656.                 return current_node->value;
  657.             }
  658.             return NULL;
  659.         }
  660.  
  661.         void set_tss_data(void const* key,boost::shared_ptr<tss_cleanup_function> func,void* tss_data,bool cleanup_existing)
  662.         {
  663.             if(tss_data_node* const current_node=find_tss_data(key))
  664.             {
  665.                 if(cleanup_existing && current_node->func.get() && current_node->value)
  666.                 {
  667.                     (*current_node->func)(current_node->value);
  668.                 }
  669.                 current_node->func=func;
  670.                 current_node->value=tss_data;
  671.             }
  672.             else if(func && tss_data)
  673.             {
  674.                 detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
  675.                 tss_data_node* const new_node=
  676.                     heap_new<tss_data_node>(key,func,tss_data,current_thread_data->tss_data);
  677.                 current_thread_data->tss_data=new_node;
  678.             }
  679.         }
  680.     }
  681.     BOOST_THREAD_DECL void __cdecl on_process_enter()
  682.     {}
  683.  
  684.     BOOST_THREAD_DECL void __cdecl on_thread_enter()
  685.     {}
  686.  
  687.     BOOST_THREAD_DECL void __cdecl on_process_exit()
  688.     {
  689.         boost::cleanup_tls_key();
  690.     }
  691.  
  692.     BOOST_THREAD_DECL void __cdecl on_thread_exit()
  693.     {
  694.         boost::run_thread_exit_callbacks();
  695.     }
  696.  
  697. }