Added resotre and override signal handler

This commit is contained in:
Kjell Hedstrom 2015-09-10 06:20:26 -06:00
parent 6432487adc
commit 602e135f84
3 changed files with 108 additions and 94 deletions

View File

@ -147,7 +147,8 @@ namespace
void SegFaultAttempt_x10000() NOEXCEPT {
deathfunc f = []{Throw(); *(char*)0 = 0; char* ptr = 0; *ptr = 1; AccessViolation();};
deathfunc f = []{char* ptr = 0; *ptr = 1; };
Death_x10000(f, "throw uncaught exception... and then some sigsegv calls");
}
@ -293,6 +294,21 @@ int main(int argc, char **argv)
g3::initializeLogging(worker.get());
g3::setFatalPreLoggingHook(&breakHere);
// <sigh>: Not yet added example of fatal signals that can be overridden
// Example: Running this with SIGTERM turned off, and choosing to "die by SIGTERM"
// will exit the process without catching the signal
//
// Enable the code below will override the signal setup, all signals active except SIGTERM
// g3::overrideSetupSignals({ {SIGABRT, "SIGABRT"}, {SIGFPE, "SIGFPE"},{SIGILL, "SIGILL"},
// {SIGSEGV, "SIGSEGV"},});
//
// the code below.... can be used to restore the signal handler again
// In truth: I don't really see how this can be used
// ...... maybe a separate signal handler for sigterm.... and running this in a unit test?
//g3::restoreSignalHandlerToDefault();
don't compile on purpose
std::future<std::string> log_file_name = handle->call(&g3::FileSink::fileName);
std::cout << "**** G3LOG FATAL EXAMPLE ***\n\n"

View File

