2
0
mirror of https://github.com/boostorg/thread.git synced 2026-01-22 17:52:18 +00:00

Add hooks for users to provide their own tss cleanup in win32 statically linked builds.

[SVN r23583]
This commit is contained in:
Michael Glassford
2004-07-15 14:26:10 +00:00
parent 50c034f650
commit 5472ebdfde
4 changed files with 158 additions and 111 deletions

View File

@@ -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

View File

@@ -14,8 +14,6 @@
#include <boost/thread/detail/config.hpp>
#ifndef BOOST_THREAD_NO_TSS_CLEANUP
#include <boost/utility.hpp>
#include <boost/function.hpp>
#include <boost/thread/exceptions.hpp>
@@ -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

View File

@@ -12,132 +12,170 @@
#include <boost/thread/detail/config.hpp>
#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 <boost/thread/detail/threadmon.hpp>
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#include <windows.h>
#ifdef BOOST_MSVC
# pragma warning(disable : 4786)
#endif
#include <list>
typedef void (__cdecl * handler)(void);
typedef std::list<handler> 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<exit_handlers*>(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<exit_handlers*>(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<exit_handlers*>(TlsGetValue(key));
if (!handlers)
#define WIN32_LEAN_AND_MEAN
//Exclude rarely-used stuff from Windows headers
#include <windows.h>
#ifdef BOOST_MSVC
# pragma warning(disable : 4786)
#endif
#include <list>
#include <boost/thread/detail/threadmon.hpp>
typedef void (__cdecl * handler)(void);
typedef std::list<handler> 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<exit_handlers*>(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<exit_handlers*>(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:

View File

@@ -114,7 +114,7 @@ tss_slots* get_slots(bool alloc)
std::auto_ptr<tss_slots> 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