/*
- * Copyright 2013 Facebook, Inc.
+ * Copyright 2014 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
void FatalSignalCallbackRegistry::run() {
if (!installed_) {
- return; // Shouldn't happen
+ return;
}
for (auto& fn : handlers_) {
for (auto p = kFatalSignals; p->name; ++p) {
if (p->number == signum) {
sigaction(signum, &p->oldAction, nullptr);
+ raise(signum);
return;
}
}
print("), stack trace: ***\n");
}
-void dumpStackTrace() {
+namespace {
+constexpr size_t kDefaultCapacity = 500;
+
+// Note: not thread-safe, but that's okay, as we only let one thread
+// in our signal handler at a time.
+SignalSafeElfCache signalSafeElfCache(kDefaultCapacity);
+} // namespace
+
+void dumpStackTrace(bool symbolize) __attribute__((noinline));
+
+void dumpStackTrace(bool symbolize) {
SCOPE_EXIT { fsyncNoInt(STDERR_FILENO); };
// Get and symbolize stack trace
constexpr size_t kMaxStackTraceDepth = 100;
FrameArray<kMaxStackTraceDepth> addresses;
// Skip the getStackTrace frame
- if (!getStackTrace(addresses)) {
+ if (!getStackTraceSafe(addresses)) {
print("(error retrieving stack trace)\n");
- } else {
- Symbolizer symbolizer;
+ } else if (symbolize) {
+ Symbolizer symbolizer(&signalSafeElfCache);
symbolizer.symbolize(addresses);
- FDSymbolizePrinter printer(STDERR_FILENO);
- printer.print(addresses);
+ FDSymbolizePrinter printer(STDERR_FILENO, SymbolizePrinter::COLOR_IF_TTY);
+
+ // Skip the top 2 frames:
+ // getStackTraceSafe
+ // dumpStackTrace (here)
+ //
+ // Leaving signalHandler on the stack for clarity, I think.
+ printer.println(addresses, 2);
+ } else {
+ print("(safe mode, symbolizer not available)\n");
+ AddressFormatter formatter;
+ for (ssize_t i = 0; i < addresses.frameCount; ++i) {
+ print(formatter.format(addresses.addresses[i]));
+ print("\n");
+ }
}
}
-std::atomic<pthread_t*> gSignalThread;
+// On Linux, pthread_t is a pointer, so 0 is an invalid value, which we
+// take to indicate "no thread in the signal handler".
+//
+// POSIX defines PTHREAD_NULL for this purpose, but that's not available.
+constexpr pthread_t kInvalidThreadId = 0;
+
+std::atomic<pthread_t> gSignalThread(kInvalidThreadId);
+std::atomic<bool> gInRecursiveSignalHandler(false);
// Here be dragons.
void innerSignalHandler(int signum, siginfo_t* info, void* uctx) {
// First, let's only let one thread in here at a time.
pthread_t myId = pthread_self();
- pthread_t* prevSignalThread = nullptr;
- while (!gSignalThread.compare_exchange_strong(prevSignalThread, &myId)) {
- if (pthread_equal(*prevSignalThread, myId)) {
- print("Entered fatal signal handler recursively. We're in trouble.\n");
+ pthread_t prevSignalThread = kInvalidThreadId;
+ while (!gSignalThread.compare_exchange_strong(prevSignalThread, myId)) {
+ if (pthread_equal(prevSignalThread, myId)) {
+ // First time here. Try to dump the stack trace without symbolization.
+ // If we still fail, well, we're mightily screwed, so we do nothing the
+ // next time around.
+ if (!gInRecursiveSignalHandler.exchange(true)) {
+ print("Entered fatal signal handler recursively. We're in trouble.\n");
+ dumpStackTrace(false); // no symbolization
+ }
return;
}
ts.tv_nsec = 100L * 1000 * 1000; // 100ms
nanosleep(&ts, nullptr);
- prevSignalThread = nullptr;
+ prevSignalThread = kInvalidThreadId;
}
dumpTimeInfo();
dumpSignalInfo(signum, info);
- dumpStackTrace();
+ dumpStackTrace(true); // with symbolization
// Run user callbacks
gFatalSignalCallbackRegistry->run();
SCOPE_EXIT { fsyncNoInt(STDERR_FILENO); };
innerSignalHandler(signum, info, uctx);
- gSignalThread = nullptr;
+ gSignalThread = kInvalidThreadId;
// Kill ourselves with the previous handler.
callPreviousSignalHandler(signum);
}
gFatalSignalCallbackRegistry->add(cb);
}
+void installFatalSignalCallbacks() {
+ gFatalSignalCallbackRegistry->markInstalled();
+}
+
namespace {
std::atomic<bool> gAlreadyInstalled;
return;
}
- gFatalSignalCallbackRegistry->markInstalled();
-
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sigemptyset(&sa.sa_mask);
}
}} // namespaces
-