@ -11,7 +11,7 @@
#include "g3log/logcapture.hpp"
#include "g3log/loglevels.hpp"
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__) && !defined(__GNUC__)) // windows and not mingw
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__) && !defined(__GNUC__))
#error "crashhandler_unix.cpp used but it's a windows system"
#endif
@ -56,7 +56,6 @@ namespace {
}
void restoreSignalHandler(int signal_number) {
std::cerr << "\n\n" << __FUNCTION__ << " " << signal_number << " threadID: " << std::this_thread::get_id() << std::endl;
#if !(defined(DISABLE_FATAL_SIGNALHANDLING))
struct sigaction action;
memset(&action, 0, sizeof (action)); //
@ -66,17 +65,6 @@ namespace {
#endif
}
void overrideSetupSignals(const std::map<int, std::string> overrideSignals) {
static std::mutex signalLock;
std::lock_guard<std::mutex> guard(signalLock);
gSignals = overrideSignals;
for(const auto& sig: kSignals) {
restoreSignalHandler(sig.first);
}
g3::installCrashHandler();
}
// Dump of stack,. then exit through g3log background worker
// ALL thanks to this thread at StackOverflow. Pretty much borrowed from:
@ -103,6 +91,33 @@ namespace {
} // message sent to g3LogWorker
// wait to die
}
//
// Installs FATAL signal handler that is enough to handle most fatal events
// on *NIX systems
void installSignalHandler() {
#if !(defined(DISABLE_FATAL_SIGNALHANDLING))
struct sigaction action;
memset(&action, 0, sizeof (action));
sigemptyset(&action.sa_mask);
action.sa_sigaction = &signalHandler; // callback to crashHandler for fatal signals
// sigaction to use sa_sigaction file. ref: http://www.linuxprogrammingblog.com/code-examples/sigaction
action.sa_flags = SA_SIGINFO;
// do it verbose style - install all signal actions
for (const auto& sig_pair : gSignals) {
if (sigaction(sig_pair.first, &action, nullptr) < 0) {
const std::string error = "sigaction - " + sig_pair.second;
perror(error.c_str());
}
}
#endif
}
} // end anonymous namespace
@ -213,23 +228,6 @@ namespace g3 {
// KJELL : TODO. The Fatal Message can contain a callback function that depending on OS and test scenario does
// different things.
// exitWithDefaultSignalHandler is called from g3logworke::bgFatal AFTER all the logging sinks have been cleared
// I.e. saving a function that has the value already encapsulated within.
// FatalMessagePtr msgPtr
// Linux/OSX --> msgPtr.get()->ContinueWithFatalExit(); --> exitWithDefaultSignalHandler(int signal_number);
// Windows ..... (if signal) --> exitWithDefaultSignalHandler(int signal_number);
// (if exception) ....
// the calling thread that is in a never-ending loop should break out of that loop
// i.e. an atomic flag should be set
// the next step should then be to re-throw the same exception
// i.e. just call the next exception handler
// we should make sure that 1) g3log exception handler is called BEFORE widows
// it should continue and then be caught in Visual Studios exception handler
//
//
// Triggered by g3log->g3LogWorker after receiving a FATAL trigger
// which is LOG(FATAL), CHECK(false) or a fatal signal our signalhandler caught.
// --- If LOG(FATAL) or CHECK(false) the signal_number will be SIGABRT
@ -245,47 +243,31 @@ namespace g3 {
}
} // end g3::internal
//
// Installs FATAL signal handler that is enough to handle most fatal events
// on *NIX systems
void installSignalHandler() {
#if !(defined(DISABLE_FATAL_SIGNALHANDLING))
struct sigaction action;
memset(&action, 0, sizeof (action));
sigemptyset(&action.sa_mask);
action.sa_sigaction = &signalHandler; // callback to crashHandler for fatal signals
// sigaction to use sa_sigaction file. ref: http://www.linuxprogrammingblog.com/code-examples/sigaction
action.sa_flags = SA_SIGINFO;
// do it verbose style - install all signal actions
for (const auto& sig_pair : gSignals) {
if (sigaction(sig_pair.first, &action, nullptr) < 0) {
const std::string error = "sigaction - " + sig_pair.second;
perror(error.c_str());
}
// This will override the default signal handler setup and instead
// install a custom set of signals to handle
void overrideSetupSignals(const std::map<int, std::string> overrideSignals) {
static std::mutex signalLock;
std::lock_guard<std::mutex> guard(signalLock);
for (const auto& sig : gSignals) {
restoreSignalHandler(sig.first);
}
// if (sigaction(SIGABRT, &action, NULL) < 0)
// perror("sigaction - SIGABRT");
// if (sigaction(SIGFPE, &action, NULL) < 0)
// perror("sigaction - SIGFPE");
// if (sigaction(SIGILL, &action, NULL) < 0)
// perror("sigaction - SIGILL");
// if (sigaction(SIGSEGV, &action, NULL) < 0)
// perror("sigaction - SIGSEGV");
// if (sigaction(SIGTERM, &action, NULL) < 0)
// perror("sigaction - SIGTERM");
#endif
gSignals = overrideSignals;
installCrashHandler(); // installs all the signal handling for gSignals
}
// restores the signal handler back to default
void restoreSignalHandlerToDefault() {
overrideSetupSignals(kSignals);
}
// installs the signal handling for whatever signal set that is currently active
// If you want to setup your own signal handling then
// You should instead call overrideSetupSignals()
void installCrashHandler() {
installSignalHandler();
} // namespace g3::internal
}
} // end namespace g3

View File

@ -9,6 +9,7 @@
* ============================================================================*/
#include <string>
#include <csignal>
#include <map>
#include "g3log/loglevels.hpp"
#include "g3log/generated_definitions.hpp"
@ -37,6 +38,21 @@ namespace g3 {
void installSignalHandlerForThread();
#else
typedef int SignalType;
/// Probably only needed for unit testing. Resets the signal handling back to default
/// which might be needed in case it was previously overridden
/// The default signals are: SIGABRT, SIGFPE, SIGILL, SIGSEGV, SIGTERM
void restoreSignalHandlerToDefault();
/// Overrides the existing signal handling for custom signals
/// For example: usage of zcmq relies on its own signal handler for SIGTERM
/// so users of g3log with zcmq should then use the @ref overrideSetupSignals
/// , likely with the original set of signals but with SIGTERM removed
///
/// call example:
/// g3::overrideSetupSignals({ {SIGABRT, "SIGABRT"}, {SIGFPE, "SIGFPE"},{SIGILL, "SIGILL"},
// {SIGSEGV, "SIGSEGV"},});
void overrideSetupSignals(const std::map<int, std::string> overrideSignals);
#endif