Skip to content

Commit

Permalink
Add support for real time signal 0 handling
Browse files Browse the repository at this point in the history
Fixes #11110

Seems that some setups (in particular Ubuntu 12.04) are seeing our applications
getting killed by SIGRTMIN.  As I have no clue what is causing this, I am
changing the signal handling to use sigaction's extended handlers that hand
off siginfo_t as well.  This gives us the source of the signal.

Additionally, I added a default handler for SIGRTMIN.  This should end that
nuisance.
  • Loading branch information
Beirdo committed Sep 25, 2012
1 parent 8611c6e commit c7f0676
Show file tree
Hide file tree
Showing 19 changed files with 100 additions and 40 deletions.
94 changes: 75 additions & 19 deletions mythtv/libs/libmythbase/signalhandling.cpp
Expand Up @@ -63,12 +63,26 @@ SignalHandler::SignalHandler(QList<int> &signallist, QObject *parent) :
s_exit_program = false; // set here due to "C++ static initializer madness"
sig_str_init();

m_sigStack = new char[SIGSTKSZ];
stack_t stack;
stack.ss_sp = (void *)m_sigStack;
stack.ss_flags = 0;
stack.ss_size = SIGSTKSZ;

// Carry on without the signal stack if it fails
if (sigaltstack(&stack, NULL) == -1)
{
cerr << "Couldn't create signal stack!" << endl;
delete [] m_sigStack;
m_sigStack = NULL;
}

if (s_defaultHandlerList.isEmpty())
s_defaultHandlerList << SIGINT << SIGTERM << SIGSEGV << SIGABRT
#ifndef _WIN32
<< SIGBUS
#endif
<< SIGFPE << SIGILL;
<< SIGFPE << SIGILL << SIGRTMIN;

#ifndef _WIN32
if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigFd))
Expand Down Expand Up @@ -107,7 +121,7 @@ SignalHandler::~SignalHandler()
}

QMutexLocker locker(&m_sigMapLock);
QMap<int, void (*)(void)>::iterator it = m_sigMap.begin();
QMap<int, SigHandlerFunc>::iterator it = m_sigMap.begin();
for ( ; it != m_sigMap.end(); ++it)
{
int signum = it.key();
Expand All @@ -133,14 +147,14 @@ void SignalHandler::Done(void)
}


void SignalHandler::SetHandler(int signum, void (*handler)(void))
void SignalHandler::SetHandler(int signum, SigHandlerFunc handler)
{
QMutexLocker locker(&s_singletonLock);
if (s_singleton)
s_singleton->SetHandlerPrivate(signum, handler);
}

