Index: kdevplatform/shell/CMakeLists.txt =================================================================== --- kdevplatform/shell/CMakeLists.txt +++ kdevplatform/shell/CMakeLists.txt @@ -159,6 +159,10 @@ if(APPLE) target_link_libraries(KDevPlatformShell PRIVATE "-framework AppKit") endif() +if(UNIX) + target_link_libraries(KDevPlatformShell PRIVATE "-pthreads") +endif() + install(FILES mainwindow.h Index: kdevplatform/shell/core.cpp =================================================================== --- kdevplatform/shell/core.cpp +++ kdevplatform/shell/core.cpp @@ -21,6 +21,7 @@ #include "core_p.h" #include +#include #include @@ -51,37 +52,52 @@ #include namespace { -void shutdownGracefully(int sig) +static KDevelop::CorePrivate *corePrivateInstance = nullptr; +static int signalPipeRead = -1; +static int signalPipeWrite = -1; +static volatile std::sig_atomic_t signalReceived = 0; +static QSocketNotifier* signalNotifier = nullptr; + +void shutdownGracefully() { static volatile std::sig_atomic_t handlingSignal = 0; + int sig = signalReceived; + + signalReceived = 0; if ( !handlingSignal ) { handlingSignal = 1; - qCDebug(SHELL) << "signal " << sig << " received, shutting down gracefully"; + qCWarning(SHELL) << "Going down on signal" << sig; QCoreApplication* app = QCoreApplication::instance(); if (QApplication* guiApp = qobject_cast(app)) { guiApp->closeAllWindows(); } app->quit(); return; } + signalNotifier->setEnabled(false); + // re-raise signal with default handler and trigger program termination std::signal(sig, SIG_DFL); std::raise(sig); } +void signalHandler(int sig) +{ + signalReceived = sig; + if (signalPipeWrite != -1) { + qCDebug(SHELL) << "signal" << sig << " received, shutting down gracefully"; + write(signalPipeWrite, &sig, sizeof(sig)); + } +} + void installSignalHandler() { -#ifdef SIGHUP - std::signal(SIGHUP, shutdownGracefully); -#endif -#ifdef SIGINT - std::signal(SIGINT, shutdownGracefully); -#endif -#ifdef SIGTERM - std::signal(SIGTERM, shutdownGracefully); -#endif + std::signal(SIGHUP, signalHandler); + std::signal(SIGINT, signalHandler); + std::signal(SIGTERM, signalHandler); + signalNotifier->setEnabled(true); } } @@ -121,6 +137,7 @@ } CorePrivate::CorePrivate(Core *core): + QObject(nullptr), m_aboutData( createAboutData() ), m_core(core), m_cleanedUp(false), m_shuttingDown(false) { } @@ -289,7 +306,27 @@ testController->initialize(); runtimeController->initialize(); - installSignalHandler(); +// A "proper" exit-on-signal approach: +// Open a pipe or an eventfd, then install your signal handler. In that signal +// handler, write anything to the writing end or write uint64_t(1) the eventfd. +// Create a QSocketNotifier on the reading end of the pipe or on the eventfd, +// connect its activation signal to a slot that does what you want. + +#ifdef Q_OS_UNIX + if (!corePrivateInstance) { + int pp[2]; + if (pipe(pp)) { + qCWarning(SHELL) << "Error opening signal handler pipe" << strerror(errno); + } else { + signalPipeRead = pp[0]; + signalPipeWrite = pp[1]; + signalNotifier = new QSocketNotifier(signalPipeRead, QSocketNotifier::Read, this); + connect(signalNotifier, &QSocketNotifier::activated, this, &CorePrivate::shutdownGracefully); + installSignalHandler(); + } + corePrivateInstance = this; + } +#endif qCDebug(SHELL) << "Done initializing controllers"; @@ -328,8 +365,23 @@ workingSetController.clear(); testController.clear(); runtimeController.clear(); + +#ifdef USE_QSOCKETNOTIFIER + if (signalPipeWrite != -1) { + close(signalPipeWrite); + } + if (signalPipeRead != -1) { + close(signalPipeRead); + } +#endif } +void CorePrivate::shutdownGracefully() +{ + ::shutdownGracefully(); +} + + bool Core::initialize(Setup mode, const QString& session) { if (m_self) @@ -604,4 +656,3 @@ } } - Index: kdevplatform/shell/core_p.h =================================================================== --- kdevplatform/shell/core_p.h +++ kdevplatform/shell/core_p.h @@ -47,11 +47,15 @@ class TestController; class RuntimeController; -class KDEVPLATFORMSHELL_EXPORT CorePrivate { +class KDEVPLATFORMSHELL_EXPORT CorePrivate : public QObject { + Q_OBJECT + public: explicit CorePrivate(Core *core); ~CorePrivate(); bool initialize( Core::Setup mode, const QString& session ); + void shutdownGracefully(); + QPointer pluginController; QPointer uiController; QPointer projectController;