Added support for PowerPC.
[platform/upstream/glog.git] / src / signalhandler.cc
index 8e30297..a7aef8b 100644 (file)
@@ -1,4 +1,32 @@
-// Copyright 2008 Google Inc. All Rights Reserved.
+// Copyright (c) 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
 // Author: Satoru Takabayashi
 //
 // Implementation of InstallFailureSignalHandler().
 #ifdef HAVE_UCONTEXT_H
 # include <ucontext.h>
 #endif
+#ifdef HAVE_SYS_UCONTEXT_H
+# include <sys/ucontext.h>
+#endif
 #include <algorithm>
 
 _START_GOOGLE_NAMESPACE_
 
-// There is a better way, but this is good enough in this file.
-#define NAIVE_ARRAYSIZE(a) (sizeof(a) / sizeof(*(a)))
+// TOOD(hamaji): Use signal instead of sigaction?
+#ifdef HAVE_SIGACTION
 
 namespace {
 
-// Wrapper of __sync_val_compare_and_swap. If the GCC extension isn't
-// defined, we try the CPU specific logics (we only support x86 and
-// x86_64 for now) first, then use a naive implementation, which has a
-// race condition.
-template<typename T>
-inline T* sync_val_compare_and_swap(T** ptr, T* oldval, T* newval) {
-#if defined(HAVE___SYNC_VAL_COMPARE_AND_SWAP)
-  return __sync_val_compare_and_swap(ptr, oldval, newval);
-#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
-  T* ret;
-  __asm__ __volatile__("lock; cmpxchg %1, (%2);"
-                       :"=a"(ret)
-                       :"r"(newval), "r"(ptr), "a"(oldval)
-                       :"memory", "cc");
-  return ret;
-#else
-  T* ret = *ptr;
-  if (ret == oldval) {
-    *ptr = newval;
-  }
-  return ret;
-#endif
-}
-
 // We'll install the failure signal handler for these signals.  We could
 // use strsignal() to get signal names, but we don't use it to avoid
 // introducing yet another #ifdef complication.
@@ -65,7 +72,7 @@ const struct {
 
 // Returns the program counter from signal context, NULL if unknown.
 void* GetPC(void* ucontext_in_void) {
-#if defined(HAVE_UCONTEXT_H) && defined(PC_FROM_UCONTEXT)
+#if (defined(HAVE_UCONTEXT_H) || defined(HAVE_SYS_UCONTEXT_H)) && defined(PC_FROM_UCONTEXT)
   if (ucontext_in_void != NULL) {
     ucontext_t *context = reinterpret_cast<ucontext_t *>(ucontext_in_void);
     return (void*)context->PC_FROM_UCONTEXT;
@@ -138,7 +145,9 @@ class MinimalFormatter {
 
 // Writes the given data with the size to the standard error.
 void WriteToStderr(const char* data, int size) {
-  write(STDERR_FILENO, data, size);
+  if (write(STDERR_FILENO, data, size) < 0) {
+    // Ignore errors.
+  }
 }
 
 // The writer function can be changed by InstallFailureWriter().
@@ -163,7 +172,7 @@ void DumpTimeInfo() {
 void DumpSignalInfo(int signal_number, siginfo_t *siginfo) {
   // Get the signal name.
   const char* signal_name = NULL;
-  for (int i = 0; i < NAIVE_ARRAYSIZE(kFailureSignals); ++i) {
+  for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) {
     if (signal_number == kFailureSignals[i].number) {
       signal_name = kFailureSignals[i].name;
     }
@@ -231,7 +240,8 @@ void DumpStackFrameInfo(const char* prefix, void* pc) {
 
 // Invoke the default signal handler.
 void InvokeDefaultSignalHandler(int signal_number) {
-  struct sigaction sig_action = {};  // Zero-clear.
+  struct sigaction sig_action;
+  memset(&sig_action, 0, sizeof(sig_action));
   sigemptyset(&sig_action.sa_mask);
   sig_action.sa_handler = SIG_DFL;
   sigaction(signal_number, &sig_action, NULL);
@@ -262,9 +272,10 @@ void FailureSignalHandler(int signal_number,
   // old value (value returned from __sync_val_compare_and_swap) is
   // different from the original value (in this case NULL).
   pthread_t* old_thread_id_pointer =
-      sync_val_compare_and_swap(&g_entered_thread_id_pointer,
-                                static_cast<pthread_t*>(NULL),
-                                &my_thread_id);
+      glog_internal_namespace_::sync_val_compare_and_swap(
+          &g_entered_thread_id_pointer,
+          static_cast<pthread_t*>(NULL),
+          &my_thread_id);
   if (old_thread_id_pointer != NULL) {
     // We've already entered the signal handler.  What should we do?
     if (pthread_equal(my_thread_id, *g_entered_thread_id_pointer)) {
@@ -295,33 +306,70 @@ void FailureSignalHandler(int signal_number,
   // Get the stack traces.
   void *stack[32];
   // +1 to exclude this function.
-  const int depth = GetStackTrace(stack, NAIVE_ARRAYSIZE(stack), 1);
+  const int depth = GetStackTrace(stack, ARRAYSIZE(stack), 1);
   DumpSignalInfo(signal_number, signal_info);
   // Dump the stack traces.
   for (int i = 0; i < depth; ++i) {
     DumpStackFrameInfo("    ", stack[i]);
   }
 #endif
+
+  // *** TRANSITION ***
+  //
+  // BEFORE this point, all code must be async-termination-safe!
+  // (See WARNING above.)
+  //
+  // AFTER this point, we do unsafe things, like using LOG()!
+  // The process could be terminated or hung at any time.  We try to
+  // do more useful things first and riskier things later.
+
+  // Flush the logs before we do anything in case 'anything'
+  // causes problems.
+  FlushLogFilesUnsafe(0);
+
   // Kill ourself by the default signal handler.
   InvokeDefaultSignalHandler(signal_number);
 }
 
 }  // namespace
 
+#endif  // HAVE_SIGACTION
+
+namespace glog_internal_namespace_ {
+
+bool IsFailureSignalHandlerInstalled() {
+#ifdef HAVE_SIGACTION
+  struct sigaction sig_action;
+  memset(&sig_action, 0, sizeof(sig_action));
+  sigemptyset(&sig_action.sa_mask);
+  sigaction(SIGABRT, NULL, &sig_action);
+  if (sig_action.sa_sigaction == &FailureSignalHandler)
+    return true;
+#endif  // HAVE_SIGACTION
+  return false;
+}
+
+}  // namespace glog_internal_namespace_
+
 void InstallFailureSignalHandler() {
+#ifdef HAVE_SIGACTION
   // Build the sigaction struct.
-  struct sigaction sig_action = {};  // Zero-clear.
+  struct sigaction sig_action;
+  memset(&sig_action, 0, sizeof(sig_action));
   sigemptyset(&sig_action.sa_mask);
   sig_action.sa_flags |= SA_SIGINFO;
   sig_action.sa_sigaction = &FailureSignalHandler;
 
-  for (int i = 0; i < NAIVE_ARRAYSIZE(kFailureSignals); ++i) {
+  for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) {
     CHECK_ERR(sigaction(kFailureSignals[i].number, &sig_action, NULL));
   }
+#endif  // HAVE_SIGACTION
 }
 
 void InstallFailureWriter(void (*writer)(const char* data, int size)) {
+#ifdef HAVE_SIGACTION
   g_failure_writer = writer;
+#endif  // HAVE_SIGACTION
 }
 
 _END_GOOGLE_NAMESPACE_