mirror of
https://github.com/wolfpld/tracy.git
synced 2026-11-09 09:25:27 +00:00
Merge pull request #1504 from Lectem/windows-dll-unload-hang
Don't deadlock when joining threads from a DLL being unloaded.
This commit is contained in:
@@ -42,22 +42,56 @@ public:
|
||||
Thread( void(*func)( void* ptr ), void* ptr )
|
||||
: m_func( func )
|
||||
, m_ptr( ptr )
|
||||
, m_exit( CreateEventW( nullptr, TRUE, FALSE, nullptr ) )
|
||||
, m_hnd( CreateThread( nullptr, 0, Launch, this, 0, nullptr ) )
|
||||
{}
|
||||
|
||||
~Thread()
|
||||
{
|
||||
WaitForSingleObject( m_hnd, INFINITE );
|
||||
// The thread signals m_exit when it is done and then parks, instead of exiting, so that
|
||||
// it can be joined from DllMain (e.g. a static Profiler destroyed by FreeLibrary).
|
||||
// A normal thread exit needs the loader lock, which the joining thread already holds.
|
||||
HANDLE handles[2] = { m_exit, m_hnd };
|
||||
WaitForMultipleObjects( 2, handles, FALSE, INFINITE );
|
||||
CloseHandle( m_exit );
|
||||
if( InLoaderCallout() )
|
||||
{
|
||||
TerminateThread( m_hnd, 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
QueueUserAPC( WakeUp, m_hnd, 0 );
|
||||
WaitForSingleObject( m_hnd, INFINITE );
|
||||
}
|
||||
CloseHandle( m_hnd );
|
||||
}
|
||||
|
||||
HANDLE Handle() const { return m_hnd; }
|
||||
|
||||
private:
|
||||
static DWORD WINAPI Launch( void* ptr ) { ((Thread*)ptr)->m_func( ((Thread*)ptr)->m_ptr ); return 0; }
|
||||
static bool InLoaderCallout()
|
||||
{
|
||||
typedef BOOLEAN(NTAPI* IsWithinCallout)();
|
||||
static const auto fn = (IsWithinCallout)GetProcAddress( GetModuleHandleW( L"ntdll.dll" ), "RtlIsThreadWithinLoaderCallout" );
|
||||
return fn && fn();
|
||||
}
|
||||
|
||||
static void CALLBACK WakeUp( ULONG_PTR ) {}
|
||||
|
||||
static DWORD WINAPI Launch( void* ptr )
|
||||
{
|
||||
auto self = (Thread*)ptr;
|
||||
self->m_func( self->m_ptr );
|
||||
// *self may be gone as soon as m_exit is signaled.
|
||||
const HANDLE exit = self->m_exit;
|
||||
SetEvent( exit );
|
||||
SleepEx( INFINITE, TRUE );
|
||||
return 0;
|
||||
}
|
||||
|
||||
void(*m_func)( void* ptr );
|
||||
void* m_ptr;
|
||||
HANDLE m_exit;
|
||||
HANDLE m_hnd;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user