From: APTX Date: Sun, 29 Jan 2017 14:27:06 +0000 (+0100) Subject: Properly handle UNIX signals. X-Git-Url: https://gitweb.aptx.org/?a=commitdiff_plain;h=a4d0ce950521d60df3dd340ee003801aedf7232f;p=localmylist.git Properly handle UNIX signals. 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 --- diff --git a/.gitignore b/.gitignore index 1e8cc43..4d5d29b 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/anioni/anioni.cpp b/anioni/anioni.cpp old mode 100644 new mode 100755 index 48f345f..164e684 --- a/anioni/anioni.cpp +++ b/anioni/anioni.cpp @@ -13,6 +13,14 @@ #include #include +#ifdef Q_OS_UNIX +# include +# include +# include +# include +# include +#endif + AniOni::AniOni(int argc, char **argv) : QObject(), QtService(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(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(signal); + auto ignored = ::write(signalFd[0], &c, sizeof(c)); + (void)ignored; +} + +int AniOni::signalFd[2] = {}; +#endif diff --git a/anioni/anioni.h b/anioni/anioni.h old mode 100644 new mode 100755 index d618209..f641d9e --- a/anioni/anioni.h +++ b/anioni/anioni.h @@ -5,6 +5,9 @@ #include class QTimer; +#ifdef Q_OS_UNIX +class QSocketNotifier; +#endif class AniOni : public QObject, public QtService { @@ -12,10 +15,6 @@ class AniOni : public QObject, public QtService 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; diff --git a/anioni/main.cpp b/anioni/main.cpp old mode 100644 new mode 100755 index 55bbac0..2508a1a --- a/anioni/main.cpp +++ b/anioni/main.cpp @@ -1,32 +1,7 @@ #include "anioni.h" -#ifdef Q_OS_UNIX -# include - -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(); }