X-Git-Url: https://git.quassel-irc.org/?a=blobdiff_plain;f=src%2Fcommon%2Fquassel.cpp;h=af4c69b607938f67e00c1154bb4b7fc4a35b6883;hb=4e43a17088e8ff76c220bd8b4ebf37d9dbb4863a;hp=5ceddb101eef6c8d48e9bf23bb8430fa19d5d753;hpb=37110ceaa070167b4f40ed449ac9ea130503a792;p=quassel.git diff --git a/src/common/quassel.cpp b/src/common/quassel.cpp index 5ceddb10..af4c69b6 100644 --- a/src/common/quassel.cpp +++ b/src/common/quassel.cpp @@ -23,13 +23,6 @@ #include #include -#include -#if !defined Q_OS_WIN && !defined Q_OS_MAC -# include -# include -# include -#endif - #include #include #include @@ -52,63 +45,30 @@ #include "syncableobject.h" #include "types.h" -#include "../../version.h" - -Quassel *Quassel::instance() -{ - static Quassel instance; - return &instance; -} +#ifndef Q_OS_WIN +# include "posixsignalwatcher.h" +#else +# include "windowssignalwatcher.h" +#endif +#include "../../version.h" Quassel::Quassel() - : _logger{new Logger{this}} + : Singleton{this} + , _logger{new Logger{this}} { } -bool Quassel::init() +void Quassel::init(RunMode runMode) { - if (instance()->_initialized) - return true; // allow multiple invocations because of MonolithicApplication + _runMode = runMode; - // Setup signal handling - // TODO: Don't use unsafe methods, see handleSignal() - - // We catch SIGTERM and SIGINT (caused by Ctrl+C) to graceful shutdown Quassel. - signal(SIGTERM, handleSignal); - signal(SIGINT, handleSignal); -#ifndef Q_OS_WIN - // SIGHUP is used to reload configuration (i.e. SSL certificates) - // Windows does not support SIGHUP - signal(SIGHUP, handleSignal); -#endif - - if (instance()->_handleCrashes) { - // we have crashhandler for win32 and unix (based on execinfo). -#if defined(Q_OS_WIN) || defined(HAVE_EXECINFO) -# ifndef Q_OS_WIN - // we only handle crashes ourselves if coredumps are disabled - struct rlimit *limit = (rlimit *)malloc(sizeof(struct rlimit)); - int rc = getrlimit(RLIMIT_CORE, limit); - - if (rc == -1 || !((long)limit->rlim_cur > 0 || limit->rlim_cur == RLIM_INFINITY)) { -# endif /* Q_OS_WIN */ - signal(SIGABRT, handleSignal); - signal(SIGSEGV, handleSignal); -# ifndef Q_OS_WIN - signal(SIGBUS, handleSignal); - } - free(limit); -# endif /* Q_OS_WIN */ -#endif /* Q_OS_WIN || HAVE_EXECINFO */ - } - - instance()->_initialized = true; qsrand(QTime(0, 0, 0).secsTo(QTime::currentTime())); - instance()->setupEnvironment(); - instance()->registerMetaTypes(); + setupSignalHandling(); + setupEnvironment(); + registerMetaTypes(); Network::setDefaultCodecForServer("UTF-8"); Network::setDefaultCodecForEncoding("UTF-8"); @@ -116,21 +76,16 @@ bool Quassel::init() if (isOptionSet("help")) { instance()->_cliParser->usage(); - return false; + return; } if (isOptionSet("version")) { std::cout << qPrintable("Quassel IRC: " + Quassel::buildInfo().plainVersionString) << std::endl; - return false; + return; } // Don't keep a debug log on the core - return instance()->logger()->setup(runMode() != RunMode::CoreOnly); -} - - -void Quassel::destroy() -{ + logger()->setup(runMode != RunMode::CoreOnly); } @@ -147,12 +102,18 @@ void Quassel::registerQuitHandler(QuitHandler handler) void Quassel::quit() { - if (_quitHandlers.empty()) { - QCoreApplication::quit(); - } - else { - for (auto &&handler : _quitHandlers) { - handler(); + // Protect against multiple invocations (e.g. triggered by MainWin::closeEvent()) + if (!_quitting) { + _quitting = true; + quInfo() << "Quitting..."; + if (_quitHandlers.empty()) { + QCoreApplication::quit(); + } + else { + // Note: We expect one of the registered handlers to call QCoreApplication::quit() + for (auto &&handler : _quitHandlers) { + handler(); + } } } } @@ -328,44 +289,41 @@ const Quassel::BuildInfo &Quassel::buildInfo() } -//! Signal handler for graceful shutdown. -//! @todo: Ensure this doesn't use unsafe methods (it does currently) -//! cf. QSocketNotifier, UnixSignalWatcher -void Quassel::handleSignal(int sig) +void Quassel::setupSignalHandling() { - switch (sig) { - case SIGTERM: - case SIGINT: - qWarning("%s", qPrintable(QString("Caught signal %1 - exiting.").arg(sig))); - instance()->quit(); - break; -#ifndef Q_OS_WIN -// Windows does not support SIGHUP - case SIGHUP: - // Most applications use this as the 'configuration reload' command, e.g. nginx uses it for - // graceful reloading of processes. - quInfo() << "Caught signal" << SIGHUP << "- reloading configuration"; - if (instance()->reloadConfig()) { - quInfo() << "Successfully reloaded configuration"; - } - break; -#endif - case SIGABRT: - case SIGSEGV: #ifndef Q_OS_WIN - case SIGBUS: + _signalWatcher = new PosixSignalWatcher(this); +#else + _signalWatcher = new WindowsSignalWatcher(this); #endif - instance()->logBacktrace(instance()->coreDumpFileName()); - exit(EXIT_FAILURE); - default: - ; - } + connect(_signalWatcher, SIGNAL(handleSignal(AbstractSignalWatcher::Action)), this, SLOT(handleSignal(AbstractSignalWatcher::Action))); } -void Quassel::disableCrashHandler() +void Quassel::handleSignal(AbstractSignalWatcher::Action action) { - instance()->_handleCrashes = false; + switch (action) { + case AbstractSignalWatcher::Action::Reload: + // Most applications use this as the 'configuration reload' command, e.g. nginx uses it for graceful reloading of processes. + if (!_reloadHandlers.empty()) { + quInfo() << "Reloading configuration"; + if (reloadConfig()) { + quInfo() << "Successfully reloaded configuration"; + } + } + break; + case AbstractSignalWatcher::Action::Terminate: + if (!_quitting) { + quit(); + } + else { + quInfo() << "Already shutting down, ignoring signal"; + } + break; + case AbstractSignalWatcher::Action::HandleCrash: + logBacktrace(instance()->coreDumpFileName()); + exit(EXIT_FAILURE); + } } @@ -374,12 +332,6 @@ Quassel::RunMode Quassel::runMode() { } -void Quassel::setRunMode(RunMode runMode) -{ - instance()->_runMode = runMode; -} - - void Quassel::setCliParser(std::shared_ptr parser) { instance()->_cliParser = std::move(parser); @@ -598,7 +550,7 @@ void Quassel::loadTranslation(const QLocale &locale) quasselTranslator->setObjectName("QuasselTr"); qApp->installTranslator(quasselTranslator); -#if QT_VERSION >= 0x040800 && !defined Q_OS_MAC +#ifndef Q_OS_MAC bool success = qtTranslator->load(locale, QString("qt_"), translationDirPath()); if (!success) qtTranslator->load(locale, QString("qt_"), QLibraryInfo::location(QLibraryInfo::TranslationsPath));