Support signal handler on Windows
This commit is contained in:
parent
7f95ecfdc7
commit
d1f49ba5aa
@ -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(
|
|||||||
# 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 @@
|
|||||||
|
|
||||||
_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 {
|
|||||||
{ 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() {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
|
|
||||||
// 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;
|
|||||||
|
|
||||||
// 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,
|
|||||||
// 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,
|
|||||||
|
|
||||||
} // 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() {
|
|||||||
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 @@
|
|||||||
|
|
||||||
#include "utilities.h"
|
#include "utilities.h"
|
||||||
|
|
||||||
|
#if defined(HAVE_PTHREAD)
|
||||||
# include <pthread.h>
|
# 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) {
|
|||||||
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() {
|
|||||||
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();
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user