10#include "llvm/Config/llvm-config.h"
23struct CrashRecoveryContextImpl;
26struct CrashRecoveryContextImpl {
31 const CrashRecoveryContextImpl *Next;
35 volatile unsigned Failed : 1;
36 unsigned SwitchedThread : 1;
37 unsigned ValidJumpBuffer : 1;
41 : CRC(CRC),
Failed(
false), SwitchedThread(
false), ValidJumpBuffer(
false) {
42 Next = CurrentContext;
43 CurrentContext =
this;
45 ~CrashRecoveryContextImpl() {
47 CurrentContext = Next;
52 void setSwitchedThread() {
53#if defined(LLVM_ENABLE_THREADS) && LLVM_ENABLE_THREADS != 0
54 SwitchedThread =
true;
62 void HandleCrash(
int RetCode, uintptr_t Context) {
65 CurrentContext = Next;
67 assert(!Failed &&
"Crash recovery context already failed!");
77 longjmp(JumpBuffer, 1);
84std::mutex &getCrashRecoveryContextMutex() {
85 static std::mutex CrashRecoveryContextMutex;
86 return CrashRecoveryContextMutex;
89static bool gCrashRecoveryEnabled =
false;
111 IsRecoveringFromCrash =
this;
119 IsRecoveringFromCrash = PC;
121 CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *) Impl;
126 return IsRecoveringFromCrash !=
nullptr;
130 if (!gCrashRecoveryEnabled)
133 const CrashRecoveryContextImpl *CRCI = CurrentContext;
141 std::lock_guard<std::mutex> L(getCrashRecoveryContextMutex());
143 if (gCrashRecoveryEnabled)
145 gCrashRecoveryEnabled =
true;
150 std::lock_guard<std::mutex> L(getCrashRecoveryContextMutex());
151 if (!gCrashRecoveryEnabled)
153 gCrashRecoveryEnabled =
false;
174 head->prev =
nullptr;
201static int ExceptionFilter(_EXCEPTION_POINTERS *Except) {
203 const CrashRecoveryContextImpl *CRCI = CurrentContext;
209 return EXCEPTION_CONTINUE_SEARCH;
212 int RetCode = (int)Except->ExceptionRecord->ExceptionCode;
213 if ((RetCode & 0xF0000000) == 0xE0000000)
214 RetCode &= ~0xF0000000;
217 const_cast<CrashRecoveryContextImpl *
>(CRCI)->HandleCrash(
218 RetCode,
reinterpret_cast<uintptr_t
>(Except));
220 return EXCEPTION_EXECUTE_HANDLER;
223#if defined(__clang__) && defined(_M_IX86)
225__attribute__((optnone))
228 if (!gCrashRecoveryEnabled) {
232 assert(!Impl &&
"Crash recovery context already initialized!");
233 Impl =
new CrashRecoveryContextImpl(
this);
236 } __except (ExceptionFilter(GetExceptionInformation())) {
266static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo)
270 constexpr ULONG DbgPrintExceptionWideC = 0x4001000AL;
271 switch (ExceptionInfo->ExceptionRecord->ExceptionCode)
273 case DBG_PRINTEXCEPTION_C:
274 case DbgPrintExceptionWideC:
276 return EXCEPTION_CONTINUE_EXECUTION;
280 const CrashRecoveryContextImpl *CRCI = CurrentContext;
286 return EXCEPTION_CONTINUE_SEARCH;
292 int RetCode = (int)ExceptionInfo->ExceptionRecord->ExceptionCode;
293 if ((RetCode & 0xF0000000) == 0xE0000000)
294 RetCode &= ~0xF0000000;
297 const_cast<CrashRecoveryContextImpl *
>(CRCI)->HandleCrash(
298 RetCode,
reinterpret_cast<uintptr_t
>(ExceptionInfo));
317 PVOID handle = ::AddVectoredExceptionHandler(1, ExceptionHandler);
318 sCurrentExceptionHandle = handle;
322 PVOID currentHandle =
const_cast<PVOID
>(sCurrentExceptionHandle);
325 ::RemoveVectoredExceptionHandler(currentHandle);
328 sCurrentExceptionHandle = NULL;
348 { SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV, SIGTRAP };
354 const CrashRecoveryContextImpl *CRCI = CurrentContext;
376 sigemptyset(&SigMask);
377 sigaddset(&SigMask, Signal);
378 sigprocmask(SIG_UNBLOCK, &SigMask,
nullptr);
383 int RetCode = 128 + Signal;
386 if (Signal == SIGPIPE)
390 const_cast<CrashRecoveryContextImpl *
>(CRCI)->HandleCrash(RetCode, Signal);
395 struct sigaction Handler;
397 Handler.sa_flags = 0;
398 sigemptyset(&Handler.sa_mask);
415 if (gCrashRecoveryEnabled) {
416 assert(!Impl &&
"Crash recovery context already initialized!");
417 CrashRecoveryContextImpl *CRCI =
new CrashRecoveryContextImpl(
this);
420 CRCI->ValidJumpBuffer =
true;
421 if (setjmp(CRCI->JumpBuffer) != 0) {
438 ::RaiseException(0xE0000000 |
RetCode, 0, 0, NULL);
442 CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *)Impl;
443 assert(CRCI &&
"Crash recovery context never initialized!");
444 CRCI->HandleCrash(
RetCode, 0 );
456 if (Code != 0xC && Code != 8)
471 ::RaiseException(
RetCode, 0, 0, NULL);
482 setpriority(PRIO_DARWIN_THREAD, 0, PRIO_DARWIN_BG);
488 return getpriority(PRIO_DARWIN_THREAD, 0) == 1;
495struct RunSafelyOnThreadInfo {
498 bool UseBackgroundPriority;
504 RunSafelyOnThreadInfo *
Info =
505 reinterpret_cast<RunSafelyOnThreadInfo*
>(UserData);
507 if (
Info->UseBackgroundPriority)
513 unsigned RequestedStackSize) {
515 RunSafelyOnThreadInfo
Info = { Fn,
this, UseBackgroundPriority,
false };
518 : std::optional<unsigned>(RequestedStackSize),
522 if (CrashRecoveryContextImpl *CRC = (CrashRecoveryContextImpl *)Impl)
523 CRC->setSwitchedThread();
static void cleanup(BlockFrequencyInfoImplBase &BFI)
Clear all memory not needed downstream.
Analysis containing CSE Info
#define LLVM_THREAD_LOCAL
\macro LLVM_THREAD_LOCAL A thread-local storage specifier which can be used with globals,...
static bool hasThreadBackgroundPriority()
static const unsigned NumSignals
static const int Signals[]
static void CrashRecoverySignalHandler(int Signal)
static void RunSafelyOnThread_Dispatch(void *UserData)
static void setThreadBackgroundPriority()
static void uninstallExceptionOrSignalHandlers()
static struct sigaction PrevActions[NumSignals]
static void installExceptionOrSignalHandlers()
This file contains definitions of exit codes for exit() function.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
Abstract base class of cleanup handlers.
virtual ~CrashRecoveryContextCleanup()
virtual void recoverResources()=0
Crash recovery helper object.
static bool isCrash(int RetCode)
Return true if RetCode indicates that a signal or an exception occurred.
static CrashRecoveryContext * GetCurrent()
Return the active context, if the code is currently executing in a thread which is in a protected con...
void HandleExit(int RetCode)
Explicitly trigger a crash recovery in the current process, and return failure from RunSafely().
static void Enable()
Enable crash recovery.
bool DumpStackAndCleanupOnFailure
Selects whether handling of failures should be done in the same way as for regular crashes.
void unregisterCleanup(CrashRecoveryContextCleanup *cleanup)
bool RunSafely(function_ref< void()> Fn)
Execute the provided callback function (with the given arguments) in a protected context.
static void Disable()
Disable crash recovery.
int RetCode
In case of a crash, this is the crash identifier.
static bool isRecoveringFromCrash()
Return true if the current thread is recovering from a crash.
static bool throwIfCrash(int RetCode)
Throw again a signal or an exception, after it was catched once by a CrashRecoveryContext.
void registerCleanup(CrashRecoveryContextCleanup *cleanup)
Register cleanup handler, which is used when the recovery context is finished.
bool RunSafelyOnThread(function_ref< void()>, unsigned RequestedStackSize=0)
Execute the provide callback function (with the given arguments) in a protected context which is run ...
An efficient, type-erasing, non-owning reference to a callable.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
void DisableSystemDialogsOnCrash()
Disable all system dialog boxes that appear when the process crashes.
void unregisterHandlers()
void CleanupOnSignal(uintptr_t Context)
This function does the following:
This is an optimization pass for GlobalISel generic memory operations.
testing::Matcher< const detail::ErrorHolder & > Failed()