Permalink
Browse files

Adapt signal handlers to Qt event loop

This commit finally converts the main loop to app.exec().  The last
missing piece was the POSIX signal handlers that need to be adapted to
the Qt event loop.

Qt integration for POSIX signals is poor so we use ugly adapter code
that converts signals into writes on a socketpair(2) file descriptor.

The good news is that the server is now event-driven and only consumes
CPU when there is event processing work to be done!

Signed-off-by: Stefan Hajnoczi <stefanha@gmail.com>
  • Loading branch information...
stefanha committed Apr 18, 2012
1 parent 62eb8ca commit d50f36934bdcd3c80d38ff27f25b9089195448a0
@@ -0,0 +1,97 @@
+/*
+ Copyright (C) 2012 Stefan Hajnoczi <stefanha@gmail.com>
+
+ Wahjam is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ Wahjam is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Wahjam; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <errno.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <QCoreApplication>
+
+#include "ninjamsrv.h"
+#include "SignalHandler.h"
+
+/* These need to be global since the signal handler has no instance pointer */
+static int sigHupFds[2];
+static int sigIntFds[2];
+
+SignalHandler::SignalHandler(int argc_, char **argv_)
+ : argc(argc_), argv(argv_)
+{
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, sigHupFds) != 0) {
+ qFatal("socketpair failed %d", errno);
+ }
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, sigIntFds) != 0) {
+ qFatal("socketpair failed %d", errno);
+ }
+
+ sigHupNotifier = new QSocketNotifier(sigHupFds[1], QSocketNotifier::Read, this);
+ connect(sigHupNotifier, SIGNAL(activated(int)), this, SLOT(onSigHup()));
+
+ sigIntNotifier = new QSocketNotifier(sigIntFds[1], QSocketNotifier::Read, this);
+ connect(sigIntNotifier, SIGNAL(activated(int)), this, SLOT(onSigInt()));
+
+ signal(SIGPIPE, SIG_IGN);
+ signal(SIGHUP, handleSigHup);
+ signal(SIGINT, handleSigInt);
+}
+
+SignalHandler::~SignalHandler()
+{
+ signal(SIGPIPE, SIG_DFL);
+ signal(SIGHUP, SIG_DFL);
+ signal(SIGINT, SIG_DFL);
+
+ close(sigHupFds[0]);
+ close(sigHupFds[1]);
+ close(sigIntFds[0]);
+ close(sigIntFds[1]);
+}
+
+void SignalHandler::onSigHup()
+{
+ sigHupNotifier->setEnabled(false);
+ char dummy;
+ read(sigHupFds[1], &dummy, sizeof(dummy));
+
+ reloadConfig(argc, argv, false);
+
+ sigHupNotifier->setEnabled(true);
+}
+
+void SignalHandler::onSigInt()
+{
+ sigIntNotifier->setEnabled(false);
+ char dummy;
+ read(sigIntFds[1], &dummy, sizeof(dummy));
+
+ QCoreApplication::quit();
+
+ sigIntNotifier->setEnabled(true);
+}
+
+void SignalHandler::handleSigHup(int)
+{
+ char dummy = 0;
+ write(sigHupFds[0], &dummy, sizeof(dummy));
+}
+
+void SignalHandler::handleSigInt(int)
+{
+ char dummy = 0;
+ write(sigIntFds[0], &dummy, sizeof(dummy));
+}
@@ -0,0 +1,55 @@
+/*
+ Copyright (C) 2012 Stefan Hajnoczi <stefanha@gmail.com>
+
+ Wahjam is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ Wahjam is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Wahjam; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef _SIGNALHANDLER_H_
+#define _SIGNALHANDLER_H_
+
+#include <QSocketNotifier>
+
+/*
+ * Adapter for POSIX signal handlers to Qt event loop
+ *
+ * Note there can only be a single instance of this class at any time because
+ * the signal disposition for the entire process is affected.
+ */
+class SignalHandler : public QObject
+{
+ Q_OBJECT
+
+public:
+ SignalHandler(int argc_, char **argv_);
+ ~SignalHandler();
+
+ void setup();
+ void cleanup();
+
+private slots:
+ void onSigHup();
+ void onSigInt();
+
+private:
+ static void handleSigHup(int);
+ static void handleSigInt(int);
+
+ int argc;
+ char **argv;
+ QSocketNotifier *sigHupNotifier;
+ QSocketNotifier *sigIntNotifier;
+};
+
+#endif /* _SIGNALHANDLER_H_ */
@@ -36,7 +36,6 @@
#include <string.h>
#endif
#include <time.h>
-#include <signal.h>
#include <stdarg.h>
#include <QCoreApplication>
@@ -51,6 +50,9 @@
#include "../../WDL/string.h"
#include "Server.h"
+#ifndef _WIN32
+#include "SignalHandler.h"
+#endif
#include "ninjamsrv.h"
#define VERSION "v0.06"
@@ -545,24 +547,6 @@ static int ReadConfig(ServerConfig *config, char *configfile)
return 0;
}
-static int g_reloadconfig;
-static int g_done;
-
-
-void sighandler(int sig)
-{
- if (sig == SIGINT)
- {
- g_done=1;
- }
-#ifndef _WIN32
- if (sig == SIGHUP)
- {
- g_reloadconfig=1;
- }
-#endif
-}
-
void usage(const char *progname)
{
printf("Usage: %s config.cfg [options]\n"
@@ -686,14 +670,7 @@ int main(int argc, char **argv)
}
else printf("Error opening PID file '%s'\n", g_config.pidFilename.Get());
}
-
-
-
- signal(SIGPIPE,sighandler);
- signal(SIGHUP,sighandler);
#endif
- signal(SIGINT,sighandler);
-
if (g_config.logFilename.Get()[0])
{
@@ -707,16 +684,15 @@ int main(int argc, char **argv)
logText("Server starting up...\n");
- while (!g_done)
- {
- app.processEvents(QEventLoop::AllEvents, 1 /* milliseconds */);
+#ifndef _WIN32
+ SignalHandler *sigHandler = new SignalHandler(argc, argv);
+#endif
- if (g_reloadconfig && strcmp(argv[1],"-"))
- {
- g_reloadconfig=0;
- reloadConfig(argc, argv, false);
- }
- }
+ app.exec();
+
+#ifndef _WIN32
+ delete sigHandler;
+#endif
logText("Shutting down server\n");
@@ -21,5 +21,6 @@
#define _NINJAMSRV_H_
void logText(const char *s, ...);
+bool reloadConfig(int argc, char **argv, bool firstTime);
#endif /* _NINJAMSRV_H_ */
@@ -12,6 +12,11 @@ QT += network
# Core ninjam/ code does not use wide characters
win32:DEFINES -= UNICODE
+unix {
+ HEADERS += SignalHandler.h
+ SOURCES += SignalHandler.cpp
+}
+
# Input
HEADERS += usercon.h \
Server.h \

0 comments on commit d50f369

Please sign in to comment.