Permalink
Browse files

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...
1 parent 27ee9fb commit 546fdac8d1e952422c91278be3187ae87aded28e @daniel-kristjansson daniel-kristjansson committed Jun 18, 2012
Showing with 63 additions and 3 deletions.
  1. +62 −3 mythtv/libs/libmythbase/signalhandling.cpp
  2. +1 −0 mythtv/libs/libmythbase/signalhandling.h
@@ -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))
{
@@ -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;
@@ -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)
@@ -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:
@@ -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);

0 comments on commit 546fdac

Please sign in to comment.