Skip to content

Commit

Permalink
Sleep infinitely on secondary crashing threads
Browse files Browse the repository at this point in the history
Sleeping infinitely instead of continuing should be better for crash reporting reliability.

Also, change the crashing thread detection to use thread ID instead of Thread*. It is fixing bogus "Fatal error while logging another fatal error." message when the crash occurs without Thread* being setup.
  • Loading branch information
jkotas committed Jul 21, 2022
1 parent f5469fe commit 0bb8932
Showing 1 changed file with 22 additions and 17 deletions.
39 changes: 22 additions & 17 deletions src/coreclr/vm/eepolicy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -325,25 +325,31 @@ void LogInfoForFatalError(UINT exitCode, LPCWSTR pszMessage, LPCWSTR errorSource
{
WRAPPER_NO_CONTRACT;

static Thread *const FatalErrorNotSeenYet = nullptr;
static Thread *const FatalErrorLoggingFinished = reinterpret_cast<Thread *>(1);
static size_t s_pCrashingThreadID;

static Thread *volatile s_pCrashingThread = FatalErrorNotSeenYet;
size_t currentThreadID;
#ifndef TARGET_UNIX
currentThreadID = GetCurrentThreadId();
#else
currentThreadID = PAL_GetCurrentOSThreadId();
#endif

Thread *pThread = GetThreadNULLOk();
Thread *pPreviousThread = InterlockedCompareExchangeT<Thread *>(&s_pCrashingThread, pThread, FatalErrorNotSeenYet);
size_t previousThreadID = InterlockedCompareExchangeT<size_t>(&s_pCrashingThreadID, currentThreadID, 0);

if (pPreviousThread == pThread)
{
PrintToStdErrA("Fatal error while logging another fatal error.\n");
return;
}
else if (pPreviousThread != nullptr)
// Let the first crashing thread take care of the reporting.
if (previousThreadID != 0)
{
GCX_PREEMP(); // Avoid blocking other threads that may be trying to suspend the runtime
while (s_pCrashingThread != FatalErrorLoggingFinished)
if (previousThreadID == currentThreadID)
{
PrintToStdErrA("Fatal error while logging another fatal error.\n");
}
else
{
ClrSleepEx(50, /*bAlertable*/ FALSE);
// Switch to preemptive mode to avoid blocking the crashing thread. It may try to suspend the runtime
// for GC during the stacktrace reporting.
GCX_PREEMP();

ClrSleepEx(INFINITE, /*bAlertable*/ FALSE);
}
return;
}
Expand Down Expand Up @@ -379,9 +385,10 @@ void LogInfoForFatalError(UINT exitCode, LPCWSTR pszMessage, LPCWSTR errorSource

PrintToStdErrA("\n");

Thread* pThread = GetThreadNULLOk();
if (pThread && errorSource == NULL)
{
LogCallstackForLogWorker(GetThread());
LogCallstackForLogWorker(pThread);

if (argExceptionString != NULL) {
PrintToStdErrW(argExceptionString);
Expand All @@ -392,8 +399,6 @@ void LogInfoForFatalError(UINT exitCode, LPCWSTR pszMessage, LPCWSTR errorSource
{
}
EX_END_CATCH(SwallowAllExceptions)

InterlockedCompareExchangeT<Thread *>(&s_pCrashingThread, FatalErrorLoggingFinished, pThread);
}

//This starts FALSE and then converts to true if HandleFatalError has ever been called by a GC thread
Expand Down

0 comments on commit 0bb8932

Please sign in to comment.