mirror of
https://github.com/RPCSX/llvm.git
synced 2024-11-28 22:20:37 +00:00
CrashRecoveryContext: Add a simple POSIX implementation.
- This works, but won't handle crashes on stack overflow, or signals delivered to a thread other than the one that crashed. The latter is particular annoying on Darwin, because SIGABRT tends to go to the main thread. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@109717 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
4bd94f7bbe
commit
d9082dfd9a
@ -9,20 +9,29 @@
|
||||
|
||||
#include "llvm/Support/CrashRecoveryContext.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/System/ThreadLocal.h"
|
||||
#include <setjmp.h>
|
||||
#include <cstdio>
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
|
||||
struct CrashRecoveryContextImpl;
|
||||
|
||||
static sys::ThreadLocal<const CrashRecoveryContextImpl> CurrentContext;
|
||||
|
||||
struct CrashRecoveryContextImpl {
|
||||
std::string Backtrace;
|
||||
::jmp_buf JumpBuffer;
|
||||
volatile unsigned Failed : 1;
|
||||
|
||||
public:
|
||||
CrashRecoveryContextImpl() : Failed(false) {}
|
||||
CrashRecoveryContextImpl() : Failed(false) {
|
||||
CurrentContext.set(this);
|
||||
}
|
||||
~CrashRecoveryContextImpl() {
|
||||
CurrentContext.set(0);
|
||||
}
|
||||
|
||||
void HandleCrash() {
|
||||
assert(!Failed && "Crash recovery context already failed!");
|
||||
@ -44,6 +53,10 @@ CrashRecoveryContext::~CrashRecoveryContext() {
|
||||
delete CRCI;
|
||||
}
|
||||
|
||||
#ifdef LLVM_ON_WIN32
|
||||
|
||||
// FIXME: No real Win32 implementation currently.
|
||||
|
||||
void CrashRecoveryContext::Enable() {
|
||||
if (gCrashRecoveryEnabled)
|
||||
return;
|
||||
@ -58,6 +71,94 @@ void CrashRecoveryContext::Disable() {
|
||||
gCrashRecoveryEnabled = false;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// Generic POSIX implementation.
|
||||
//
|
||||
// This implementation relies on synchronous signals being delivered to the
|
||||
// current thread. We use a thread local object to keep track of the active
|
||||
// crash recovery context, and install signal handlers to invoke HandleCrash on
|
||||
// the active object.
|
||||
//
|
||||
// This implementation does not to attempt to chain signal handlers in any
|
||||
// reliable fashion -- if we get a signal outside of a crash recovery context we
|
||||
// simply disable crash recovery and raise the signal again.
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
static struct {
|
||||
int Signal;
|
||||
struct sigaction PrevAction;
|
||||
} SignalInfo[] = {
|
||||
{ SIGABRT, {} },
|
||||
{ SIGBUS, {} },
|
||||
{ SIGFPE, {} },
|
||||
{ SIGILL, {} },
|
||||
{ SIGSEGV, {} },
|
||||
{ SIGTRAP, {} },
|
||||
};
|
||||
static const unsigned NumSignals = sizeof(SignalInfo) / sizeof(SignalInfo[0]);
|
||||
|
||||
static void CrashRecoverySignalHandler(int Signal) {
|
||||
// Lookup the current thread local recovery object.
|
||||
const CrashRecoveryContextImpl *CRCI = CurrentContext.get();
|
||||
|
||||
if (!CRCI) {
|
||||
// We didn't find a crash recovery context -- this means either we got a
|
||||
// signal on a thread we didn't expect it on, the application got a signal
|
||||
// outside of a crash recovery context, or something else went horribly
|
||||
// wrong.
|
||||
//
|
||||
// Disable crash recovery and raise the signal again. The assumption here is
|
||||
// that the enclosing application will terminate soon, and we won't want to
|
||||
// attempt crash recovery again.
|
||||
//
|
||||
// This call of Disable isn't thread safe, but it doesn't actually matter.
|
||||
CrashRecoveryContext::Disable();
|
||||
raise(Signal);
|
||||
}
|
||||
|
||||
// Unblock the signal we received.
|
||||
sigset_t SigMask;
|
||||
sigemptyset(&SigMask);
|
||||
sigaddset(&SigMask, Signal);
|
||||
sigprocmask(SIG_UNBLOCK, &SigMask, 0);
|
||||
|
||||
if (CRCI)
|
||||
const_cast<CrashRecoveryContextImpl*>(CRCI)->HandleCrash();
|
||||
}
|
||||
|
||||
void CrashRecoveryContext::Enable() {
|
||||
if (gCrashRecoveryEnabled)
|
||||
return;
|
||||
|
||||
gCrashRecoveryEnabled = true;
|
||||
|
||||
// Setup the signal handler.
|
||||
struct sigaction Handler;
|
||||
Handler.sa_handler = CrashRecoverySignalHandler;
|
||||
Handler.sa_flags = 0;
|
||||
sigemptyset(&Handler.sa_mask);
|
||||
|
||||
for (unsigned i = 0; i != NumSignals; ++i) {
|
||||
sigaction(SignalInfo[i].Signal, &Handler,
|
||||
&SignalInfo[i].PrevAction);
|
||||
}
|
||||
}
|
||||
|
||||
void CrashRecoveryContext::Disable() {
|
||||
if (!gCrashRecoveryEnabled)
|
||||
return;
|
||||
|
||||
gCrashRecoveryEnabled = false;
|
||||
|
||||
// Restore the previous signal handlers.
|
||||
for (unsigned i = 0; i != NumSignals; ++i)
|
||||
sigaction(SignalInfo[i].Signal, &SignalInfo[i].PrevAction, 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool CrashRecoveryContext::RunSafely(void (*Fn)(void*), void *UserData) {
|
||||
// If crash recovery is disabled, do nothing.
|
||||
if (gCrashRecoveryEnabled) {
|
||||
|
Loading…
Reference in New Issue
Block a user