diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index 10bceabe..860542be 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -180,8 +180,6 @@ alias thread_sources : ## win32 sources ## win32/thread.cpp win32/exceptions.cpp - win32/tss.cpp - win32/tss_hooks.cpp win32/tss_dll.cpp win32/tss_pe.cpp : ## requirements ## diff --git a/include/boost/thread/detail/tss_hooks.hpp b/include/boost/thread/detail/tss_hooks.hpp index a1c1aa3b..4b18fe97 100644 --- a/include/boost/thread/detail/tss_hooks.hpp +++ b/include/boost/thread/detail/tss_hooks.hpp @@ -67,7 +67,7 @@ //Called automatically by Boost.Threads when //a method for doing so has been discovered. //Must not be omitted; may be called multiple times. - + extern "C" void tss_cleanup_implemented(void); //Dummy function used both to detect whether tss cleanup //cleanup has been implemented and to force diff --git a/include/boost/thread/tss.hpp b/include/boost/thread/tss.hpp index 0b33bda4..1870324c 100644 --- a/include/boost/thread/tss.hpp +++ b/include/boost/thread/tss.hpp @@ -1,5 +1,6 @@ // Copyright (C) 2001-2003 William E. Kempf // Copyright (C) 2006 Roland Schwarz +// Copyright (C) 2007 Anthony Williams // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -9,14 +10,17 @@ #include +#ifdef BOOST_HAS_WINTHREADS +#include +#include BOOST_THREAD_PLATFORM(tss.hpp) +#else + #include #include #include #if defined(BOOST_HAS_PTHREADS) # include -#elif defined(BOOST_HAS_MPTASKS) -# include #endif namespace boost { @@ -57,10 +61,6 @@ private: void init(boost::function1* pcleanup); }; -#if defined(BOOST_HAS_MPTASKS) -void thread_cleanup(); -#endif - template struct tss_adapter { @@ -112,6 +112,8 @@ private: } // namespace boost +#endif + #endif //BOOST_TSS_WEK070601_HPP // Change Log: diff --git a/include/boost/thread/win32/thread.hpp b/include/boost/thread/win32/thread.hpp index a81c6ee6..1e237791 100644 --- a/include/boost/thread/win32/thread.hpp +++ b/include/boost/thread/win32/thread.hpp @@ -27,6 +27,7 @@ namespace boost namespace detail { struct thread_exit_callback_node; + struct tss_data_node; struct thread_data_base { @@ -34,13 +35,14 @@ namespace boost detail::win32::handle_manager thread_handle; detail::win32::handle_manager interruption_handle; boost::detail::thread_exit_callback_node* thread_exit_callbacks; + boost::detail::tss_data_node* tss_data; bool interruption_enabled; unsigned id; thread_data_base(): count(0),thread_handle(detail::win32::invalid_handle_value), interruption_handle(create_anonymous_event(detail::win32::manual_reset_event,detail::win32::event_initially_reset)), - thread_exit_callbacks(0), + thread_exit_callbacks(0),tss_data(0), interruption_enabled(true), id(0) {} diff --git a/include/boost/thread/win32/thread_heap_alloc.hpp b/include/boost/thread/win32/thread_heap_alloc.hpp index eed7d4b3..1835e35e 100644 --- a/include/boost/thread/win32/thread_heap_alloc.hpp +++ b/include/boost/thread/win32/thread_heap_alloc.hpp @@ -6,6 +6,8 @@ #define THREAD_HEAP_ALLOC_HPP #include #include "thread_primitives.hpp" +#include +#include #if defined( BOOST_USE_WINDOWS_H ) # include @@ -51,35 +53,106 @@ namespace boost { namespace detail { + inline BOOST_THREAD_DECL void* allocate_raw_heap_memory(unsigned size) + { + void* const heap_memory=detail::win32::HeapAlloc(detail::win32::GetProcessHeap(),0,size); + if(!heap_memory) + { + throw std::bad_alloc(); + } + return heap_memory; + } + + inline BOOST_THREAD_DECL void free_raw_heap_memory(void* heap_memory) + { + BOOST_VERIFY(detail::win32::HeapFree(detail::win32::GetProcessHeap(),0,heap_memory)!=0); + } + template T* heap_new() { - void* const heap_memory=detail::win32::HeapAlloc(detail::win32::GetProcessHeap(),0,sizeof(T)); - T* const data=new (heap_memory) T(); - return data; + void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); + try + { + T* const data=new (heap_memory) T(); + return data; + } + catch(...) + { + free_raw_heap_memory(heap_memory); + throw; + } } template T* heap_new(A1 a1) { - void* const heap_memory=detail::win32::HeapAlloc(detail::win32::GetProcessHeap(),0,sizeof(T)); - T* const data=new (heap_memory) T(a1); - return data; + void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); + try + { + T* const data=new (heap_memory) T(a1); + return data; + } + catch(...) + { + free_raw_heap_memory(heap_memory); + throw; + } } template T* heap_new(A1 a1,A2 a2) { - void* const heap_memory=detail::win32::HeapAlloc(detail::win32::GetProcessHeap(),0,sizeof(T)); - T* const data=new (heap_memory) T(a1,a2); - return data; + void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); + try + { + T* const data=new (heap_memory) T(a1,a2); + return data; + } + catch(...) + { + free_raw_heap_memory(heap_memory); + throw; + } + } + + template + T* heap_new(A1 a1,A2 a2,A3 a3) + { + void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); + try + { + T* const data=new (heap_memory) T(a1,a2,a3); + return data; + } + catch(...) + { + free_raw_heap_memory(heap_memory); + throw; + } + } + + template + T* heap_new(A1 a1,A2 a2,A3 a3,A4 a4) + { + void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); + try + { + T* const data=new (heap_memory) T(a1,a2,a3,a4); + return data; + } + catch(...) + { + free_raw_heap_memory(heap_memory); + throw; + } } template void heap_delete(T* data) { data->~T(); - detail::win32::HeapFree(detail::win32::GetProcessHeap(),0,data); + free_raw_heap_memory(data); } template diff --git a/include/boost/thread/win32/tss.hpp b/include/boost/thread/win32/tss.hpp new file mode 100644 index 00000000..a99dfac4 --- /dev/null +++ b/include/boost/thread/win32/tss.hpp @@ -0,0 +1,82 @@ +#ifndef BOOST_THREAD_WIN32_TSS_HPP +#define BOOST_THREAD_WIN32_TSS_HPP + +namespace boost +{ + namespace detail + { + typedef void(*tss_cleanup_function)(void const* key,void* value); + + BOOST_THREAD_DECL void set_tss_data(void const* key,tss_cleanup_function func,void* tss_data,bool cleanup_existing); + BOOST_THREAD_DECL void* get_tss_data(void const* key); + } + + template + class thread_specific_ptr + { + private: + thread_specific_ptr(thread_specific_ptr&); + thread_specific_ptr& operator=(thread_specific_ptr&); + + static void delete_data(void const* self,void* value) + { + static_cast(self)->cleanup((T*)value); + } + + void cleanup(T* data) const + { + if(func) + { + func(data); + } + else + { + delete data; + } + } + + void (*func)(T*); + + public: + thread_specific_ptr(): + func(0) + {} + explicit thread_specific_ptr(void (*func_)(T*)): + func(func_) + {} + ~thread_specific_ptr() + { + reset(); + } + + T* get() const + { + return static_cast(detail::get_tss_data(this)); + } + T* operator->() const + { + return get(); + } + T& operator*() const + { + return *get(); + } + T* release() + { + T* const temp=get(); + detail::set_tss_data(this,0,0,false); + return temp; + } + void reset(T* new_value=0) + { + T* const current_value=get(); + if(current_value!=new_value) + { + detail::set_tss_data(this,delete_data,new_value,true); + } + } + }; +} + + +#endif diff --git a/src/win32/thread.cpp b/src/win32/thread.cpp index 54636dcc..fee2b4fd 100644 --- a/src/win32/thread.cpp +++ b/src/win32/thread.cpp @@ -12,7 +12,9 @@ #endif #include #include +#include #include +#include namespace boost { @@ -130,6 +132,19 @@ namespace boost {} }; + struct tss_data_node + { + void const* key; + boost::detail::tss_cleanup_function func; + void* value; + tss_data_node* next; + + tss_data_node(void const* key_,boost::detail::tss_cleanup_function func_,void* value_, + tss_data_node* next_): + key(key_),func(func_),value(value_),next(next_) + {} + }; + } namespace @@ -139,17 +154,31 @@ namespace boost boost::intrusive_ptr current_thread_data(get_current_thread_data(),false); if(current_thread_data) { - while(current_thread_data->thread_exit_callbacks) + while(current_thread_data->tss_data || current_thread_data->thread_exit_callbacks) { - detail::thread_exit_callback_node* const current_node=current_thread_data->thread_exit_callbacks; - current_thread_data->thread_exit_callbacks=current_node->next; - if(current_node->func) + while(current_thread_data->thread_exit_callbacks) { - (*current_node->func)(); - boost::detail::heap_delete(current_node->func); + detail::thread_exit_callback_node* const current_node=current_thread_data->thread_exit_callbacks; + current_thread_data->thread_exit_callbacks=current_node->next; + if(current_node->func) + { + (*current_node->func)(); + boost::detail::heap_delete(current_node->func); + } + boost::detail::heap_delete(current_node); + } + while(current_thread_data->tss_data) + { + detail::tss_data_node* const current_node=current_thread_data->tss_data; + current_thread_data->tss_data=current_node->next; + if(current_node->func) + { + (*current_node->func)(current_node->key,current_node->value); + } + boost::detail::heap_delete(current_node); } - boost::detail::heap_delete(current_node); } + } set_current_thread_data(0); } @@ -210,14 +239,20 @@ namespace boost void run() {} }; + + void make_external_thread_data() + { + externally_launched_thread* me=detail::heap_new(); + set_current_thread_data(me); + } + } thread thread::self() { if(!get_current_thread_data()) { - externally_launched_thread* me=detail::heap_new(); - set_current_thread_data(me); + make_external_thread_data(); } return thread(boost::intrusive_ptr(get_current_thread_data())); } @@ -450,49 +485,83 @@ namespace boost } } - namespace - { - void NTAPI thread_exit_func_callback(HINSTANCE, DWORD, PVOID); - typedef void (NTAPI* tls_callback)(HINSTANCE, DWORD, PVOID); - -#ifdef _MSC_VER - extern "C" - { - extern DWORD _tls_used; //the tls directory (located in .rdata segment) - extern tls_callback __xl_a[], __xl_z[]; //tls initializers */ - } - -#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0 -# pragma data_seg(push, old_seg) -#endif - -#pragma data_seg(".CRT$XLB") - tls_callback p_thread_callback = thread_exit_func_callback; -#pragma data_seg() - -#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0 -# pragma data_seg(pop, old_seg) -#endif -#endif - - void NTAPI thread_exit_func_callback(HINSTANCE h, DWORD dwReason, PVOID pv) - { - if((dwReason==DLL_THREAD_DETACH) || (dwReason==DLL_PROCESS_DETACH)) - { - run_thread_exit_callbacks(); - } - } - } - namespace detail { void add_thread_exit_function(thread_exit_function_base* func) { + detail::thread_data_base* const current_thread_data(get_current_thread_data()); thread_exit_callback_node* const new_node= heap_new(func, - get_current_thread_data()->thread_exit_callbacks); - get_current_thread_data()->thread_exit_callbacks=new_node; + current_thread_data->thread_exit_callbacks); + current_thread_data->thread_exit_callbacks=new_node; + } + + tss_data_node* find_tss_data(void const* key) + { + detail::thread_data_base* const current_thread_data(get_current_thread_data()); + if(current_thread_data) + { + detail::tss_data_node* current_node=current_thread_data->tss_data; + while(current_node) + { + if(current_node->key==key) + { + return current_node; + } + current_node=current_node->next; + } + } + return NULL; + } + + void* get_tss_data(void const* key) + { + if(tss_data_node* const current_node=find_tss_data(key)) + { + return current_node->value; + } + return NULL; + } + + void set_tss_data(void const* key,tss_cleanup_function func,void* tss_data,bool cleanup_existing) + { + tss_cleanup_implemented(); // if anyone uses TSS, we need the cleanup linked in + if(tss_data_node* const current_node=find_tss_data(key)) + { + if(cleanup_existing && current_node->func) + { + (current_node->func)(current_node->key,current_node->value); + } + current_node->func=func; + current_node->value=tss_data; + } + else + { + detail::thread_data_base* current_thread_data(get_current_thread_data()); + if(!current_thread_data) + { + make_external_thread_data(); + current_thread_data=get_current_thread_data(); + } + tss_data_node* const new_node=heap_new(key,func,tss_data,current_thread_data->tss_data); + current_thread_data->tss_data=new_node; + } } } } + +extern "C" BOOST_THREAD_DECL void on_process_enter() +{} + +extern "C" BOOST_THREAD_DECL void on_thread_enter() +{} + +extern "C" BOOST_THREAD_DECL void on_process_exit() +{} + +extern "C" BOOST_THREAD_DECL void on_thread_exit() +{ + boost::run_thread_exit_callbacks(); +} + diff --git a/src/win32/tss.cpp b/src/win32/tss.cpp deleted file mode 100644 index eb5a4d81..00000000 --- a/src/win32/tss.cpp +++ /dev/null @@ -1,211 +0,0 @@ -// Copyright (C) 2001-2003 William E. Kempf -// Copyright (C) 2006 Roland Schwarz -// Copyright (C) 2007 Anthony Williams -// Copyright (C) 2007 David Deakins -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -#include - -#include -#ifndef BOOST_THREAD_NO_TSS_CLEANUP - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#if defined(UNDER_CE) && !defined(TLS_OUT_OF_INDEXES) -# define TLS_OUT_OF_INDEXES 0xFFFFFFFF -#endif - -namespace { - -typedef std::vector tss_slots; -typedef std::vector*> tss_data_cleanup_handlers_type; - -boost::once_flag tss_data_once = BOOST_ONCE_INIT; -boost::mutex* tss_data_mutex = 0; -tss_data_cleanup_handlers_type* tss_data_cleanup_handlers = 0; - DWORD tss_data_native_key=TLS_OUT_OF_INDEXES; -int tss_data_use = 0; - -void tss_data_inc_use(boost::mutex::scoped_lock& lk) -{ - ++tss_data_use; -} - -void tss_data_dec_use(boost::mutex::scoped_lock& lk) -{ - if (0 == --tss_data_use) - { - tss_data_cleanup_handlers_type::size_type i; - for (i = 0; i < tss_data_cleanup_handlers->size(); ++i) - { - delete (*tss_data_cleanup_handlers)[i]; - } - delete tss_data_cleanup_handlers; - tss_data_cleanup_handlers = 0; - lk.unlock(); - delete tss_data_mutex; - tss_data_mutex = 0; - TlsFree(tss_data_native_key); - tss_data_native_key=TLS_OUT_OF_INDEXES; - } -} - -extern "C" void cleanup_slots(void* p) -{ - tss_slots* slots = static_cast(p); - boost::mutex::scoped_lock lock(*tss_data_mutex); - for (tss_slots::size_type i = 0; i < slots->size(); ++i) - { - (*(*tss_data_cleanup_handlers)[i])((*slots)[i]); - (*slots)[i] = 0; - } - TlsSetValue(tss_data_native_key,0); - tss_data_dec_use(lock); - delete slots; -} - -void init_tss_data() -{ - std::auto_ptr - temp(new tss_data_cleanup_handlers_type); - - std::auto_ptr temp_mutex(new boost::mutex); - if (temp_mutex.get() == 0) - throw boost::thread_resource_error(); - - //Force the cleanup implementation library to be linked in - tss_cleanup_implemented(); - - //Allocate tls slot - tss_data_native_key = TlsAlloc(); - if (tss_data_native_key == TLS_OUT_OF_INDEXES) - return; - - // The life time of cleanup handlers and mutex is beeing - // managed by a reference counting technique. - // This avoids a memory leak by releasing the global data - // after last use only, since the execution order of cleanup - // handlers is unspecified on any platform with regards to - // C++ destructor ordering rules. - tss_data_cleanup_handlers = temp.release(); - tss_data_mutex = temp_mutex.release(); -} - -tss_slots* get_slots(bool alloc); - -void __cdecl tss_thread_exit() -{ - tss_slots* slots = get_slots(false); - if (slots) - cleanup_slots(slots); -} - -tss_slots* get_slots(bool alloc) -{ - tss_slots* slots = 0; - - slots = static_cast( - TlsGetValue(tss_data_native_key)); - - if (slots == 0 && alloc) - { - std::auto_ptr temp(new tss_slots); - - if (at_thread_exit(&tss_thread_exit) == -1) - return 0; - if (!TlsSetValue(tss_data_native_key, temp.get())) - return 0; - { - boost::mutex::scoped_lock lock(*tss_data_mutex); - tss_data_inc_use(lock); - } - slots = temp.release(); - } - - return slots; -} - -} // namespace - -namespace boost { - -namespace detail { -void tss::init(boost::function1* pcleanup) -{ - boost::call_once(tss_data_once, &init_tss_data); - if (tss_data_cleanup_handlers == 0) - throw thread_resource_error(); - boost::mutex::scoped_lock lock(*tss_data_mutex); - try - { - tss_data_cleanup_handlers->push_back(pcleanup); - m_slot = tss_data_cleanup_handlers->size() - 1; - tss_data_inc_use(lock); - } - catch (...) - { - throw thread_resource_error(); - } -} - -tss::~tss() -{ - boost::mutex::scoped_lock lock(*tss_data_mutex); - tss_data_dec_use(lock); -} - -void* tss::get() const -{ - tss_slots* slots = get_slots(false); - - if (!slots) - return 0; - - if (m_slot >= slots->size()) - return 0; - - return (*slots)[m_slot]; -} - -void tss::set(void* value) -{ - tss_slots* slots = get_slots(true); - - if (!slots) - throw boost::thread_resource_error(); - - if (m_slot >= slots->size()) - { - try - { - slots->resize(m_slot + 1); - } - catch (...) - { - throw boost::thread_resource_error(); - } - } - - (*slots)[m_slot] = value; -} - -void tss::cleanup(void* value) -{ - boost::mutex::scoped_lock lock(*tss_data_mutex); - (*(*tss_data_cleanup_handlers)[m_slot])(value); -} - -} // namespace detail -} // namespace boost - -#endif //BOOST_THREAD_NO_TSS_CLEANUP diff --git a/src/win32/tss_hooks.cpp b/src/win32/tss_hooks.cpp deleted file mode 100644 index 8e9f7df8..00000000 --- a/src/win32/tss_hooks.cpp +++ /dev/null @@ -1,218 +0,0 @@ -// Copyright (C) 2004 Michael Glassford -// Copyright (C) 2006 Roland Schwarz -// Copyright (C) 2007 Anthony Williams -// Copyright (C) 2007 David Deakins -// Use, modification and distribution are subject to the -// Boost Software License, Version 1.0. (See accompanying file -// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -#include - -#if defined(BOOST_HAS_WINTHREADS) - - #include - - #include -// #include - #include - - #include - - #define WIN32_LEAN_AND_MEAN - #include - -# if defined(UNDER_CE) && !defined(TLS_OUT_OF_INDEXES) -# define TLS_OUT_OF_INDEXES 0xFFFFFFFF -# endif - - namespace - { - class CScopedCSLock - { - public: - CScopedCSLock(LPCRITICAL_SECTION cs) : lk(true), cs(cs) { - ::EnterCriticalSection(cs); - } - ~CScopedCSLock() { - if (lk) ::LeaveCriticalSection(cs); - } - void Unlock() { - lk = false; - ::LeaveCriticalSection(cs); - } - private: - bool lk; - LPCRITICAL_SECTION cs; - }; - - typedef std::list thread_exit_handlers; - - boost::once_flag once_init_threadmon_mutex = BOOST_ONCE_INIT; - //boost::mutex* threadmon_mutex; - // We don't use boost::mutex here, to avoid a memory leak report, - // because we cannot delete it again easily. - CRITICAL_SECTION threadmon_mutex; - void init_threadmon_mutex(void) - { - //threadmon_mutex = new boost::mutex; - //if (!threadmon_mutex) - // throw boost::thread_resource_error(); - ::InitializeCriticalSection(&threadmon_mutex); - } - - const DWORD invalid_tls_key = TLS_OUT_OF_INDEXES; - DWORD tls_key = invalid_tls_key; - - unsigned long attached_thread_count = 0; - } - - /* - Calls to DllMain() and tls_callback() are serialized by the OS; - however, calls to at_thread_exit are not, so it must be protected - by a mutex. Since we already need a mutex for at_thread_exit(), - and since there is no guarantee that on_process_enter(), - on_process_exit(), on_thread_enter(), and on_thread_exit() - will be called only from DllMain() or tls_callback(), it makes - sense to protect those, too. - */ - - extern "C" BOOST_THREAD_DECL int at_thread_exit( - thread_exit_handler exit_handler - ) - { - boost::call_once(once_init_threadmon_mutex, init_threadmon_mutex); - //boost::mutex::scoped_lock lock(*threadmon_mutex); - CScopedCSLock lock(&threadmon_mutex); - - //Allocate a tls slot if necessary. - - if (tls_key == invalid_tls_key) - tls_key = TlsAlloc(); - - if (tls_key == invalid_tls_key) - return -1; - - //Get the exit handlers list for the current thread from tls. - - thread_exit_handlers* exit_handlers = - static_cast(TlsGetValue(tls_key)); - - if (!exit_handlers) - { - //No exit handlers list was created yet. - - try - { - //Attempt to create a new exit handlers list. - - exit_handlers = new thread_exit_handlers; - if (!exit_handlers) - return -1; - - //Attempt to store the list pointer in tls. - - if (TlsSetValue(tls_key, exit_handlers)) - ++attached_thread_count; - else - { - delete exit_handlers; - return -1; - } - } - catch (...) - { - return -1; - } - } - - //Like the C runtime library atexit() function, - //functions should be called in the reverse of - //the order they are added, so push them on the - //front of the list. - - try - { - exit_handlers->push_front(exit_handler); - } - catch (...) - { - return -1; - } - - //Like the atexit() function, a result of zero - //indicates success. - - return 0; - } - - extern "C" BOOST_THREAD_DECL void on_process_enter(void) - { - boost::call_once(once_init_threadmon_mutex, init_threadmon_mutex); -// boost::mutex::scoped_lock lock(*threadmon_mutex); - CScopedCSLock lock(&threadmon_mutex); - - BOOST_ASSERT(attached_thread_count == 0); - } - - extern "C" BOOST_THREAD_DECL void on_process_exit(void) - { - boost::call_once(once_init_threadmon_mutex, init_threadmon_mutex); -// boost::mutex::scoped_lock lock(*threadmon_mutex); - CScopedCSLock lock(&threadmon_mutex); - - BOOST_ASSERT(attached_thread_count == 0); - - //Free the tls slot if one was allocated. - - if (tls_key != invalid_tls_key) - { - TlsFree(tls_key); - tls_key = invalid_tls_key; - } - } - - extern "C" BOOST_THREAD_DECL void on_thread_enter(void) - { - //boost::call_once(init_threadmon_mutex, once_init_threadmon_mutex); - //boost::mutex::scoped_lock lock(*threadmon_mutex); - } - - extern "C" BOOST_THREAD_DECL void on_thread_exit(void) - { - boost::call_once(once_init_threadmon_mutex, init_threadmon_mutex); -// boost::mutex::scoped_lock lock(*threadmon_mutex); - CScopedCSLock lock(&threadmon_mutex); - - //Get the exit handlers list for the current thread from tls. - - if (tls_key == invalid_tls_key) - return; - - thread_exit_handlers* exit_handlers = - static_cast(TlsGetValue(tls_key)); - - //If a handlers list was found, use it. - - if (exit_handlers && TlsSetValue(tls_key, 0)) - { - BOOST_ASSERT(attached_thread_count > 0); - --attached_thread_count; - - //lock.unlock(); - lock.Unlock(); - - //Call each handler and remove it from the list - - while (!exit_handlers->empty()) - { - if (thread_exit_handler exit_handler = *exit_handlers->begin()) - (*exit_handler)(); - exit_handlers->pop_front(); - } - - delete exit_handlers; - exit_handlers = 0; - } - } - -#endif //defined(BOOST_HAS_WINTHREADS) diff --git a/src/win32/tss_pe.cpp b/src/win32/tss_pe.cpp index 010920f6..3aef63a1 100644 --- a/src/win32/tss_pe.cpp +++ b/src/win32/tss_pe.cpp @@ -220,10 +220,13 @@ extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata void NTAPI on_tls_callback(HINSTANCE h, DWORD dwReason, PVOID pv) { + OutputDebugString("on_tls_callback\n"); + switch (dwReason) { case DLL_THREAD_DETACH: { + OutputDebugString("on_tls_callback: thread_exit\n"); on_thread_exit(); break; }