2
0
mirror of https://github.com/boostorg/thread.git synced 2026-01-29 20:12:10 +00:00
Files
thread/src/threadmon.cpp

146 lines
4.1 KiB
C++

// threadmon.cpp : Defines the entry point for the DLL application.
//
#define BOOST_THREADMON_EXPORTS
#include "threadmon.hpp"
#ifdef BOOST_HAS_WINTHREADS
#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 <set>
#include <algorithm>
typedef void (__cdecl * handler)(void);
typedef std::list<handler> exit_handlers;
typedef std::set<exit_handlers*> registered_handlers;
namespace
{
CRITICAL_SECTION cs;
DWORD key;
registered_handlers registry;
}
#if defined(__BORLANDC__)
#define DllMain DllEntryPoint
#endif
BOOL APIENTRY DllMain(HANDLE module, DWORD reason, LPVOID)
{
switch (reason)
{
case DLL_PROCESS_ATTACH:
InitializeCriticalSection(&cs);
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)();
// Remove the exit handler list from the registered lists and then destroy it.
EnterCriticalSection(&cs);
registry.erase(handlers);
LeaveCriticalSection(&cs);
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)();
}
// Destroy any remaining exit handlers. Above we assumed there'd only be the main
// thread left, but to insure we don't get memory leaks we won't make that assumption
// here.
EnterCriticalSection(&cs);
for (registered_handlers::iterator it = registry.begin(); it != registry.end(); ++it)
delete (*it);
LeaveCriticalSection(&cs);
DeleteCriticalSection(&cs);
TlsFree(key);
}
break;
}
return TRUE;
}
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)
{
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 register this new handler so that memory can be properly
// cleaned up.
try
{
EnterCriticalSection(&cs);
registry.insert(handlers);
LeaveCriticalSection(&cs);
}
catch (...)
{
LeaveCriticalSection(&cs);
delete handlers;
return -1;
}
}
// Attempt to add the handler to the list of exit handlers. If it's been previously
// added just report success and exit.
try
{
handlers->push_front(func);
}
catch (...)
{
return -1;
}
return 0;
}
#endif // BOOST_HAS_WINTHREADS