Permalink
Browse files

Add support for real time signal 0 handling

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 22, 2012
1 parent 8611c6e commit c7f0676059a6e901b760e596750876783502c1a5
@@ -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))
@@ -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();
@@ -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);
@@ -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));
@@ -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
@@ -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)
{
@@ -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));
@@ -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
{
@@ -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.
@@ -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;
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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);
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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

0 comments on commit c7f0676

Please sign in to comment.