Use an alternate signal stack for the unexpected signals on the host.

This lets us report native stack overflow somewhat sensibly.

Change-Id: I841c285b2481aecc6edb0800f385ccc5665067ff
diff --git a/src/runtime_linux.cc b/src/runtime_linux.cc
index 4214003..c96b1e5 100644
--- a/src/runtime_linux.cc
+++ b/src/runtime_linux.cc
@@ -209,7 +209,7 @@
   memset(&action, 0, sizeof(action));
   sigemptyset(&action.sa_mask);
   action.sa_sigaction = HandleUnexpectedSignal;
-  action.sa_flags = SA_RESTART | SA_SIGINFO;
+  action.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
 
   int rc = 0;
   rc += sigaction(SIGILL, &action, NULL);
diff --git a/src/thread.cc b/src/thread.cc
index 27831a4..6fcbaca 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -189,6 +189,43 @@
   return stack_size;
 }
 
+static void SigAltStack(stack_t* new_stack, stack_t* old_stack) {
+  if (sigaltstack(new_stack, old_stack) == -1) {
+    PLOG(FATAL) << "sigaltstack failed";
+  }
+}
+
+static void SetUpAlternateSignalStack() {
+  // Create and set an alternate signal stack.
+  stack_t ss;
+  ss.ss_sp = new uint8_t[SIGSTKSZ];
+  ss.ss_size = SIGSTKSZ;
+  ss.ss_flags = 0;
+  CHECK(ss.ss_sp != NULL);
+  SigAltStack(&ss, NULL);
+
+  // Double-check that it worked.
+  ss.ss_sp = NULL;
+  SigAltStack(NULL, &ss);
+  VLOG(threads) << "Alternate signal stack is " << PrettySize(ss.ss_size) << " at " << ss.ss_sp;
+}
+
+static void TearDownAlternateSignalStack() {
+  // Get the pointer so we can free the memory.
+  stack_t ss;
+  SigAltStack(NULL, &ss);
+  uint8_t* allocated_signal_stack = reinterpret_cast<uint8_t*>(ss.ss_sp);
+
+  // Tell the kernel to stop using it.
+  ss.ss_sp = NULL;
+  ss.ss_flags = SS_DISABLE;
+  ss.ss_size = 0;
+  SigAltStack(&ss, NULL);
+
+  // Free it.
+  delete[] allocated_signal_stack;
+}
+
 void Thread::Create(Object* peer, size_t stack_size) {
   CHECK(peer != NULL);
 
@@ -223,6 +260,7 @@
   // thread hasn't been through here already...
   CHECK(Thread::Current() == NULL);
 
+  SetUpAlternateSignalStack();
   InitCpu();
   InitFunctionPointers();
   InitCardTable();
@@ -882,6 +920,8 @@
   delete debug_invoke_req_;
   delete trace_stack_;
   delete name_;
+
+  TearDownAlternateSignalStack();
 }
 
 void Thread::HandleUncaughtExceptions() {