Permalink
Browse files

Make SignalHandler a singleton.

There can only be one SignalHandler object per application.
This allows AddHandler to be a static method so it can
be used outside the main initialization. Since AddHandler
doesn't actually chain handlers as suggested by it's name
this also renames the method to SetHandler.

This also adds a lock for m_sigMap so we can call SetHandler
in a thread other than the main thread.

Finally, this allows a handler to be added for SIGINT and
SIGKILL.
  • Loading branch information...
daniel-kristjansson committed Jul 29, 2012
1 parent 292323d commit f3fb6f066ef12d470695c6934a023e26a557c6bb
@@ -22,6 +22,8 @@ using namespace std;
int SignalHandler::sigFd[2];
volatile bool SignalHandler::s_exit_program = false;
+QMutex SignalHandler::s_singletonLock;
+SignalHandler *SignalHandler::s_singleton;
// We may need to write out signal info using just the write() function
// so we create an array of C strings + measure their lengths.
@@ -87,13 +89,15 @@ SignalHandler::SignalHandler(QList<int> &signallist, QObject *parent) :
continue;
}
- AddHandler(signum, NULL);
+ SetHandlerPrivate(signum, NULL);
}
#endif
}
SignalHandler::~SignalHandler()
{
+ s_singleton = NULL;
+
#ifndef _WIN32
if (m_notifier)
{
@@ -102,6 +106,7 @@ SignalHandler::~SignalHandler()
delete m_notifier;
}
+ QMutexLocker locker(&m_sigMapLock);
QMap<int, void (*)(void)>::iterator it = m_sigMap.begin();
for ( ; it != m_sigMap.end(); ++it)
{
@@ -113,23 +118,61 @@ SignalHandler::~SignalHandler()
#endif
}
-void SignalHandler::AddHandler(int signum, void (*handler)(void))
+void SignalHandler::Init(QList<int> &signallist, QObject *parent)
{
-#ifndef _WIN32
- struct sigaction sa;
- sa.sa_handler = SignalHandler::signalHandler;
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = SA_RESTART;
+ QMutexLocker locker(&s_singletonLock);
+ if (!s_singleton)
+ s_singleton = new SignalHandler(signallist, parent);
+}
+
+void SignalHandler::Done(void)
+{
+ QMutexLocker locker(&s_singletonLock);
+ if (s_singleton)
+ delete s_singleton;
+}
+
+void SignalHandler::SetHandler(int signum, void (*handler)(void))
+{
+ QMutexLocker locker(&s_singletonLock);
+ if (s_singleton)
+ s_singleton->SetHandlerPrivate(signum, handler);
+}
+
+void SignalHandler::SetHandlerPrivate(int signum, void (*handler)(void))
+{
+#ifndef _WIN32
const char *signame = strsignal(signum);
- signame = strdup(signame ? signame : "Unknown");
+ QString signal_name = signame ?
+ QString(signame) : QString("Unknown(%1)").arg(signum);
+
+ bool sa_handler_already_set = false;
+ {
+ QMutexLocker locker(&m_sigMapLock);
+ sa_handler_already_set = m_sigMap.contains(signum);
+ if (m_sigMap.value(signum, NULL) && (handler != NULL))
+ {
+ LOG(VB_GENERAL, LOG_WARNING,
+ QString("Warning %1 signal handler overridden")
+ .arg(signal_name));
+ }
+ m_sigMap[signum] = handler;
+ }
- sig_str_init(signum, signame);
- sigaction(signum, &sa, NULL);
- m_sigMap.insert(signum, handler);
- LOG(VB_GENERAL, LOG_INFO, QString("Setup %1 handler").arg(signame));
+ if (!sa_handler_already_set)
+ {
+ struct sigaction sa;
+ sa.sa_handler = SignalHandler::signalHandler;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_RESTART;
- free((void *)signame);
+ sig_str_init(signum, qPrintable(signal_name));
+
+ sigaction(signum, &sa, NULL);
+ }
+
+ LOG(VB_GENERAL, LOG_INFO, QString("Setup %1 handler").arg(signal_name));
#endif
}
@@ -204,11 +247,20 @@ void SignalHandler::handleSignal(void)
LOG(VB_GENERAL, LOG_CRIT, QString("Received %1").arg(signame));
free((void *)signame);
+ void (*handler)(void) = NULL;
+
switch (signum)
{
case SIGINT:
case SIGTERM:
- qApp->quit();
+ m_sigMapLock.lock();
+ handler = m_sigMap.value(signum, NULL);
+ m_sigMapLock.unlock();
+
+ if (handler)
+ handler();
+ else
+ QCoreApplication::exit(0);
s_exit_program = true;
break;
case SIGSEGV:
@@ -220,7 +272,9 @@ void SignalHandler::handleSignal(void)
s_exit_program = true;
break;
default:
- void (*handler)(void) = m_sigMap.value(signum, NULL);
+ m_sigMapLock.lock();
+ handler = m_sigMap.value(signum, NULL);
+ m_sigMapLock.unlock();
if (handler)
{
handler();
@@ -3,6 +3,7 @@
#include <QObject>
#include <QSocketNotifier>
+#include <QMutex>
#include <QList>
#include <QMap>
@@ -19,10 +20,10 @@ class MBASE_PUBLIC SignalHandler: public QObject
Q_OBJECT
public:
- SignalHandler(QList<int> &signallist, QObject *parent = NULL);
- ~SignalHandler();
+ static void Init(QList<int> &signallist, QObject *parent = NULL);
+ static void Done(void);
- void AddHandler(int signal, void (*handler)(void));
+ static void SetHandler(int signal, void (*handler)(void));
static bool IsExiting(void) { return s_exit_program; }
@@ -34,12 +35,20 @@ class MBASE_PUBLIC SignalHandler: public QObject
void handleSignal(void);
private:
+ SignalHandler(QList<int> &signallist, QObject *parent);
+ ~SignalHandler();
+ void SetHandlerPrivate(int signal, void (*handler)(void));
+
static int sigFd[2];
static volatile bool s_exit_program;
QSocketNotifier *m_notifier;
+ QMutex m_sigMapLock;
QMap<int, void (*)(void)> m_sigMap;
static QList<int> s_defaultHandlerList;
+
+ static QMutex s_singletonLock;
+ static SignalHandler *s_singleton;
};
#endif
@@ -225,6 +225,14 @@ int main(int argc, char *argv[])
MythMainWindow *mainWindow = GetMythMainWindow();
mainWindow->Init();
+#ifndef _WIN32
+ QList<int> signallist;
+ signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE
+ << SIGILL;
+ SignalHandler::Init(signallist);
+ signal(SIGHUP, SIG_IGN);
+#endif
+
if (cmdline.toBool("test"))
{
int seconds = 5;
@@ -261,6 +269,8 @@ int main(int argc, char *argv[])
delete gContext;
+ SignalHandler::Done();
+
return GENERIC_EXIT_OK;
}
@@ -104,7 +104,7 @@ int main(int argc, char **argv)
QList<int> signallist;
signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE
<< SIGILL;
- SignalHandler handler(signallist);
+ SignalHandler::Init(signallist);
signal(SIGHUP, SIG_IGN);
#endif
@@ -50,6 +50,7 @@
#include "backendcontext.h"
#include "mythtranslation.h"
#include "mythtimezone.h"
+#include "signalhandling.h"
#include "mediaserver.h"
#include "httpstatus.h"
@@ -268,6 +269,8 @@ void cleanup(void)
unlink(pidfile.toAscii().constData());
pidfile.clear();
}
+
+ SignalHandler::Done();
}
int handle_command(const MythBackendCommandLineParser &cmdline)
@@ -25,6 +25,7 @@ namespace {
{
delete gContext;
gContext = NULL;
+ SignalHandler::Done();
}
class CleanupGuard
@@ -145,7 +146,7 @@ int main(int argc, char *argv[])
QList<int> signallist;
signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE
<< SIGILL;
- SignalHandler handler(signallist);
+ SignalHandler::Init(signallist);
signal(SIGHUP, SIG_IGN);
#endif
@@ -57,7 +57,7 @@ namespace
{
delete gContext;
gContext = NULL;
-
+ SignalHandler::Done();
}
class CleanupGuard
@@ -1127,7 +1127,7 @@ int main(int argc, char *argv[])
QList<int> signallist;
signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE
<< SIGILL;
- SignalHandler handler(signallist);
+ SignalHandler::Init(signallist);
signal(SIGHUP, SIG_IGN);
#endif
@@ -38,7 +38,7 @@ namespace
{
delete gContext;
gContext = NULL;
-
+ SignalHandler::Done();
}
class CleanupGuard
@@ -349,7 +349,7 @@ int main(int argc, char *argv[])
QList<int> signallist;
signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE
<< SIGILL;
- SignalHandler handler(signallist);
+ SignalHandler::Init(signallist);
signal(SIGHUP, SIG_IGN);
#endif
@@ -267,6 +267,8 @@ namespace
ReferenceCounter::PrintDebug();
delete qApp;
+
+ SignalHandler::Done();
}
class CleanupGuard
@@ -1477,9 +1479,9 @@ int main(int argc, char **argv)
QList<int> signallist;
signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE
<< SIGILL;
- SignalHandler handler(signallist);
- handler.AddHandler(SIGUSR1, handleSIGUSR1);
- handler.AddHandler(SIGUSR2, handleSIGUSR2);
+ SignalHandler::Init(signallist);
+ SignalHandler::SetHandler(SIGUSR1, handleSIGUSR1);
+ SignalHandler::SetHandler(SIGUSR2, handleSIGUSR2);
signal(SIGHUP, SIG_IGN);
#endif
@@ -50,6 +50,8 @@ static void cleanup(void)
unlink(pidfile.toAscii().constData());
pidfile.clear();
}
+
+ SignalHandler::Done();
}
namespace
@@ -112,7 +114,7 @@ int main(int argc, char *argv[])
QList<int> signallist;
signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE
<< SIGILL;
- SignalHandler handler(signallist);
+ SignalHandler::Init(signallist);
signal(SIGHUP, SIG_IGN);
#endif
@@ -101,7 +101,7 @@ int main(int argc, char **argv)
QList<int> signallist;
signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE
<< SIGILL;
- SignalHandler handler(signallist);
+ SignalHandler::Init(signallist);
signal(SIGHUP, SIG_IGN);
#endif
@@ -111,6 +111,7 @@ int main(int argc, char **argv)
{
LOG(VB_GENERAL, LOG_ERR,
"lcdserver: Could not initialize MythContext. Exiting.");
+ SignalHandler::Done();
return GENERIC_EXIT_NO_MYTHCONTEXT;
}
@@ -130,6 +131,9 @@ int main(int argc, char **argv)
a.exec();
delete gContext;
+
+ SignalHandler::Done();
+
return GENERIC_EXIT_OK;
}
@@ -106,8 +106,8 @@ int main(int argc, char *argv[])
QList<int> signallist;
signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE
<< SIGILL;
- SignalHandler handler(signallist);
- handler.AddHandler(SIGHUP, logSigHup);
+ SignalHandler::Init(signallist);
+ SignalHandler::SetHandler(SIGHUP, logSigHup);
#endif
gContext = new MythContext(MYTH_BINARY_VERSION);
@@ -119,6 +119,8 @@ int main(int argc, char *argv[])
qApp->exec();
+ SignalHandler::Done();
+
return GENERIC_EXIT_OK;
}
@@ -48,6 +48,8 @@ static void cleanup(void)
unlink(pidfile.toAscii().constData());
pidfile.clear();
}
+
+ SignalHandler::Done();
}
namespace
@@ -110,7 +112,7 @@ int main(int argc, char *argv[])
QList<int> signallist;
signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE
<< SIGILL;
- SignalHandler handler(signallist);
+ SignalHandler::Init(signallist);
signal(SIGHUP, SIG_IGN);
#endif
Oops, something went wrong.

0 comments on commit f3fb6f0

Please sign in to comment.