Commit d1f49ba5 authored by Andrew Schwartzmeyer's avatar Andrew Schwartzmeyer

Support signal handler on Windows

parent 7f95ecfd
...@@ -364,9 +364,9 @@ set (GLOG_SRCS ...@@ -364,9 +364,9 @@ set (GLOG_SRCS
src/vlog_is_on.cc src/vlog_is_on.cc
) )
if (HAVE_PTHREAD) if (HAVE_PTHREAD OR WIN32)
list (APPEND GLOG_SRCS src/signalhandler.cc) list (APPEND GLOG_SRCS src/signalhandler.cc)
endif (HAVE_PTHREAD) endif (HAVE_PTHREAD OR WIN32)
if (WIN32) if (WIN32)
list (APPEND GLOG_SRCS list (APPEND GLOG_SRCS
......
...@@ -1463,16 +1463,13 @@ void LogMessage::RecordCrashReason( ...@@ -1463,16 +1463,13 @@ void LogMessage::RecordCrashReason(
# define ATTRIBUTE_NORETURN # define ATTRIBUTE_NORETURN
#endif #endif
#if defined(OS_WINDOWS)
__declspec(noreturn)
#endif
static void logging_fail() ATTRIBUTE_NORETURN; static void logging_fail() ATTRIBUTE_NORETURN;
static void logging_fail() { 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(); abort();
#endif
} }
typedef void (*logging_fail_func_t)() ATTRIBUTE_NORETURN; typedef void (*logging_fail_func_t)() ATTRIBUTE_NORETURN;
......
...@@ -48,9 +48,6 @@ ...@@ -48,9 +48,6 @@
_START_GOOGLE_NAMESPACE_ _START_GOOGLE_NAMESPACE_
// TOOD(hamaji): Use signal instead of sigaction?
#ifdef HAVE_SIGACTION
namespace { namespace {
// We'll install the failure signal handler for these signals. We could // We'll install the failure signal handler for these signals. We could
...@@ -66,10 +63,14 @@ const struct { ...@@ -66,10 +63,14 @@ const struct {
{ SIGILL, "SIGILL" }, { SIGILL, "SIGILL" },
{ SIGFPE, "SIGFPE" }, { SIGFPE, "SIGFPE" },
{ SIGABRT, "SIGABRT" }, { SIGABRT, "SIGABRT" },
#if !defined(OS_WINDOWS)
{ SIGBUS, "SIGBUS" }, { SIGBUS, "SIGBUS" },
#endif
{ SIGTERM, "SIGTERM" }, { SIGTERM, "SIGTERM" },
}; };
static bool kFailureSignalHandlerInstalled = false;
// Returns the program counter from signal context, NULL if unknown. // Returns the program counter from signal context, NULL if unknown.
void* GetPC(void* ucontext_in_void) { void* GetPC(void* ucontext_in_void) {
#if (defined(HAVE_UCONTEXT_H) || defined(HAVE_SYS_UCONTEXT_H)) && defined(PC_FROM_UCONTEXT) #if (defined(HAVE_UCONTEXT_H) || defined(HAVE_SYS_UCONTEXT_H)) && defined(PC_FROM_UCONTEXT)
...@@ -168,6 +169,9 @@ void DumpTimeInfo() { ...@@ -168,6 +169,9 @@ void DumpTimeInfo() {
g_failure_writer(buf, formatter.num_bytes_written()); 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. // Dumps information about the signal to STDERR.
void DumpSignalInfo(int signal_number, siginfo_t *siginfo) { void DumpSignalInfo(int signal_number, siginfo_t *siginfo) {
// Get the signal name. // Get the signal name.
...@@ -213,6 +217,8 @@ void DumpSignalInfo(int signal_number, siginfo_t *siginfo) { ...@@ -213,6 +217,8 @@ void DumpSignalInfo(int signal_number, siginfo_t *siginfo) {
g_failure_writer(buf, formatter.num_bytes_written()); g_failure_writer(buf, formatter.num_bytes_written());
} }
#endif // HAVE_SIGACTION
// Dumps information about the stack frame to STDERR. // Dumps information about the stack frame to STDERR.
void DumpStackFrameInfo(const char* prefix, void* pc) { void DumpStackFrameInfo(const char* prefix, void* pc) {
// Get the symbol name. // Get the symbol name.
...@@ -240,12 +246,17 @@ void DumpStackFrameInfo(const char* prefix, void* pc) { ...@@ -240,12 +246,17 @@ void DumpStackFrameInfo(const char* prefix, void* pc) {
// Invoke the default signal handler. // Invoke the default signal handler.
void InvokeDefaultSignalHandler(int signal_number) { void InvokeDefaultSignalHandler(int signal_number) {
#ifdef HAVE_SIGACTION
struct sigaction sig_action; struct sigaction sig_action;
memset(&sig_action, 0, sizeof(sig_action)); memset(&sig_action, 0, sizeof(sig_action));
sigemptyset(&sig_action.sa_mask); sigemptyset(&sig_action.sa_mask);
sig_action.sa_handler = SIG_DFL; sig_action.sa_handler = SIG_DFL;
sigaction(signal_number, &sig_action, NULL); sigaction(signal_number, &sig_action, NULL);
kill(getpid(), signal_number); 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 // This variable is used for protecting FailureSignalHandler() from
...@@ -256,9 +267,14 @@ static pthread_t* g_entered_thread_id_pointer = NULL; ...@@ -256,9 +267,14 @@ static pthread_t* g_entered_thread_id_pointer = NULL;
// Dumps signal and stack frame information, and invokes the default // Dumps signal and stack frame information, and invokes the default
// signal handler once our job is done. // signal handler once our job is done.
#if defined(OS_WINDOWS)
void FailureSignalHandler(int signal_number)
#else
void FailureSignalHandler(int signal_number, void FailureSignalHandler(int signal_number,
siginfo_t *signal_info, siginfo_t *signal_info,
void *ucontext) { void *ucontext)
#endif
{
// First check if we've already entered the function. We use an atomic // First check if we've already entered the function. We use an atomic
// compare and swap operation for platforms that support it. For other // compare and swap operation for platforms that support it. For other
// platforms, we use a naive method that could lead to a subtle race. // platforms, we use a naive method that could lead to a subtle race.
...@@ -298,16 +314,20 @@ void FailureSignalHandler(int signal_number, ...@@ -298,16 +314,20 @@ void FailureSignalHandler(int signal_number,
// First dump time info. // First dump time info.
DumpTimeInfo(); DumpTimeInfo();
#if !defined(OS_WINDOWS)
// Get the program counter from ucontext. // Get the program counter from ucontext.
void *pc = GetPC(ucontext); void *pc = GetPC(ucontext);
DumpStackFrameInfo("PC: ", pc); DumpStackFrameInfo("PC: ", pc);
#endif
#ifdef HAVE_STACKTRACE #ifdef HAVE_STACKTRACE
// Get the stack traces. // Get the stack traces.
void *stack[32]; void *stack[32];
// +1 to exclude this function. // +1 to exclude this function.
const int depth = GetStackTrace(stack, ARRAYSIZE(stack), 1); const int depth = GetStackTrace(stack, ARRAYSIZE(stack), 1);
# ifdef HAVE_SIGACTION
DumpSignalInfo(signal_number, signal_info); DumpSignalInfo(signal_number, signal_info);
# endif
// Dump the stack traces. // Dump the stack traces.
for (int i = 0; i < depth; ++i) { for (int i = 0; i < depth; ++i) {
DumpStackFrameInfo(" ", stack[i]); DumpStackFrameInfo(" ", stack[i]);
...@@ -333,18 +353,19 @@ void FailureSignalHandler(int signal_number, ...@@ -333,18 +353,19 @@ void FailureSignalHandler(int signal_number,
} // namespace } // namespace
#endif // HAVE_SIGACTION
namespace glog_internal_namespace_ { namespace glog_internal_namespace_ {
bool IsFailureSignalHandlerInstalled() { bool IsFailureSignalHandlerInstalled() {
#ifdef HAVE_SIGACTION #ifdef HAVE_SIGACTION
// TODO(andschwa): Return kFailureSignalHandlerInstalled?
struct sigaction sig_action; struct sigaction sig_action;
memset(&sig_action, 0, sizeof(sig_action)); memset(&sig_action, 0, sizeof(sig_action));
sigemptyset(&sig_action.sa_mask); sigemptyset(&sig_action.sa_mask);
sigaction(SIGABRT, NULL, &sig_action); sigaction(SIGABRT, NULL, &sig_action);
if (sig_action.sa_sigaction == &FailureSignalHandler) if (sig_action.sa_sigaction == &FailureSignalHandler)
return true; return true;
#elif defined(OS_WINDOWS)
return kFailureSignalHandlerInstalled;
#endif // HAVE_SIGACTION #endif // HAVE_SIGACTION
return false; return false;
} }
...@@ -363,11 +384,18 @@ void InstallFailureSignalHandler() { ...@@ -363,11 +384,18 @@ void InstallFailureSignalHandler() {
for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) { for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) {
CHECK_ERR(sigaction(kFailureSignals[i].number, &sig_action, NULL)); 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 #endif // HAVE_SIGACTION
} }
void InstallFailureWriter(void (*writer)(const char* data, int size)) { void InstallFailureWriter(void (*writer)(const char* data, int size)) {
#ifdef HAVE_SIGACTION #if defined(HAVE_SIGACTION) || defined(OS_WINDOWS)
g_failure_writer = writer; g_failure_writer = writer;
#endif // HAVE_SIGACTION #endif // HAVE_SIGACTION
} }
......
...@@ -34,7 +34,9 @@ ...@@ -34,7 +34,9 @@
#include "utilities.h" #include "utilities.h"
#include <pthread.h> #if defined(HAVE_PTHREAD)
# include <pthread.h>
#endif
#include <signal.h> #include <signal.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
...@@ -87,12 +89,20 @@ int main(int argc, char **argv) { ...@@ -87,12 +89,20 @@ int main(int argc, char **argv) {
fprintf(stderr, "looping\n"); fprintf(stderr, "looping\n");
while (true); while (true);
} else if (command == "die_in_thread") { } else if (command == "die_in_thread") {
#if defined(HAVE_PTHREAD)
pthread_t thread; pthread_t thread;
pthread_create(&thread, NULL, &DieInThread, NULL); pthread_create(&thread, NULL, &DieInThread, NULL);
pthread_join(thread, NULL); pthread_join(thread, NULL);
#else
fprintf(stderr, "no pthread\n");
return 1;
#endif
} else if (command == "dump_to_stdout") { } else if (command == "dump_to_stdout") {
InstallFailureWriter(WriteToStdout); InstallFailureWriter(WriteToStdout);
abort(); abort();
} else if (command == "installed") {
fprintf(stderr, "signal handler installed: %s\n",
IsFailureSignalHandlerInstalled() ? "true" : "false");
} else { } else {
// Tell the shell script // Tell the shell script
puts("OK"); puts("OK");
......
...@@ -137,17 +137,19 @@ static void DumpStackTraceAndExit() { ...@@ -137,17 +137,19 @@ static void DumpStackTraceAndExit() {
DumpStackTrace(1, DebugWriteToStderr, NULL); DumpStackTrace(1, DebugWriteToStderr, NULL);
// TOOD(hamaji): Use signal instead of sigaction? // TOOD(hamaji): Use signal instead of sigaction?
#ifdef HAVE_SIGACTION
if (IsFailureSignalHandlerInstalled()) { if (IsFailureSignalHandlerInstalled()) {
// Set the default signal handler for SIGABRT, to avoid invoking our // Set the default signal handler for SIGABRT, to avoid invoking our
// own signal handler installed by InstallFailureSignalHandler(). // own signal handler installed by InstallFailureSignalHandler().
#ifdef HAVE_SIGACTION
struct sigaction sig_action; struct sigaction sig_action;
memset(&sig_action, 0, sizeof(sig_action)); memset(&sig_action, 0, sizeof(sig_action));
sigemptyset(&sig_action.sa_mask); sigemptyset(&sig_action.sa_mask);
sig_action.sa_handler = SIG_DFL; sig_action.sa_handler = SIG_DFL;
sigaction(SIGABRT, &sig_action, NULL); sigaction(SIGABRT, &sig_action, NULL);
} #elif defined(OS_WINDOWS)
signal(SIGABRT, SIG_DFL);
#endif // HAVE_SIGACTION #endif // HAVE_SIGACTION
}
abort(); abort();
} }
......
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