Commit c1beec58 authored by Dan Melnic's avatar Dan Melnic Committed by Facebook GitHub Bot

Add support for specifying which fatal signals to handle

Summary: Add support for specifying which fatal signals to handle

Reviewed By: simpkins

Differential Revision: D20672281

fbshipit-source-id: 16696abcf551efcd932f5b56b336d6c5bc0d7a55
parent 91a0da83
...@@ -40,6 +40,10 @@ ...@@ -40,6 +40,10 @@
namespace folly { namespace folly {
namespace symbolizer { namespace symbolizer {
const unsigned long kAllFatalSignals = (1UL << SIGSEGV) | (1UL << SIGILL) |
(1UL << SIGFPE) | (1UL << SIGABRT) | (1UL << SIGBUS) | (1UL << SIGTERM) |
(1UL << SIGQUIT);
namespace { namespace {
/** /**
...@@ -489,7 +493,7 @@ bool isSmallSigAltStackEnabled() { ...@@ -489,7 +493,7 @@ bool isSmallSigAltStackEnabled() {
} // namespace } // namespace
void installFatalSignalHandler() { void installFatalSignalHandler(std::bitset<64> signals) {
if (gAlreadyInstalled.exchange(true)) { if (gAlreadyInstalled.exchange(true)) {
// Already done. // Already done.
return; return;
...@@ -530,7 +534,10 @@ void installFatalSignalHandler() { ...@@ -530,7 +534,10 @@ void installFatalSignalHandler() {
sa.sa_sigaction = &signalHandler; sa.sa_sigaction = &signalHandler;
for (auto p = kFatalSignals; p->name; ++p) { for (auto p = kFatalSignals; p->name; ++p) {
CHECK_ERR(sigaction(p->number, &sa, &p->oldAction)); if ((p->number < static_cast<int>(signals.size())) &&
signals.test(p->number)) {
CHECK_ERR(sigaction(p->number, &sa, &p->oldAction));
}
} }
} }
} // namespace symbolizer } // namespace symbolizer
......
...@@ -16,19 +16,27 @@ ...@@ -16,19 +16,27 @@
#pragma once #pragma once
#include <bitset>
#include <functional> #include <functional>
namespace folly { namespace folly {
namespace symbolizer { namespace symbolizer {
extern const unsigned long kAllFatalSignals;
/** /**
* Install handler for fatal signals. The list of signals being handled is in * Install handler for fatal signals. The list of signals being handled is in
* SignalHandler.cpp. * SignalHandler.cpp.
* *
* The handler will dump signal and time information followed by a stack trace * The handler will dump signal and time information followed by a stack trace
* to stderr, and then call the callbacks registered below. * to stderr, and then call the callbacks registered below.
*
* The signals parameter can be used to specify only specific fatal signals for
* which the handler should be installed. Only signals from kAllFatalSignals
* are honored in this list, other signals are ignored.
*/ */
void installFatalSignalHandler(); void installFatalSignalHandler(
std::bitset<64> signals = std::bitset<64>(kAllFatalSignals));
/** /**
* Add a callback to be run when receiving a fatal signal. They will also * Add a callback to be run when receiving a fatal signal. They will also
......
...@@ -32,12 +32,26 @@ ...@@ -32,12 +32,26 @@
DEFINE_string(logging, "", "Logging configuration"); DEFINE_string(logging, "", "Logging configuration");
namespace folly { namespace folly {
const unsigned long kAllFatalSignals =
#if FOLLY_USE_SYMBOLIZER
symbolizer::kAllFatalSignals;
#else
0;
#endif
InitOptions::InitOptions() noexcept : fatal_signals(kAllFatalSignals) {}
void init(int* argc, char*** argv, bool removeFlags) { void init(int* argc, char*** argv, bool removeFlags) {
InitOptions options;
options.removeFlags(removeFlags);
init(argc, argv, options);
}
void init(int* argc, char*** argv, InitOptions options) {
#if FOLLY_USE_SYMBOLIZER #if FOLLY_USE_SYMBOLIZER
// Install the handler now, to trap errors received during startup. // Install the handler now, to trap errors received during startup.
// The callbacks, if any, can be installed later // The callbacks, if any, can be installed later
folly::symbolizer::installFatalSignalHandler(); folly::symbolizer::installFatalSignalHandler(options.fatal_signals);
#elif !defined(_WIN32) #elif !defined(_WIN32)
google::InstallFailureSignalHandler(); google::InstallFailureSignalHandler();
#endif #endif
...@@ -51,9 +65,9 @@ void init(int* argc, char*** argv, bool removeFlags) { ...@@ -51,9 +65,9 @@ void init(int* argc, char*** argv, bool removeFlags) {
folly::SingletonVault::singleton()->registrationComplete(); folly::SingletonVault::singleton()->registrationComplete();
#if !FOLLY_HAVE_LIBGFLAGS #if !FOLLY_HAVE_LIBGFLAGS
(void)removeFlags; (void)options;
#else #else
gflags::ParseCommandLineFlags(argc, argv, removeFlags); gflags::ParseCommandLineFlags(argc, argv, options.remove_flags);
#endif #endif
folly::initLoggingOrDie(FLAGS_logging); folly::initLoggingOrDie(FLAGS_logging);
...@@ -76,6 +90,10 @@ Init::Init(int* argc, char*** argv, bool removeFlags) { ...@@ -76,6 +90,10 @@ Init::Init(int* argc, char*** argv, bool removeFlags) {
init(argc, argv, removeFlags); init(argc, argv, removeFlags);
} }
Init::Init(int* argc, char*** argv, InitOptions options) {
init(argc, argv, options);
}
Init::~Init() { Init::~Init() {
SingletonVault::singleton()->destroyInstances(); SingletonVault::singleton()->destroyInstances();
} }
......
...@@ -15,8 +15,34 @@ ...@@ -15,8 +15,34 @@
*/ */
#pragma once #pragma once
#include <folly/CPortability.h> #include <folly/CPortability.h>
#include <bitset>
namespace folly {
class InitOptions {
public:
InitOptions() noexcept;
bool remove_flags{true};
// mask of all fatal (default handler of terminating the process) signals for
// which `init()` will install handler that print stack traces and invokes
// previously established handler (or terminate if there were none).
// Signals that are not in `symbolizer::kAllFatalSignals` will be ignored
// if passed here
// Defaults to all signal in `symbolizer::kAllFatalSignals`
std::bitset<64> fatal_signals;
InitOptions& removeFlags(bool remove) {
remove_flags = remove;
return *this;
}
InitOptions& fatalSignals(unsigned long val) {
fatal_signals = val;
return *this;
}
};
/* /*
* Calls common init functions in the necessary order * Calls common init functions in the necessary order
...@@ -27,11 +53,13 @@ ...@@ -27,11 +53,13 @@
* @param argc, argv arguments to your main * @param argc, argv arguments to your main
* @param removeFlags if true, will update argc,argv to remove recognized * @param removeFlags if true, will update argc,argv to remove recognized
* gflags passed on the command line * gflags passed on the command line
* @param options options
*/ */
namespace folly {
void init(int* argc, char*** argv, bool removeFlags = true); void init(int* argc, char*** argv, bool removeFlags = true);
void init(int* argc, char*** argv, InitOptions options);
/* /*
* An RAII object to be constructed at the beginning of main() and destructed * An RAII object to be constructed at the beginning of main() and destructed
* implicitly at the end of main(). * implicitly at the end of main().
...@@ -48,6 +76,9 @@ class Init { ...@@ -48,6 +76,9 @@ class Init {
public: public:
// Force ctor & dtor out of line for better stack traces even with LTO. // Force ctor & dtor out of line for better stack traces even with LTO.
FOLLY_NOINLINE Init(int* argc, char*** argv, bool removeFlags = true); FOLLY_NOINLINE Init(int* argc, char*** argv, bool removeFlags = true);
FOLLY_NOINLINE Init(int* argc, char*** argv, InitOptions options);
FOLLY_NOINLINE ~Init(); FOLLY_NOINLINE ~Init();
Init(Init const&) = delete; Init(Init const&) = delete;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment