[DO NOT MERGE] Improve signal catching and native stack dumps.

This works around the problem with abort(3) (and friends) on glibc,
and improves our ability to catch SIGSEGVs from the main thread, and
slightly improves our behavior if multiple threads are dying at once.
I think any remaining flakiness is only in this last case, and I'm
not sure whether we can actually improve that any further.

(cherry picked from commit dcaaea9d30f39622d0b1d9bbb68911173621e54b)

Conflicts:

	src/runtime_linux.cc

Change-Id: I9922f3ee4609799993635e1ed98a21363505a6ab
diff --git a/src/runtime.cc b/src/runtime.cc
index d8beae8..e1c3099 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -17,6 +17,7 @@
 #include "runtime.h"
 
 #include <signal.h>
+#include <sys/syscall.h>
 
 #include <cstdio>
 #include <cstdlib>
@@ -168,6 +169,7 @@
     LOG(INTERNAL_FATAL) << "Unexpectedly returned from abort hook!";
   }
 
+#if defined(__BIONIC__)
   // TODO: finish merging patches to fix abort(3) in bionic, then lose this!
   // Bionic doesn't implement POSIX semantics for abort(3) in a multi-threaded
   // process, so if we call abort(3) on a device, all threads in the process
@@ -178,7 +180,17 @@
   // We can also trivially tell the difference between a crash and
   // a deliberate abort by looking at the fault address.
   *reinterpret_cast<char*>(0xdeadd00d) = 38;
-  abort();
+#elif defined(__APPLE__)
+  // TODO: check that this actually gives good stack traces on the Mac!
+  pthread_kill(pthread_self(), SIGABRT);
+#else
+  // TODO: we ought to be able to use pthread_kill(3) here (or abort(3),
+  // which POSIX defines in terms of raise(3), which POSIX defines in terms
+  // of pthread_kill(3)). On Linux, though, libcorkscrew can't unwind through
+  // libpthread, which means the stacks we dump would be useless. Calling
+  // tgkill(2) directly avoids that.
+  syscall(__NR_tgkill, getpid(), GetTid(), SIGABRT);
+#endif
   // notreached
 }
 
diff --git a/src/runtime_linux.cc b/src/runtime_linux.cc
index e2c806d..3e39fa2 100644
--- a/src/runtime_linux.cc
+++ b/src/runtime_linux.cc
@@ -258,6 +258,9 @@
 };
 
 static void HandleUnexpectedSignal(int signal_number, siginfo_t* info, void* raw_context) {
+  static Mutex unexpected_signal_lock("unexpected signal lock");
+  MutexLock mu(unexpected_signal_lock);
+
   bool has_address = (signal_number == SIGILL || signal_number == SIGBUS ||
                       signal_number == SIGFPE || signal_number == SIGSEGV);
 
@@ -283,6 +286,15 @@
     while (true) {
     }
   }
+
+  // Remove our signal handler for this signal...
+  struct sigaction action;
+  memset(&action, 0, sizeof(action));
+  sigemptyset(&action.sa_mask);
+  action.sa_handler = SIG_DFL;
+  sigaction(signal_number, &action, NULL);
+  // ...and re-raise so we die with the appropriate status.
+  kill(getpid(), signal_number);
 }
 
 void Runtime::InitPlatformSignalHandlers() {
@@ -291,11 +303,12 @@
   memset(&action, 0, sizeof(action));
   sigemptyset(&action.sa_mask);
   action.sa_sigaction = HandleUnexpectedSignal;
-  action.sa_flags = SA_RESTART;
   // Use the three-argument sa_sigaction handler.
   action.sa_flags |= SA_SIGINFO;
-  // Remove ourselves as signal handler for this signal, in case of recursion.
-  action.sa_flags |= SA_RESETHAND;
+#if !defined(__APPLE__)
+  // Use the alternate signal stack so we can catch stack overflows.
+  action.sa_flags |= SA_ONSTACK;
+#endif
 
   int rc = 0;
   rc += sigaction(SIGILL, &action, NULL);