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:
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user