-// 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.
// 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;
// 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().
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;
}
// 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);
// 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)) {
// 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_