From 5472ebdfdee42c4df6432847542d99f3fa0a21ff Mon Sep 17 00:00:00 2001 From: Michael Glassford Date: Thu, 15 Jul 2004 14:26:10 +0000 Subject: [PATCH] Add hooks for users to provide their own tss cleanup in win32 statically linked builds. [SVN r23583] --- include/boost/thread/detail/threadmon.hpp | 14 +- include/boost/thread/tss.hpp | 5 +- src/threadmon.cpp | 246 +++++++++++++--------- src/tss.cpp | 4 +- 4 files changed, 158 insertions(+), 111 deletions(-) diff --git a/include/boost/thread/detail/threadmon.hpp b/include/boost/thread/detail/threadmon.hpp index 46254615..00cf8879 100644 --- a/include/boost/thread/detail/threadmon.hpp +++ b/include/boost/thread/detail/threadmon.hpp @@ -16,7 +16,19 @@ #ifdef BOOST_HAS_WINTHREADS -extern "C" BOOST_THREAD_DECL int on_thread_exit(void (__cdecl * func)(void)); +extern "C" BOOST_THREAD_DECL int add_thread_exit(void (__cdecl * func)(void)); + //Add a function to the list of thread-exit functions + +extern "C" BOOST_THREAD_DECL void on_process_enter(void); + //To be called when the process starts, when the dll is loaded, etc. + //Called automatically by Boost.Thread when possible +extern "C" BOOST_THREAD_DECL void on_thread_exit(void); + //To be called for each thread when it exits + //Must be called in the context of the thread that is exiting + //Called automatically by Boost.Thread when possible +extern "C" BOOST_THREAD_DECL void on_process_exit(void); + //To be called when the process exits, when the dll is unloaded, etc. + //Called automatically by Boost.Thread when possible #endif // BOOST_HAS_WINTHREADS diff --git a/include/boost/thread/tss.hpp b/include/boost/thread/tss.hpp index 59a7cd5e..042e2b64 100644 --- a/include/boost/thread/tss.hpp +++ b/include/boost/thread/tss.hpp @@ -14,8 +14,6 @@ #include -#ifndef BOOST_THREAD_NO_TSS_CLEANUP - #include #include #include @@ -107,8 +105,7 @@ private: } // namespace boost -#endif BOOST_THREAD_NO_TSS_CLEANUP -#endif // BOOST_TSS_WEK070601_HPP +#endif //BOOST_TSS_WEK070601_HPP // Change Log: // 6 Jun 01 diff --git a/src/threadmon.cpp b/src/threadmon.cpp index e4936c80..48248dd0 100644 --- a/src/threadmon.cpp +++ b/src/threadmon.cpp @@ -12,132 +12,170 @@ #include #if defined(BOOST_HAS_WINTHREADS) - -// Check this as well, for compatibility with pthreads-win32 (where this won't -// be defined) -#if defined(BOOST_THREAD_BUILD_DLL) - -#include - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#include - -#ifdef BOOST_MSVC -# pragma warning(disable : 4786) -#endif - -#include - -typedef void (__cdecl * handler)(void); -typedef std::list exit_handlers; - -namespace -{ - DWORD key; -} - -#if defined(__BORLANDC__) -#define DllMain DllEntryPoint -#endif - -extern "C" -BOOL WINAPI DllMain(HANDLE /*module*/, DWORD reason, LPVOID) -{ - switch (reason) + extern "C" void tss_cleanup_implemented(void); + + void require_tss_cleanup_implemented(void) { - case DLL_PROCESS_ATTACH: - key = TlsAlloc(); - break; - case DLL_THREAD_ATTACH: - break; - case DLL_THREAD_DETACH: - { - // Call the thread's exit handlers. - exit_handlers* handlers = - static_cast(TlsGetValue(key)); - if (handlers) - { - for (exit_handlers::iterator it = handlers->begin(); - it != handlers->end(); ++it) - { - (*it)(); - } - - // Destroy the exit handler. - delete handlers; - } - } - break; - case DLL_PROCESS_DETACH: - { - // Assume the main thread is ending (call its handlers) and - // all other threads have already ended. If this DLL is - // loaded and unloaded dynamically at run time - // this is a bad assumption, but this is the best we can do. - exit_handlers* handlers = - static_cast(TlsGetValue(key)); - if (handlers) - { - for (exit_handlers::iterator it = handlers->begin(); - it != handlers->end(); ++it) - { - (*it)(); - } - - // Remove the exit handler list from the registered lists - // and then destroy it. - delete handlers; - } - - TlsFree(key); - } - break; + tss_cleanup_implemented(); } - return TRUE; -} -extern "C" BOOST_THREAD_DECL int on_thread_exit(void (__cdecl * func)(void)) -{ - // Get the exit handlers for the current thread, creating and registering - // one if it doesn't exist. - exit_handlers* handlers = static_cast(TlsGetValue(key)); - if (!handlers) + #define WIN32_LEAN_AND_MEAN + //Exclude rarely-used stuff from Windows headers + + #include + + #ifdef BOOST_MSVC + # pragma warning(disable : 4786) + #endif + + #include + #include + + typedef void (__cdecl * handler)(void); + typedef std::list exit_handlers; + + namespace { + const DWORD invalid_key = TLS_OUT_OF_INDEXES; + static DWORD key = invalid_key; + } + + extern "C" + BOOST_THREAD_DECL int add_thread_exit(void (__cdecl * func)(void)) + { + //Get the exit handlers for the current thread, + //creating and registering one if it doesn't exist. + + if (key == invalid_key) + key = TlsAlloc(); + + if (key == invalid_key) + return -1; + + exit_handlers* handlers = + static_cast(TlsGetValue(key)); + + if (!handlers) + { + try + { + handlers = new exit_handlers; + + //Handle broken implementations + //of operator new that don't throw + if (!handlers) + return -1; + } + catch (...) + { + return -1; + } + + //Attempt to set a TLS value for the new handlers. + if (!TlsSetValue(key, handlers)) + { + delete handlers; + return -1; + } + } + + //Attempt to add the handler to the list of exit handlers. try { - handlers = new exit_handlers; - // Handle broken implementations of operator new that don't throw. - if (!handlers) - return -1; + handlers->push_front(func); } catch (...) { return -1; } - // Attempt to set a TLS value for the new handlers. - if (!TlsSetValue(key, handlers)) + return 0; + } + + extern "C" BOOST_THREAD_DECL void on_process_enter(void) + { + if (key == invalid_key) + key = TlsAlloc(); + } + + extern "C" BOOST_THREAD_DECL void on_thread_exit(void) + { + if (key == invalid_key) + return; + + exit_handlers* handlers = + static_cast(TlsGetValue(key)); + + if (handlers) { + for (exit_handlers::iterator it = handlers->begin(); + it != handlers->end(); + ++it) + { + //Call each exit handler + (*it)(); + } + + //Destroy the exit handlers delete handlers; - return -1; } } - // Attempt to add the handler to the list of exit handlers. - try + extern "C" BOOST_THREAD_DECL void on_process_exit(void) { - handlers->push_front(func); - } - catch (...) - { - return -1; + if (key != invalid_key) + { + TlsFree(key); + key = invalid_key; + } } - return 0; -} + #if defined(BOOST_THREAD_BUILD_DLL) + extern "C" void tss_cleanup_implemented(void) + { + //Don't need to do anything; this function's + //sole purpose is to cause a link error in cases + //where tss cleanup is not implemented by Boost.Threads + //as a reminder that user code is responsible for calling + //on_process_enter(), on_thread_exit(), and + //on_process_exit() at the appropriate times + //and implementing an empty tss_cleanup_implemented() + //function to eliminate the link error. + } -#endif // BOOST_THREAD_BUILD_DLL + #if defined(__BORLANDC__) + #define DllMain DllEntryPoint + #endif + extern "C" + BOOL WINAPI DllMain(HANDLE /*module*/, DWORD reason, LPVOID) + { + switch (reason) + { + case DLL_PROCESS_ATTACH: + { + on_process_enter(); + break; + } + case DLL_THREAD_ATTACH: + { + break; + } + case DLL_THREAD_DETACH: + { + on_thread_exit(); + break; + } + case DLL_PROCESS_DETACH: + { + on_thread_exit(); + on_process_exit(); + break; + } + } + return TRUE; + } + #endif // BOOST_THREAD_BUILD_DLL #endif // BOOST_HAS_WINTHREADS // Change Log: diff --git a/src/tss.cpp b/src/tss.cpp index fea176d7..34b1c71c 100644 --- a/src/tss.cpp +++ b/src/tss.cpp @@ -114,7 +114,7 @@ tss_slots* get_slots(bool alloc) std::auto_ptr temp(new tss_slots); #if defined(BOOST_HAS_WINTHREADS) - if (on_thread_exit(&tss_thread_exit) == -1) + if (add_thread_exit(&tss_thread_exit) == -1) return 0; if (!TlsSetValue(tss_data->native_key, temp.get())) return 0; @@ -198,7 +198,7 @@ void tss::cleanup(void* value) } // namespace detail } // namespace boost -#endif BOOST_THREAD_NO_TSS_CLEANUP +#endif //BOOST_THREAD_NO_TSS_CLEANUP // Change Log: // 6 Jun 01