Skip to content

Commit

Permalink
Make SignalHandler a singleton.
Browse files Browse the repository at this point in the history
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 30, 2012
1 parent 292323d commit f3fb6f0
Show file tree
Hide file tree
Showing 20 changed files with 147 additions and 41 deletions.
84 changes: 69 additions & 15 deletions mythtv/libs/libmythbase/signalhandling.cpp
Expand Up @@ -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.
Expand Down Expand Up @@ -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)
{
Expand All @@ -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)
{
Expand All @@ -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
}

Expand Down Expand Up @@ -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:
Expand All @@ -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();
Expand Down
15 changes: 12 additions & 3 deletions mythtv/libs/libmythbase/signalhandling.h
Expand Up @@ -3,6 +3,7 @@

#include <QObject>
#include <QSocketNotifier>
#include <QMutex>
#include <QList>
#include <QMap>

Expand All @@ -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; }

Expand All @@ -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
Expand Down
10 changes: 10 additions & 0 deletions mythtv/programs/mythavtest/main.cpp
Expand Up @@ -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;
Expand Down Expand Up @@ -261,6 +269,8 @@ int main(int argc, char *argv[])

delete gContext;

SignalHandler::Done();

return GENERIC_EXIT_OK;
}

Expand Down
2 changes: 1 addition & 1 deletion mythtv/programs/mythbackend/main.cpp
Expand Up @@ -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

Expand Down
3 changes: 3 additions & 0 deletions mythtv/programs/mythbackend/main_helpers.cpp
Expand Up @@ -50,6 +50,7 @@
#include "backendcontext.h"
#include "mythtranslation.h"
#include "mythtimezone.h"
#include "signalhandling.h"

#include "mediaserver.h"
#include "httpstatus.h"
Expand Down Expand Up @@ -268,6 +269,8 @@ void cleanup(void)
unlink(pidfile.toAscii().constData());
pidfile.clear();
}

SignalHandler::Done();
}

int handle_command(const MythBackendCommandLineParser &cmdline)
Expand Down
3 changes: 2 additions & 1 deletion mythtv/programs/mythccextractor/main.cpp
Expand Up @@ -25,6 +25,7 @@ namespace {
{
delete gContext;
gContext = NULL;
SignalHandler::Done();
}

class CleanupGuard
Expand Down Expand Up @@ -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

Expand Down
4 changes: 2 additions & 2 deletions mythtv/programs/mythcommflag/main.cpp
Expand Up @@ -57,7 +57,7 @@ namespace
{
delete gContext;
gContext = NULL;

SignalHandler::Done();
}

class CleanupGuard
Expand Down Expand Up @@ -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

Expand Down
4 changes: 2 additions & 2 deletions mythtv/programs/mythfilldatabase/main.cpp
Expand Up @@ -38,7 +38,7 @@ namespace
{
delete gContext;
gContext = NULL;

SignalHandler::Done();
}

class CleanupGuard
Expand Down Expand Up @@ -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

Expand Down
8 changes: 5 additions & 3 deletions mythtv/programs/mythfrontend/main.cpp
Expand Up @@ -267,6 +267,8 @@ namespace
ReferenceCounter::PrintDebug();

delete qApp;

SignalHandler::Done();
}

class CleanupGuard
Expand Down Expand Up @@ -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

Expand Down
4 changes: 3 additions & 1 deletion mythtv/programs/mythjobqueue/main.cpp
Expand Up @@ -50,6 +50,8 @@ static void cleanup(void)
unlink(pidfile.toAscii().constData());
pidfile.clear();
}

SignalHandler::Done();
}

namespace
Expand Down Expand Up @@ -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

Expand Down
6 changes: 5 additions & 1 deletion mythtv/programs/mythlcdserver/main.cpp
Expand Up @@ -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

Expand All @@ -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;
}

Expand All @@ -130,6 +131,9 @@ int main(int argc, char **argv)
a.exec();

delete gContext;

SignalHandler::Done();

return GENERIC_EXIT_OK;
}

6 changes: 4 additions & 2 deletions mythtv/programs/mythlogserver/main.cpp
Expand Up @@ -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);
Expand All @@ -119,6 +119,8 @@ int main(int argc, char *argv[])

qApp->exec();

SignalHandler::Done();

return GENERIC_EXIT_OK;
}

Expand Down
4 changes: 3 additions & 1 deletion mythtv/programs/mythmediaserver/main.cpp
Expand Up @@ -48,6 +48,8 @@ static void cleanup(void)
unlink(pidfile.toAscii().constData());
pidfile.clear();
}

SignalHandler::Done();
}

namespace
Expand Down Expand Up @@ -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

Expand Down

0 comments on commit f3fb6f0

Please sign in to comment.