Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Refs #10841. A fix for SEGFAULT handling.
We may want to handle this differently later, but this works.
We don't return from signalHandler if the signal is SEGV, ILL, BUS, or FPE.
This ensures the signal isn't immediately re-raised on return.
Also, after waiting 1 second for any cleanup actions which will
only happen if this signal didn't occur in the UI thread, we
call the default handler which will generate a core if necessary
and then exit the program.
  • Loading branch information
daniel-kristjansson committed Jun 18, 2012
1 parent 27ee9fb commit 546fdac
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 3 deletions.
65 changes: 62 additions & 3 deletions mythtv/libs/libmythbase/signalhandling.cpp
Expand Up @@ -20,10 +20,37 @@ using namespace std;
#include "signalhandling.h"

int SignalHandler::sigFd[2];
volatile bool SignalHandler::s_exit_program = false;

// We may need to write out signal info using just the write() function
// so we create an array of C strings + measure their lengths.
const int sig_str_count = 256;
char *sig_str[sig_str_count];
uint sig_str_len[sig_str_count];
static void sig_str_init(int sig, const char *name)
{
if (sig < sig_str_count)
{
if (sig_str[sig])
free(sig_str[sig]);
sig_str[sig] = strdup(name);
sig_str_len[sig] = strlen(sig_str[sig]);
}
}
static void sig_str_init(void)
{
for (int i = 0; i < sig_str_count; i++)
{
sig_str[i] = NULL;
sig_str_init(i, qPrintable(QString("%1").arg(i)));
}
}

SignalHandler::SignalHandler(QList<int> &signallist, QObject *parent) :
QObject(parent), m_notifier(NULL), m_usr1Handler(NULL), m_usr2Handler(NULL)
{
s_exit_program = false; // set here due to "C++ static initializer madness"
sig_str_init();
#ifndef _WIN32
if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigFd))
{
Expand All @@ -44,18 +71,22 @@ SignalHandler::SignalHandler(QList<int> &signallist, QObject *parent) :
switch (*it)
{
case SIGINT:
sig_str_init(*it, "SIGINT");
sigaction(*it, &sa, NULL);
LOG(VB_GENERAL, LOG_INFO, "Setup SIGINT handler");
break;
case SIGTERM:
sig_str_init(*it, "SIGTERM");
sigaction(*it, &sa, NULL);
LOG(VB_GENERAL, LOG_INFO, "Setup SIGTERM handler");
break;
case SIGSEGV:
sig_str_init(*it, "SIGSEGV");
sigaction(*it, &sa, NULL);
LOG(VB_GENERAL, LOG_INFO, "Setup SIGSEGV handler");
break;
case SIGABRT:
sig_str_init(*it, "SIGABRT");
sigaction(*it, &sa, NULL);
LOG(VB_GENERAL, LOG_INFO, "Setup SIGABRT handler");
break;
Expand Down Expand Up @@ -117,8 +148,33 @@ void SignalHandler::AddHandler(int signum, void (*handler)(void))
void SignalHandler::signalHandler(int signum)
{
char a = (char)signum;
int ret = ::write(sigFd[0], &a, sizeof(a));
(void)ret;
while (::write(sigFd[0], &a, 1) != 1);

// One must not return from SEGV, ILL, BUS or FPE. When these
// are raised by the program itself they will immediately get
// re-raised on return.
if ((signum == SIGSEGV) || (signum == SIGILL) ||
(signum == SIGBUS) || (signum == SIGFPE))
{
// Wait for UI event loop to handle this, however we may be
// blocking it if this signal occured in the UI thread.
// Note, can not use usleep() as it is not a signal safe function.
sleep(1);

if (!s_exit_program)
{
// log something to console.. regular logging may be kaput
ssize_t d = ::write(STDERR_FILENO, "Handling ", 9);
if (signum < sig_str_count)
d+=::write(STDERR_FILENO, sig_str[signum], sig_str_len[signum]);
d+=::write(STDERR_FILENO, "\n", 1);
(void) d; // quiet ignoring return value warning.
}

// call the default signal handler.
signal(signum, SIG_DFL);
raise(signum);
}
}

void SignalHandler::handleSignal(void)
Expand All @@ -136,22 +192,25 @@ void SignalHandler::handleSignal(void)
LOG(VB_GENERAL, LOG_CRIT, "Received SIGINT");
signal(SIGINT, SIG_DFL);
qApp->quit();
s_exit_program = true;
break;
case SIGTERM:
LOG(VB_GENERAL, LOG_CRIT, "Received SIGTERM");
signal(SIGTERM, SIG_DFL);
qApp->quit();
s_exit_program = true;
break;
case SIGSEGV:
LOG(VB_GENERAL, LOG_CRIT, "Received SIGSEGV");
signal(SIGSEGV, SIG_DFL);
usleep(100000);
raise(signum);
s_exit_program = true;
break;
case SIGABRT:
LOG(VB_GENERAL, LOG_CRIT, "Received SIGABRT");
signal(SIGABRT, SIG_DFL);
usleep(100000);
s_exit_program = true;
raise(signum);
break;
case SIGUSR1:
Expand Down
1 change: 1 addition & 0 deletions mythtv/libs/libmythbase/signalhandling.h
Expand Up @@ -32,6 +32,7 @@ class MBASE_PUBLIC SignalHandler: public QObject

private:
static int sigFd[2];
static volatile bool s_exit_program;
QSocketNotifier *m_notifier;

void (*m_usr1Handler)(void);
Expand Down

0 comments on commit 546fdac

Please sign in to comment.