From 0258f4a7b4ee0044f2e4ecba77dec2fd96ad76df Mon Sep 17 00:00:00 2001 From: Bartosz Taudul Date: Mon, 20 Aug 2018 01:05:09 +0200 Subject: [PATCH] Handle crashes on windows. When a crash happens, put all threads (bar the profiler and crash handling ones) into the freezer, send crash notification message, request profiler shutdown and when it does, terminate process. The list of ignored exceptions is sorta-kinda random at the moment and may need further expansion. --- client/TracyProfiler.cpp | 65 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/client/TracyProfiler.cpp b/client/TracyProfiler.cpp index 6318ee13..3aa64dcd 100644 --- a/client/TracyProfiler.cpp +++ b/client/TracyProfiler.cpp @@ -3,6 +3,7 @@ #ifdef _MSC_VER # include # include +# include #else # include #endif @@ -301,6 +302,65 @@ static const char* GetHostInfo() return buf; } +#ifdef _MSC_VER +static DWORD s_profilerThreadId = 0; + +LONG WINAPI CrashFilter( PEXCEPTION_POINTERS pExp ) +{ + if( pExp->ExceptionRecord->ExceptionCode == 0xe24c4a02 ) return EXCEPTION_CONTINUE_SEARCH; // LuaJIT + if( pExp->ExceptionRecord->ExceptionCode == 0xe06d7363 ) return EXCEPTION_CONTINUE_SEARCH; // MSVC C++ exceptions + if( pExp->ExceptionRecord->ExceptionCode == 0x406d1388 ) return EXCEPTION_CONTINUE_SEARCH; // MSVC thread naming magic + + Profiler::Message( "!!!CRASH!!!" ); + + HANDLE h = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 ); + if( h == INVALID_HANDLE_VALUE ) return EXCEPTION_CONTINUE_SEARCH; + + THREADENTRY32 te = { sizeof( te ) }; + if( !Thread32First( h, &te ) ) + { + CloseHandle( h ); + return EXCEPTION_CONTINUE_SEARCH; + } + + const auto pid = GetCurrentProcessId(); + const auto tid = GetCurrentThreadId(); + + do + { + if( te.th32OwnerProcessID == pid && te.th32ThreadID != tid && te.th32ThreadID != s_profilerThreadId ) + { + HANDLE th = OpenThread( THREAD_SUSPEND_RESUME, FALSE, te.th32ThreadID ); + if( th != INVALID_HANDLE_VALUE ) + { + SuspendThread( th ); + CloseHandle( th ); + } + } + } + while( Thread32Next( h, &te ) ); + CloseHandle( h ); + + { + Magic magic; + auto& token = s_token.ptr; + auto& tail = token->get_tail_index(); + auto item = token->enqueue_begin( magic ); + MemWrite( &item->hdr.type, QueueType::Crash ); + tail.store( magic + 1, std::memory_order_release ); + } + + std::this_thread::sleep_for( std::chrono::milliseconds( 500 ) ); + s_profiler.RequestShutdown(); + while( !s_profiler.HasShutdownFinished() ) { std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) ); }; + + TerminateProcess( GetCurrentProcess(), 1 ); + + return EXCEPTION_CONTINUE_SEARCH; +} +#endif + + enum { QueuePrealloc = 256 * 1024 }; // MSVC static initialization order solution. gcc/clang uses init_order() to avoid all this. @@ -441,6 +501,11 @@ Profiler::Profiler() new(s_thread) Thread( LaunchWorker, this ); SetThreadName( s_thread->Handle(), "Tracy Profiler" ); +#ifdef _MSC_VER + s_profilerThreadId = GetThreadId( s_thread->Handle() ); + AddVectoredExceptionHandler( 1, CrashFilter ); +#endif + #ifdef TRACY_HAS_CALLSTACK InitCallstack(); #endif