Permalink
Browse files

Moved UNIX signal handling to signalhandling.cpp

According to Qt docs, we were doing something very bad.  We were using Qt
functions inside our signal handler.  This is expressly forbidden.  I reworked
the handlers to their scheme for safety.

See: http://qt-project.org/doc/qt-4.8/unix-signals.html
  • Loading branch information...
Beirdo committed May 2, 2012
1 parent c2132cf commit baee9ac9e7750f19a0b50d8d80dd80a863f48f55
@@ -24,7 +24,7 @@ HEADERS += mythmiscutil.h mythhdd.h mythcdrom.h autodeletedeque.h dbutil.h
HEADERS += mythhttppool.h mythhttphandler.h mythdeque.h mythlogging.h
HEADERS += mythbaseutil.h referencecounter.h version.h mythcommandlineparser.h
HEADERS += mythscheduler.h filesysteminfo.h hardwareprofile.h serverpool.h
-HEADERS += plist.h
+HEADERS += plist.h signalhandling.h
SOURCES += mthread.cpp mthreadpool.cpp
SOURCES += mythsocket.cpp mythsocketthread.cpp msocketdevice.cpp
@@ -39,7 +39,7 @@ SOURCES += mythhdd.cpp mythcdrom.cpp dbutil.cpp
SOURCES += mythhttppool.cpp mythhttphandler.cpp logging.cpp loggingserver.cpp
SOURCES += referencecounter.cpp mythcommandlineparser.cpp
SOURCES += filesysteminfo.cpp hardwareprofile.cpp serverpool.cpp
-SOURCES += plist.cpp
+SOURCES += plist.cpp signalhandling.cpp
win32:SOURCES += msocketdevice_win.cpp
unix {
@@ -66,7 +66,7 @@ inc.files += mythtranslation.h iso639.h iso3166.h mythmedia.h mythmiscutil.h
inc.files += mythcdrom.h autodeletedeque.h dbutil.h mythhttppool.h mythdeque.h
inc.files += referencecounter.h mythcommandlineparser.h mthread.h mthreadpool.h
inc.files += filesysteminfo.h hardwareprofile.h bonjourregister.h serverpool.h
-inc.files += plist.h
+inc.files += plist.h signalhandling.h
# Allow both #include <blah.h> and #include <libmythbase/blah.h>
inc2.path = $${PREFIX}/include/mythtv/libmythbase
@@ -11,6 +11,7 @@
#include <QMap>
#include <QRegExp>
#include <QTimer>
+#include <QSocketNotifier>
#include <iostream>
using namespace std;
@@ -88,7 +89,8 @@ static QWaitCondition logMsgListNotEmpty;
#define MAX_STRING_LENGTH (LOGLINE_MAX+120)
#ifndef _WIN32
-void logSighup( int signum, siginfo_t *info, void *secret );
+static int sighupFd[2];
+void logSighup(int signum);
#endif
@@ -600,10 +602,25 @@ void DBLoggerThread::stop(void)
+#ifndef _WIN32
+/// \brief UNIX-side SIGHUP signal handler. Hand it off to the Qt-size via
+/// a socketpair so Qt code can safely be used.
+
+void logSighup(int signum)
+{
+ (void)signum;
+ char a = 1;
+ int ret = ::write(sighupFd[0], &a, sizeof(a));
+ (void)ret;
+}
+#endif
+
/// \brief LogServerThread constructor.
LogServerThread::LogServerThread() :
- MThread("LogServer"), m_aborted(false)
+ MThread("LogServer"), m_aborted(false), m_zmqContext(NULL),
+ m_zmqInSock(NULL), m_zmqPubSock(NULL), m_heartbeatTimer(NULL),
+ m_shutdownTimer(NULL), m_sighupNotifier(NULL)
{
moveToThread(qthread());
}
@@ -625,6 +642,26 @@ void LogServerThread::run(void)
logThreadFinished = false;
QMutexLocker locker(&logThreadStartedMutex);
+#ifndef _WIN32
+ if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sighupFd))
+ {
+ LOG(VB_GENERAL, LOG_ERR, "Couldn't create HUP socketpair");
+ qApp->quit();
+ }
+ m_sighupNotifier = new QSocketNotifier(sighupFd[1], QSocketNotifier::Read,
+ this);
+ connect(m_sighupNotifier, SIGNAL(activated(int)),
+ this, SLOT(handleSigHup()));
+
+ /* Setup SIGHUP */
+ LOG(VB_GENERAL, LOG_NOTICE, "Setting up SIGHUP handler");
+ struct sigaction sa;
+ sa.sa_handler = logSighup;
+ sigemptyset( &sa.sa_mask );
+ sa.sa_flags = SA_RESTART;
+ sigaction( SIGHUP, &sa, NULL );
+#endif
+
qRegisterMetaType<QList<QByteArray> >("QList<QByteArray>");
m_zmqContext = nzmqt::createDefaultContext(NULL);
@@ -678,6 +715,19 @@ void LogServerThread::run(void)
logThreadFinished = true;
+ delete m_sighupNotifier;
+
+#ifndef _WIN32
+ ::close(sighupFd[0]);
+ ::close(sighupFd[1]);
+
+ /* Tear down SIGHUP */
+ sa.sa_handler = SIG_DFL;
+ sigemptyset( &sa.sa_mask );
+ sa.sa_flags = SA_RESTART;
+ sigaction( SIGHUP, &sa, NULL );
+#endif
+
m_heartbeatTimer->stop();
delete m_heartbeatTimer;
@@ -722,6 +772,30 @@ void LogServerThread::pingClient(QString clientId)
m_zmqInSock->sendMessage(msg);
}
+/// \brief SIGHUP handler - reopen all open logfiles for logrollers
+void LogServerThread::handleSigHup(void)
+{
+#ifndef _WIN32
+ m_sighupNotifier->setEnabled(false);
+
+ char tmp;
+ int ret = ::read(sighupFd[1], &tmp, sizeof(tmp));
+ (void)ret;
+
+ LOG(VB_GENERAL, LOG_INFO, "SIGHUP received, rolling log files.");
+
+ /* SIGHUP was sent. Close and reopen debug logfiles */
+ QMutexLocker locker(&loggerMapMutex);
+ QMap<QString, LoggerBase *>::iterator it;
+ for (it = loggerMap.begin(); it != loggerMap.end(); ++it)
+ {
+ it.value()->reopen();
+ }
+
+ m_sighupNotifier->setEnabled(true);
+#endif
+}
+
/// \brief Fires off when no clients are left (other than the current daemon)
/// for 5 minutes.
@@ -1017,22 +1091,6 @@ static QTime memory_time;
#endif
-#ifndef _WIN32
-/// \brief SIGHUP handler - reopen all open logfiles for logrollers
-void logSighup( int signum, siginfo_t *info, void *secret )
-{
- LOG(VB_GENERAL, LOG_INFO, "SIGHUP received, rolling log files.");
-
- /* SIGHUP was sent. Close and reopen debug logfiles */
- QMutexLocker locker(&loggerMapMutex);
- QMap<QString, LoggerBase *>::iterator it;
- for (it = loggerMap.begin(); it != loggerMap.end(); ++it)
- {
- it.value()->reopen();
- }
-}
-#endif
-
/// \brief Entry point to start logging for the application. This will
/// start up all of the threads needed.
@@ -1054,16 +1112,6 @@ void logServerStart(void)
if (!logServerThread)
logServerThread = new LogServerThread();
-#ifndef _WIN32
- /* Setup SIGHUP */
- LOG(VB_GENERAL, LOG_NOTICE, "Setting up SIGHUP handler");
- struct sigaction sa;
- sa.sa_sigaction = logSighup;
- sigemptyset( &sa.sa_mask );
- sa.sa_flags = SA_RESTART | SA_SIGINFO;
- sigaction( SIGHUP, &sa, NULL );
-#endif
-
QMutexLocker locker(&logThreadStartedMutex);
logServerThread->start();
logThreadStarted.wait(locker.mutex());
@@ -1079,15 +1127,6 @@ void logServerStop(void)
logServerThread->wait();
}
-#ifndef _WIN32
- /* Tear down SIGHUP */
- struct sigaction sa;
- sa.sa_handler = SIG_DFL;
- sigemptyset( &sa.sa_mask );
- sa.sa_flags = SA_RESTART;
- sigaction( SIGHUP, &sa, NULL );
-#endif
-
QMutexLocker locker(&loggerMapMutex);
QMap<QString, LoggerBase *>::iterator it;
for (it = loggerMap.begin(); it != loggerMap.end(); ++it)
@@ -2,6 +2,7 @@
#define LOGGINGSERVER_H_
#include <QMutexLocker>
+#include <QSocketNotifier>
#include <QMutex>
#include <QQueue>
#include <QTime>
@@ -128,6 +129,8 @@ typedef QList<LogMessage *> LogMessageList;
class LogServerThread : public QObject, public MThread
{
Q_OBJECT;
+
+ friend void logSighup(int signum);
public:
LogServerThread();
~LogServerThread();
@@ -143,13 +146,16 @@ class LogServerThread : public QObject, public MThread
QTimer *m_heartbeatTimer; ///< 1s repeating timer for client
/// heartbeats
QTimer *m_shutdownTimer; ///< 5 min timer to shut down if no clients
+ QSocketNotifier *m_sighupNotifier; ///< Notifier to synchronize to UNIX
+ /// signal SIGHUP safely
void forwardMessage(LogMessage *msg);
void pingClient(QString clientId);
protected slots:
void receivedMessage(const QList<QByteArray>&);
void checkHeartBeats(void);
void shutdownTimerExpired(void);
+ void handleSigHup(void);
};
class QWaitCondition;
Oops, something went wrong.

0 comments on commit baee9ac

Please sign in to comment.