void SignalHandler::SetHandlerPrivate(int signum, void (*handler)(void))
void SignalHandler::SetHandlerPrivate(int signum, SigHandlerFunc handler)
{
#ifndef _WIN32
const char *signame = strsignal(signum);
Expand All @@ -163,9 +177,11 @@ void SignalHandler::SetHandlerPrivate(int signum, void (*handler)(void))
if (!sa_handler_already_set)
{
struct sigaction sa;
sa.sa_handler = SignalHandler::signalHandler;
sa.sa_sigaction = SignalHandler::signalHandler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
sa.sa_flags = SA_RESTART | SA_SIGINFO;
if (m_sigStack)
sa.sa_flags |= SA_ONSTACK;

sig_str_init(signum, qPrintable(signal_name));

Expand All @@ -176,12 +192,38 @@ void SignalHandler::SetHandlerPrivate(int signum, void (*handler)(void))
#endif
}

void SignalHandler::signalHandler(int signum)
typedef struct {
int signum;
int code;
int pid;
int uid;
uint64_t value;
} SignalInfo;

void SignalHandler::signalHandler(int signum, siginfo_t *info, void *context)
{
char a = (char)signum;
SignalInfo signalInfo;

(void)context;
signalInfo.signum = signum;
signalInfo.code = (info ? info->si_code : 0);
signalInfo.pid = (info ? (int)info->si_pid : 0);
signalInfo.uid = (info ? (int)info->si_uid : 0);
signalInfo.value = (info ? (uint64_t)info->si_ptr : 0);

// Keep trying if there's no room to write, but stop on error (-1)
while (::write(sigFd[0], &a, 1) == 0);
int index = 0;
int size = sizeof(SignalInfo);
char *buffer = (char *)&signalInfo;
do {
int written = ::write(sigFd[0], &buffer[index], size);
// If there's an error, the signal will not be seen be the application,
// but we can't keep trying.
if (written < 0)
break;
index += written;
size -= written;
} while (size > 0);

// One must not return from SEGV, ILL, BUS or FPE. When these
// are raised by the program itself they will immediately get
Expand Down Expand Up @@ -237,17 +279,31 @@ void SignalHandler::handleSignal(void)
#ifndef _WIN32
m_notifier->setEnabled(false);

char a;
int ret = ::read(sigFd[1], &a, sizeof(a));
int signum = (int)a;
(void)ret;
SignalInfo signalInfo;
int ret = ::read(sigFd[1], &signalInfo, sizeof(SignalInfo));
bool infoComplete = (ret == sizeof(SignalInfo));
int signum = (infoComplete ? signalInfo.signum : 0);

const char *signame = strsignal(signum);
signame = strdup(signame ? signame : "Unknown");
LOG(VB_GENERAL, LOG_CRIT, QString("Received %1").arg(signame));
free((void *)signame);
if (infoComplete)
{
const char *signame = strsignal(signum);
signame = strdup(signame ? signame : "Unknown Signal");
LOG(VB_GENERAL, LOG_CRIT,
QString("Received %1: Code %2, PID %3, UID %4, Value 0x%5")
.arg(signame) .arg(signalInfo.code) .arg(signalInfo.pid)
.arg(signalInfo.uid) .arg(signalInfo.value,8,16,QChar('0')));
free((void *)signame);
}

void (*handler)(void) = NULL;
SigHandlerFunc handler = NULL;
bool allowNullHandler = false;
if (signum == SIGRTMIN)
{
// glibc idiots seem to have made SIGRTMIN a macro that expands to a
// function, so we can't do this in the switch below.
// This uses the default handler to just get us here and to ignore it.
allowNullHandler = true;
}

switch (signum)
{
Expand Down Expand Up @@ -279,7 +335,7 @@ void SignalHandler::handleSignal(void)
{
handler();
}
else
else if (!allowNullHandler)
{
LOG(VB_GENERAL, LOG_CRIT, QString("Recieved unexpected signal %1")
.arg(signum));
Expand Down
12 changes: 8 additions & 4 deletions mythtv/libs/libmythbase/signalhandling.h
Expand Up @@ -14,6 +14,8 @@
#include "mythbaseexp.h" // MBASE_PUBLIC , etc.
#include "mthread.h"

typedef void (*SigHandlerFunc)(void);

/// \brief A container object to handle UNIX signals in the Qt space correctly
class MBASE_PUBLIC SignalHandler: public QObject
{
Expand All @@ -23,12 +25,13 @@ class MBASE_PUBLIC SignalHandler: public QObject
static void Init(QList<int> &signallist, QObject *parent = NULL);
static void Done(void);

static void SetHandler(int signal, void (*handler)(void));
static void SetHandler(int signal, SigHandlerFunc handler);

static bool IsExiting(void) { return s_exit_program; }

// Unix signal handler.
static void signalHandler(int signum);
// context is of type ucontext_t * cast to void *
static void signalHandler(int signum, siginfo_t *info, void *context);

public slots:
// Qt signal handler.
Expand All @@ -37,14 +40,15 @@ class MBASE_PUBLIC SignalHandler: public QObject
private:
SignalHandler(QList<int> &signallist, QObject *parent);
~SignalHandler();
void SetHandlerPrivate(int signal, void (*handler)(void));
void SetHandlerPrivate(int signal, SigHandlerFunc handler);

static int sigFd[2];
static volatile bool s_exit_program;
QSocketNotifier *m_notifier;
char *m_sigStack;

QMutex m_sigMapLock;
QMap<int, void (*)(void)> m_sigMap;
QMap<int, SigHandlerFunc> m_sigMap;
static QList<int> s_defaultHandlerList;

static QMutex s_singletonLock;
Expand Down
2 changes: 1 addition & 1 deletion mythtv/programs/mythavtest/main.cpp
Expand Up @@ -232,7 +232,7 @@ int main(int argc, char *argv[])
#ifndef _WIN32
QList<int> signallist;
signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE
<< SIGILL;
<< SIGILL << SIGRTMIN;
SignalHandler::Init(signallist);
signal(SIGHUP, SIG_IGN);
#endif
Expand Down
2 changes: 1 addition & 1 deletion mythtv/programs/mythbackend/main.cpp
Expand Up @@ -103,7 +103,7 @@ int main(int argc, char **argv)
#ifndef _WIN32
QList<int> signallist;
signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE
<< SIGILL;
<< SIGILL << SIGRTMIN;
SignalHandler::Init(signallist);
signal(SIGHUP, SIG_IGN);
#endif
Expand Down
2 changes: 1 addition & 1 deletion mythtv/programs/mythccextractor/main.cpp
Expand Up @@ -145,7 +145,7 @@ int main(int argc, char *argv[])
#ifndef _WIN32
QList<int> signallist;
signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE
<< SIGILL;
<< SIGILL << SIGRTMIN;
SignalHandler::Init(signallist);
signal(SIGHUP, SIG_IGN);
#endif
Expand Down
2 changes: 1 addition & 1 deletion mythtv/programs/mythcommflag/main.cpp
Expand Up @@ -1126,7 +1126,7 @@ int main(int argc, char *argv[])
#ifndef _WIN32
QList<int> signallist;
signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE
<< SIGILL;
<< SIGILL << SIGRTMIN;
SignalHandler::Init(signallist);
signal(SIGHUP, SIG_IGN);
#endif
Expand Down
2 changes: 1 addition & 1 deletion mythtv/programs/mythfilldatabase/main.cpp
Expand Up @@ -348,7 +348,7 @@ int main(int argc, char *argv[])
#ifndef _WIN32
QList<int> signallist;
signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE
<< SIGILL;
<< SIGILL << SIGRTMIN;
SignalHandler::Init(signallist);
signal(SIGHUP, SIG_IGN);
#endif
Expand Down
2 changes: 1 addition & 1 deletion mythtv/programs/mythfrontend/main.cpp
Expand Up @@ -1478,7 +1478,7 @@ int main(int argc, char **argv)
#ifndef _WIN32
QList<int> signallist;
signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE
<< SIGILL;
<< SIGILL << SIGRTMIN;
SignalHandler::Init(signallist);
SignalHandler::SetHandler(SIGUSR1, handleSIGUSR1);
SignalHandler::SetHandler(SIGUSR2, handleSIGUSR2);
Expand Down
2 changes: 1 addition & 1 deletion mythtv/programs/mythjobqueue/main.cpp
Expand Up @@ -113,7 +113,7 @@ int main(int argc, char *argv[])
#ifndef _WIN32
QList<int> signallist;
signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE
<< SIGILL;
<< SIGILL << SIGRTMIN;
SignalHandler::Init(signallist);
signal(SIGHUP, SIG_IGN);
#endif
Expand Down
2 changes: 1 addition & 1 deletion mythtv/programs/mythlcdserver/main.cpp
Expand Up @@ -100,7 +100,7 @@ int main(int argc, char **argv)
#ifndef _WIN32
QList<int> signallist;
signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE
<< SIGILL;
<< SIGILL << SIGRTMIN;
SignalHandler::Init(signallist);
signal(SIGHUP, SIG_IGN);
#endif
Expand Down
2 changes: 1 addition & 1 deletion mythtv/programs/mythlogserver/main.cpp
Expand Up @@ -105,7 +105,7 @@ int main(int argc, char *argv[])
#ifndef _WIN32
QList<int> signallist;
signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE
<< SIGILL;
<< SIGILL << SIGRTMIN;
SignalHandler::Init(signallist);
SignalHandler::SetHandler(SIGHUP, logSigHup);
#endif
Expand Down
2 changes: 1 addition & 1 deletion mythtv/programs/mythmediaserver/main.cpp
Expand Up @@ -111,7 +111,7 @@ int main(int argc, char *argv[])
#ifndef _WIN32
QList<int> signallist;
signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE
<< SIGILL;
<< SIGILL << SIGRTMIN;
SignalHandler::Init(signallist);
signal(SIGHUP, SIG_IGN);
#endif
Expand Down
2 changes: 1 addition & 1 deletion mythtv/programs/mythmetadatalookup/main.cpp
Expand Up @@ -91,7 +91,7 @@ int main(int argc, char *argv[])
#ifndef _WIN32
QList<int> signallist;
signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE
<< SIGILL;
<< SIGILL << SIGRTMIN;
SignalHandler::Init(signallist);
signal(SIGHUP, SIG_IGN);
#endif
Expand Down
2 changes: 1 addition & 1 deletion mythtv/programs/mythpreviewgen/main.cpp
Expand Up @@ -206,7 +206,7 @@ int main(int argc, char **argv)
#ifndef _WIN32
QList<int> signallist;
signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE
<< SIGILL;
<< SIGILL << SIGRTMIN;
SignalHandler::Init(signallist);
signal(SIGHUP, SIG_IGN);
#endif
Expand Down
2 changes: 1 addition & 1 deletion mythtv/programs/mythshutdown/main.cpp
Expand Up @@ -787,7 +787,7 @@ int main(int argc, char **argv)
#ifndef _WIN32
QList<int> signallist;
signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE
<< SIGILL;
<< SIGILL << SIGRTMIN;
SignalHandler::Init(signallist);
signal(SIGHUP, SIG_IGN);
#endif
Expand Down
2 changes: 1 addition & 1 deletion mythtv/programs/mythtranscode/main.cpp
Expand Up @@ -377,7 +377,7 @@ int main(int argc, char *argv[])
#ifndef _WIN32
QList<int> signallist;
signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE
<< SIGILL;
<< SIGILL << SIGRTMIN;
SignalHandler::Init(signallist);
signal(SIGHUP, SIG_IGN);
#endif
Expand Down
2 changes: 1 addition & 1 deletion mythtv/programs/mythtv-setup/main.cpp
Expand Up @@ -287,7 +287,7 @@ int main(int argc, char *argv[])
#ifndef _WIN32
QList<int> signallist;
signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE
<< SIGILL;
<< SIGILL << SIGRTMIN;
SignalHandler::Init(signallist);
signal(SIGHUP, SIG_IGN);
#endif
Expand Down
2 changes: 1 addition & 1 deletion mythtv/programs/mythutil/main.cpp
Expand Up @@ -79,7 +79,7 @@ int main(int argc, char *argv[])
#ifndef _WIN32
QList<int> signallist;
signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE
<< SIGILL;
<< SIGILL << SIGRTMIN;
SignalHandler::Init(signallist);
signal(SIGHUP, SIG_IGN);
#endif
Expand Down
2 changes: 1 addition & 1 deletion mythtv/programs/mythwelcome/main.cpp
Expand Up @@ -77,7 +77,7 @@ int main(int argc, char **argv)
#ifndef _WIN32
QList<int> signallist;
signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE
<< SIGILL;
<< SIGILL << SIGRTMIN;
SignalHandler::Init(signallist);
signal(SIGHUP, SIG_IGN);
#endif
Expand Down

0 comments on commit c7f0676

Please sign in to comment.