[llvm-commits] [llvm] r109717 - /llvm/trunk/lib/Support/CrashRecoveryContext.cpp

Daniel Dunbar daniel at zuster.org
Wed Jul 28 18:21:47 PDT 2010


Author: ddunbar
Date: Wed Jul 28 20:21:47 2010
New Revision: 109717

URL: http://llvm.org/viewvc/llvm-project?rev=109717&view=rev
Log:
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.

Modified:
    llvm/trunk/lib/Support/CrashRecoveryContext.cpp

Modified: llvm/trunk/lib/Support/CrashRecoveryContext.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/CrashRecoveryContext.cpp?rev=109717&r1=109716&r2=109717&view=diff
==============================================================================
--- llvm/trunk/lib/Support/CrashRecoveryContext.cpp (original)
+++ llvm/trunk/lib/Support/CrashRecoveryContext.cpp Wed Jul 28 20:21:47 2010
@@ -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 @@
   delete CRCI;
 }
 
+#ifdef LLVM_ON_WIN32
+
+// FIXME: No real Win32 implementation currently.
+
 void CrashRecoveryContext::Enable() {
   if (gCrashRecoveryEnabled)
     return;
@@ -58,6 +71,94 @@
   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) {





More information about the llvm-commits mailing list