]> Some of my projects - localmylist.git/commitdiff
Properly handle UNIX signals.
authorAPTX <marek321@gmail.com>
Sun, 29 Jan 2017 14:27:06 +0000 (15:27 +0100)
committerAPTX <marek321@gmail.com>
Sun, 29 Jan 2017 14:27:06 +0000 (15:27 +0100)
Very few operations can actualy be done in a signal handler.
This change follows Qt's recommendation on calling Qt functions
from UNIX signal handlers:

http://doc.qt.io/qt-5/unix-signals.html

.gitignore
anioni/anioni.cpp [changed mode: 0644->0755]
anioni/anioni.h [changed mode: 0644->0755]
anioni/main.cpp [changed mode: 0644->0755]

index 1e8cc4338dfbf248b8c77099e4baa02f2f00886d..4d5d29b202e0fe6b819dae215e11e239c0476df7 100644 (file)
@@ -26,11 +26,17 @@ Makefile*
 moc_*.cpp
 ui_*.h
 qrc_*.cpp
+*.qmake.stash
 
 # qtcreator generated files
 *.pro.user
 *.pro.user.*
 *.autosave
+*.files
+*.creator
+*.creator.*
+*.config
+*.includes
 
 # xemacs temporary files
 *.flc
old mode 100644 (file)
new mode 100755 (executable)
index 48f345f..164e684
 #include <QTimer>
 #include <QDebug>
 
+#ifdef Q_OS_UNIX
+#      include <QSocketNotifier>
+#      include <signal.h>
+#      include <unistd.h>
+#      include <sys/types.h>
+#      include <sys/socket.h>
+#endif
+
 AniOni::AniOni(int argc, char **argv) :
        QObject(), QtService<QCoreApplication>(argc, argv, "LocalMyList Daemon")
 {
@@ -20,7 +28,11 @@ AniOni::AniOni(int argc, char **argv) :
        runUdpClient = false;
        runRenameHandler = false;
        watchDirectories = false;
-       requestFailTimer = 0;
+       requestFailTimer = nullptr;
+#ifdef Q_OS_UNIX
+       setupUnixSignalHandler();
+       signalFdNotifier = nullptr;
+#endif
 }
 
 void AniOni::handleUdpClientError()
@@ -78,6 +90,11 @@ void AniOni::failRequests()
 
 void AniOni::start()
 {
+#ifdef Q_OS_UNIX
+       signalFdNotifier = new QSocketNotifier(signalFd[1], QSocketNotifier::Read, this);
+       connect(signalFdNotifier, SIGNAL(activated(int)), this, SLOT(handleUnixSignal()));
+#endif
+
 #if defined(Q_OS_WIN)
        QSettings s(QDir::currentPath() + "/anioni.ini", QSettings::IniFormat);
 #elif defined(Q_OS_UNIX)
@@ -150,6 +167,21 @@ void AniOni::start()
        requestFailTimer->start();
 }
 
+#ifdef Q_OS_UNIX
+void AniOni::handleUnixSignal()
+{
+       signalFdNotifier->setEnabled(false);
+       char tmp;
+       auto ignored = ::read(signalFd[1], &tmp, sizeof(tmp));
+       (void)ignored;
+
+       int signal = static_cast<int>(tmp);
+       qInfo("Got signal %d, quitting...", signal);
+       QTimer::singleShot(0, qApp, SLOT(quit()));
+       signalFdNotifier->setEnabled(true);
+}
+#endif
+
 void AniOni::loadSettings(QSettings &s)
 {
        LocalMyList::instance()->loadLocalSettings(s);
@@ -166,3 +198,34 @@ void AniOni::log(const QString &message, QtServiceBase::MessageType type)
        logMessage(message, type);
        qWarning() << message;
 }
+
+#ifdef Q_OS_UNIX
+void AniOni::setupUnixSignalHandler()
+{
+       if (::socketpair(AF_UNIX, SOCK_STREAM, 0, signalFd))
+               qFatal("Couldn't create signal socketpair");
+
+       struct sigaction action;
+       action.sa_handler = &AniOni::unixSignalHandler;
+       sigemptyset(&action.sa_mask);
+       action.sa_flags = 0;
+       action.sa_flags |= SA_RESTART;
+
+       if (sigaction(SIGTERM, &action, NULL) < 0)
+               qFatal("Failed to set SIGTERM handler");
+       if (sigaction(SIGINT, &action, NULL) < 0)
+               qFatal("Failed to set SIGINT handler");
+       if (sigaction(SIGHUP, &action, NULL) < 0)
+               qFatal("Failed to set SIGHUP handler");
+}
+
+void AniOni::unixSignalHandler(int signal)
+{
+       qWarning("handling signal %d", signal);
+       char c = static_cast<char>(signal);
+       auto ignored = ::write(signalFd[0], &c, sizeof(c));
+       (void)ignored;
+}
+
+int AniOni::signalFd[2] = {};
+#endif
old mode 100644 (file)
new mode 100755 (executable)
index d618209..f641d9e
@@ -5,6 +5,9 @@
 #include <QSettings>
 
 class QTimer;
+#ifdef Q_OS_UNIX
+class QSocketNotifier;
+#endif
 
 class AniOni : public QObject, public QtService<QCoreApplication>
 {
@@ -12,10 +15,6 @@ class AniOni : public QObject, public QtService<QCoreApplication>
 public:
        explicit AniOni(int argc, char **argv);
 
-signals:
-       
-public slots:
-
 protected slots:
        void handleUdpClientError();
        void failRequests();
@@ -23,10 +22,22 @@ protected slots:
 protected:
        void start();
 
+private slots:
+#ifdef Q_OS_UNIX
+       void handleUnixSignal();
+#endif
+
 private:
        void loadSettings(QSettings &s);
        void log(const QString &message, QtServiceBase::MessageType type);
 
+#ifdef Q_OS_UNIX
+       static void setupUnixSignalHandler();
+       static void unixSignalHandler(int signal);
+       static int signalFd[2];
+       QSocketNotifier *signalFdNotifier;
+#endif
+
        bool runUdpClient;
        bool runRenameHandler;
        bool watchDirectories;
old mode 100644 (file)
new mode 100755 (executable)
index 55bbac0..2508a1a
@@ -1,32 +1,7 @@
 #include "anioni.h"
 
-#ifdef Q_OS_UNIX
-#      include <signal.h>
-
-void sighandler(int)
-{
-       qDebug("Caught signal. Exiting...");
-       qApp->quit();
-}
-#endif
-
 int main(int argc, char *argv[])
 {
        AniOni a(argc, argv);
-
-#ifdef Q_OS_UNIX
-       struct sigaction action;
-       action.sa_handler = sighandler;
-       sigemptyset(&action.sa_mask);
-       action.sa_flags = 0;
-
-       if (sigaction(SIGTERM, &action, NULL) < 0)
-               qWarning("Failed to set signal handler");
-       if (sigaction(SIGINT, &action, NULL) < 0)
-               qWarning("Failed to set signal handler");
-       if (sigaction(SIGHUP, &action, NULL) < 0)
-               qWarning("Failed to set signal handler");
-#endif
-
        return a.exec();
 }