From d1f49ba5aa8a06be74dedc60cdf56a2e74031b7b Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Mon, 26 Jun 2017 17:13:21 -0700 Subject: [PATCH] Support signal handler on Windows --- CMakeLists.txt | 4 ++-- src/logging.cc | 9 +++------ src/signalhandler.cc | 42 +++++++++++++++++++++++++++++++++++------- src/signalhandler_unittest.cc | 12 +++++++++++- src/utilities.cc | 6 ++++-- 5 files changed, 55 insertions(+), 18 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index af4680d..7f28295 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -364,9 +364,9 @@ set (GLOG_SRCS src/vlog_is_on.cc ) -if (HAVE_PTHREAD) +if (HAVE_PTHREAD OR WIN32) list (APPEND GLOG_SRCS src/signalhandler.cc) -endif (HAVE_PTHREAD) +endif (HAVE_PTHREAD OR WIN32) if (WIN32) list (APPEND GLOG_SRCS diff --git a/src/logging.cc b/src/logging.cc index 0b5e6ee..32a5791 100644 --- a/src/logging.cc +++ b/src/logging.cc @@ -1463,16 +1463,13 @@ void LogMessage::RecordCrashReason( # define ATTRIBUTE_NORETURN #endif +#if defined(OS_WINDOWS) +__declspec(noreturn) +#endif static void logging_fail() ATTRIBUTE_NORETURN; static void logging_fail() { -#if defined(_DEBUG) && defined(_MSC_VER) - // When debugging on windows, avoid the obnoxious dialog and make - // it possible to continue past a LOG(FATAL) in the debugger - __debugbreak(); -#else abort(); -#endif } typedef void (*logging_fail_func_t)() ATTRIBUTE_NORETURN; diff --git a/src/signalhandler.cc b/src/signalhandler.cc index a7aef8b..72fd92b 100644 --- a/src/signalhandler.cc +++ b/src/signalhandler.cc @@ -48,9 +48,6 @@ _START_GOOGLE_NAMESPACE_ -// TOOD(hamaji): Use signal instead of sigaction? -#ifdef HAVE_SIGACTION - namespace { // We'll install the failure signal handler for these signals. We could @@ -66,10 +63,14 @@ const struct { { SIGILL, "SIGILL" }, { SIGFPE, "SIGFPE" }, { SIGABRT, "SIGABRT" }, +#if !defined(OS_WINDOWS) { SIGBUS, "SIGBUS" }, +#endif { SIGTERM, "SIGTERM" }, }; +static bool kFailureSignalHandlerInstalled = false; + // Returns the program counter from signal context, NULL if unknown. void* GetPC(void* ucontext_in_void) { #if (defined(HAVE_UCONTEXT_H) || defined(HAVE_SYS_UCONTEXT_H)) && defined(PC_FROM_UCONTEXT) @@ -168,6 +169,9 @@ void DumpTimeInfo() { g_failure_writer(buf, formatter.num_bytes_written()); } +// TOOD(hamaji): Use signal instead of sigaction? +#ifdef HAVE_SIGACTION + // Dumps information about the signal to STDERR. void DumpSignalInfo(int signal_number, siginfo_t *siginfo) { // Get the signal name. @@ -213,6 +217,8 @@ void DumpSignalInfo(int signal_number, siginfo_t *siginfo) { g_failure_writer(buf, formatter.num_bytes_written()); } +#endif // HAVE_SIGACTION + // Dumps information about the stack frame to STDERR. void DumpStackFrameInfo(const char* prefix, void* pc) { // Get the symbol name. @@ -240,12 +246,17 @@ void DumpStackFrameInfo(const char* prefix, void* pc) { // Invoke the default signal handler. void InvokeDefaultSignalHandler(int signal_number) { +#ifdef HAVE_SIGACTION 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); kill(getpid(), signal_number); +#elif defined(OS_WINDOWS) + signal(signal_number, SIG_DFL); + raise(signal_number); +#endif } // This variable is used for protecting FailureSignalHandler() from @@ -256,9 +267,14 @@ static pthread_t* g_entered_thread_id_pointer = NULL; // Dumps signal and stack frame information, and invokes the default // signal handler once our job is done. +#if defined(OS_WINDOWS) +void FailureSignalHandler(int signal_number) +#else void FailureSignalHandler(int signal_number, siginfo_t *signal_info, - void *ucontext) { + void *ucontext) +#endif +{ // First check if we've already entered the function. We use an atomic // compare and swap operation for platforms that support it. For other // platforms, we use a naive method that could lead to a subtle race. @@ -298,16 +314,20 @@ void FailureSignalHandler(int signal_number, // First dump time info. DumpTimeInfo(); +#if !defined(OS_WINDOWS) // Get the program counter from ucontext. void *pc = GetPC(ucontext); DumpStackFrameInfo("PC: ", pc); +#endif #ifdef HAVE_STACKTRACE // Get the stack traces. void *stack[32]; // +1 to exclude this function. const int depth = GetStackTrace(stack, ARRAYSIZE(stack), 1); +# ifdef HAVE_SIGACTION DumpSignalInfo(signal_number, signal_info); +# endif // Dump the stack traces. for (int i = 0; i < depth; ++i) { DumpStackFrameInfo(" ", stack[i]); @@ -333,18 +353,19 @@ void FailureSignalHandler(int signal_number, } // namespace -#endif // HAVE_SIGACTION - namespace glog_internal_namespace_ { bool IsFailureSignalHandlerInstalled() { #ifdef HAVE_SIGACTION + // TODO(andschwa): Return kFailureSignalHandlerInstalled? 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; +#elif defined(OS_WINDOWS) + return kFailureSignalHandlerInstalled; #endif // HAVE_SIGACTION return false; } @@ -363,11 +384,18 @@ void InstallFailureSignalHandler() { for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) { CHECK_ERR(sigaction(kFailureSignals[i].number, &sig_action, NULL)); } + kFailureSignalHandlerInstalled = true; +#elif defined(OS_WINDOWS) + for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) { + CHECK_NE(signal(kFailureSignals[i].number, &FailureSignalHandler), + SIG_ERR); + } + kFailureSignalHandlerInstalled = true; #endif // HAVE_SIGACTION } void InstallFailureWriter(void (*writer)(const char* data, int size)) { -#ifdef HAVE_SIGACTION +#if defined(HAVE_SIGACTION) || defined(OS_WINDOWS) g_failure_writer = writer; #endif // HAVE_SIGACTION } diff --git a/src/signalhandler_unittest.cc b/src/signalhandler_unittest.cc index 59be231..e85f523 100644 --- a/src/signalhandler_unittest.cc +++ b/src/signalhandler_unittest.cc @@ -34,7 +34,9 @@ #include "utilities.h" -#include +#if defined(HAVE_PTHREAD) +# include +#endif #include #include #include @@ -87,12 +89,20 @@ int main(int argc, char **argv) { fprintf(stderr, "looping\n"); while (true); } else if (command == "die_in_thread") { +#if defined(HAVE_PTHREAD) pthread_t thread; pthread_create(&thread, NULL, &DieInThread, NULL); pthread_join(thread, NULL); +#else + fprintf(stderr, "no pthread\n"); + return 1; +#endif } else if (command == "dump_to_stdout") { InstallFailureWriter(WriteToStdout); abort(); + } else if (command == "installed") { + fprintf(stderr, "signal handler installed: %s\n", + IsFailureSignalHandlerInstalled() ? "true" : "false"); } else { // Tell the shell script puts("OK"); diff --git a/src/utilities.cc b/src/utilities.cc index 0d686eb..e73cee0 100644 --- a/src/utilities.cc +++ b/src/utilities.cc @@ -137,17 +137,19 @@ static void DumpStackTraceAndExit() { DumpStackTrace(1, DebugWriteToStderr, NULL); // TOOD(hamaji): Use signal instead of sigaction? -#ifdef HAVE_SIGACTION if (IsFailureSignalHandlerInstalled()) { // Set the default signal handler for SIGABRT, to avoid invoking our // own signal handler installed by InstallFailureSignalHandler(). +#ifdef HAVE_SIGACTION struct sigaction sig_action; memset(&sig_action, 0, sizeof(sig_action)); sigemptyset(&sig_action.sa_mask); sig_action.sa_handler = SIG_DFL; sigaction(SIGABRT, &sig_action, NULL); - } +#elif defined(OS_WINDOWS) + signal(SIGABRT, SIG_DFL); #endif // HAVE_SIGACTION + } abort(); } -- 2.7.4