diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index 236421558ca..ed41f3dce0d 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -12,7 +12,7 @@ install( add_qtc_executable(qtcreator DEFINES IDE_LIBRARY_BASENAME=\"${IDE_LIBRARY_BASE_PATH}\" - DEPENDS Aggregation ExtensionSystem Qt5::Core Qt5::Widgets Utils QtcSsh shared_qtsingleapplication app_version + DEPENDS Aggregation ExtensionSystem Qt5::Core Qt5::Widgets Utils shared_qtsingleapplication app_version SOURCES main.cpp ../tools/qtcreatorcrashhandler/crashhandlersetup.cpp ../tools/qtcreatorcrashhandler/crashhandlersetup.h diff --git a/src/app/app.pro b/src/app/app.pro index 1d15d390c3d..730427ba897 100644 --- a/src/app/app.pro +++ b/src/app/app.pro @@ -17,7 +17,7 @@ include(../rpath.pri) include(../libs/qt-breakpad/qtbreakpad.pri) -LIBS *= -l$$qtLibraryName(ExtensionSystem) -l$$qtLibraryName(Aggregation) -l$$qtLibraryName(Utils) -l$$qtLibraryName(QtcSsh) +LIBS *= -l$$qtLibraryName(ExtensionSystem) -l$$qtLibraryName(Aggregation) -l$$qtLibraryName(Utils) win32 { # We need the version in two separate formats for the .rc file diff --git a/src/app/app.qbs b/src/app/app.qbs index c97a6457274..42172aa09f6 100644 --- a/src/app/app.qbs +++ b/src/app/app.qbs @@ -46,7 +46,6 @@ QtcProduct { Depends { name: "app_version_header" } Depends { name: "Qt"; submodules: ["widgets", "network"] } Depends { name: "Utils" } - Depends { name: "QtcSsh" } Depends { name: "ExtensionSystem" } files: [ diff --git a/src/app/main.cpp b/src/app/main.cpp index bc0d72aeacb..8ab587a7131 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -32,16 +32,13 @@ #include #include -#include - #include #include #include #include -#include #include -#include #include +#include #include #include @@ -537,10 +534,7 @@ int main(int argc, char **argv) QCoreApplication::setOrganizationName(QLatin1String(Core::Constants::IDE_SETTINGSVARIANT_STR)); QGuiApplication::setApplicationDisplayName(Core::Constants::IDE_DISPLAY_NAME); - Utils::ProcessReaper processReaper; - Utils::LauncherInterface::startLauncher(); - auto cleanup = qScopeGuard([] { Utils::LauncherInterface::stopLauncher(); }); - QSsh::SshConnectionManager sshConnectionManager; + auto cleanup = qScopeGuard([] { Utils::Singleton::deleteAll(); }); const QStringList pluginArguments = app.arguments(); diff --git a/src/libs/ssh/sshconnectionmanager.cpp b/src/libs/ssh/sshconnectionmanager.cpp index 59ddb78f2ac..3ac82a7dabc 100644 --- a/src/libs/ssh/sshconnectionmanager.cpp +++ b/src/libs/ssh/sshconnectionmanager.cpp @@ -53,16 +53,11 @@ bool operator!=(const UnacquiredConnection &c1, const UnacquiredConnection &c2) return !(c1 == c2); } -static class SshConnectionManagerPrivate *s_instance = nullptr; - class SshConnectionManagerPrivate : public QObject { public: SshConnectionManagerPrivate() { - QTC_ASSERT(s_instance == nullptr, return); - s_instance = this; - connect(&m_removalTimer, &QTimer::timeout, this, &SshConnectionManagerPrivate::removeInactiveConnections); m_removalTimer.start(SshSettings::connectionSharingTimeout() * 1000 * 60 / 2); @@ -70,8 +65,6 @@ public: ~SshConnectionManagerPrivate() override { - QTC_ASSERT(s_instance == this, return); - for (const UnacquiredConnection &connection : qAsConst(m_unacquiredConnections)) { disconnect(connection.connection, nullptr, this, nullptr); delete connection.connection; @@ -79,8 +72,6 @@ public: QTC_CHECK(m_acquiredConnections.isEmpty()); QTC_CHECK(m_deprecatedConnections.isEmpty()); - - s_instance = nullptr; } SshConnection *acquireConnection(const SshConnectionParameters &sshParams) @@ -213,6 +204,7 @@ private: SshConnectionManager::SshConnectionManager() : d(new Internal::SshConnectionManagerPrivate()) { + QTC_CHECK(QThread::currentThread() == qApp->thread()); } SshConnectionManager::~SshConnectionManager() @@ -222,20 +214,17 @@ SshConnectionManager::~SshConnectionManager() SshConnection *SshConnectionManager::acquireConnection(const SshConnectionParameters &sshParams) { - QTC_ASSERT(Internal::s_instance, return nullptr); - return Internal::s_instance->acquireConnection(sshParams); + return instance()->d->acquireConnection(sshParams); } void SshConnectionManager::releaseConnection(SshConnection *connection) { - QTC_ASSERT(Internal::s_instance, return); - Internal::s_instance->releaseConnection(connection); + instance()->d->releaseConnection(connection); } void SshConnectionManager::forceNewConnection(const SshConnectionParameters &sshParams) { - QTC_ASSERT(Internal::s_instance, return); - Internal::s_instance->forceNewConnection(sshParams); + instance()->d->forceNewConnection(sshParams); } } // namespace QSsh diff --git a/src/libs/ssh/sshconnectionmanager.h b/src/libs/ssh/sshconnectionmanager.h index 8d8a03f43a5..d46a8d8b89f 100644 --- a/src/libs/ssh/sshconnectionmanager.h +++ b/src/libs/ssh/sshconnectionmanager.h @@ -27,6 +27,9 @@ #include "ssh_global.h" +#include +#include + namespace QSsh { class SshConnection; @@ -35,18 +38,21 @@ class SshConnectionParameters; namespace Internal { class SshConnectionManagerPrivate; } class QSSH_EXPORT SshConnectionManager final + : public Utils::SingletonWithOptionalDependencies { public: - SshConnectionManager(); - ~SshConnectionManager(); - static SshConnection *acquireConnection(const SshConnectionParameters &sshParams); static void releaseConnection(SshConnection *connection); // Make sure the next acquireConnection with the given parameters will return a new connection. static void forceNewConnection(const SshConnectionParameters &sshParams); private: + SshConnectionManager(); + ~SshConnectionManager(); + Internal::SshConnectionManagerPrivate *d; + friend class Utils::SingletonWithOptionalDependencies; }; } // namespace QSsh diff --git a/src/libs/utils/CMakeLists.txt b/src/libs/utils/CMakeLists.txt index 3ef203bc21b..9db6ea5f1e7 100644 --- a/src/libs/utils/CMakeLists.txt +++ b/src/libs/utils/CMakeLists.txt @@ -144,6 +144,7 @@ add_qtc_library(Utils settingsutils.h shellcommand.cpp shellcommand.h shellcommandpage.cpp shellcommandpage.h + singleton.cpp singleton.h sizedarray.h smallstring.h smallstringfwd.h diff --git a/src/libs/utils/launcherinterface.cpp b/src/libs/utils/launcherinterface.cpp index 269e4393d73..a5609fd6e7c 100644 --- a/src/libs/utils/launcherinterface.cpp +++ b/src/libs/utils/launcherinterface.cpp @@ -28,7 +28,6 @@ #include "filepath.h" #include "launcherpackets.h" #include "launchersocket.h" -#include "processreaper.h" #include "qtcassert.h" #include @@ -42,7 +41,6 @@ #endif namespace Utils { - namespace Internal { class LauncherProcess : public QProcess @@ -185,92 +183,73 @@ void LauncherInterfacePrivate::handleProcessStderr() using namespace Utils::Internal; static QMutex s_instanceMutex; -static LauncherInterface *s_instance = nullptr; +static QString s_pathToLauncher; +static std::atomic_bool s_started = false; LauncherInterface::LauncherInterface() : m_private(new LauncherInterfacePrivate()) { m_private->moveToThread(&m_thread); - connect(m_private, &LauncherInterfacePrivate::errorOccurred, - this, &LauncherInterface::errorOccurred); - connect(&m_thread, &QThread::finished, m_private, &QObject::deleteLater); + QObject::connect(&m_thread, &QThread::finished, m_private, &QObject::deleteLater); m_thread.start(); -} + m_thread.moveToThread(qApp->thread()); -LauncherInterface::~LauncherInterface() -{ - m_thread.quit(); - m_thread.wait(); -} - -// Called from main thread -void LauncherInterface::startLauncher(const QString &pathToLauncher) -{ - QMutexLocker locker(&s_instanceMutex); - QTC_ASSERT(s_instance == nullptr, return); - s_instance = new LauncherInterface(); - LauncherInterfacePrivate *p = s_instance->m_private; - p->setPathToLauncher(pathToLauncher); - const FilePath launcherFilePath = FilePath::fromString(p->launcherFilePath()) + m_private->setPathToLauncher(s_pathToLauncher); + const FilePath launcherFilePath = FilePath::fromString(m_private->launcherFilePath()) .cleanPath().withExecutableSuffix(); auto launcherIsNotExecutable = [&launcherFilePath]() { qWarning() << "The Creator's process launcher" << launcherFilePath << "is not executable."; }; QTC_ASSERT(launcherFilePath.isExecutableFile(), launcherIsNotExecutable(); return); + s_started = true; // Call in launcher's thread. - QMetaObject::invokeMethod(p, &LauncherInterfacePrivate::doStart); + QMetaObject::invokeMethod(m_private, &LauncherInterfacePrivate::doStart); } -// Called from main thread -void LauncherInterface::stopLauncher() +LauncherInterface::~LauncherInterface() { QMutexLocker locker(&s_instanceMutex); - QTC_ASSERT(s_instance != nullptr, return); - LauncherInterfacePrivate *p = s_instance->m_private; + LauncherInterfacePrivate *p = instance()->m_private; // Call in launcher's thread. QMetaObject::invokeMethod(p, &LauncherInterfacePrivate::doStop, Qt::BlockingQueuedConnection); - delete s_instance; - s_instance = nullptr; + m_thread.quit(); + m_thread.wait(); +} + +void LauncherInterface::setPathToLauncher(const QString &pathToLauncher) +{ + s_pathToLauncher = pathToLauncher; } bool LauncherInterface::isStarted() { - QMutexLocker locker(&s_instanceMutex); - return s_instance != nullptr; + return s_started; } bool LauncherInterface::isReady() { QMutexLocker locker(&s_instanceMutex); - QTC_ASSERT(s_instance != nullptr, return false); - - return s_instance->m_private->socket()->isReady(); + return instance()->m_private->socket()->isReady(); } void LauncherInterface::sendData(const QByteArray &data) { QMutexLocker locker(&s_instanceMutex); - QTC_ASSERT(s_instance != nullptr, return); - - s_instance->m_private->socket()->sendData(data); + instance()->m_private->socket()->sendData(data); } Utils::Internal::CallerHandle *LauncherInterface::registerHandle(QObject *parent, quintptr token, ProcessMode mode) { QMutexLocker locker(&s_instanceMutex); - QTC_ASSERT(s_instance != nullptr, return nullptr); - - return s_instance->m_private->socket()->registerHandle(parent, token, mode); + return instance()->m_private->socket()->registerHandle(parent, token, mode); } void LauncherInterface::unregisterHandle(quintptr token) { QMutexLocker locker(&s_instanceMutex); - QTC_ASSERT(s_instance != nullptr, return); - - s_instance->m_private->socket()->unregisterHandle(token); + instance()->m_private->socket()->unregisterHandle(token); } } // namespace Utils diff --git a/src/libs/utils/launcherinterface.h b/src/libs/utils/launcherinterface.h index 0df595af855..541501efeec 100644 --- a/src/libs/utils/launcherinterface.h +++ b/src/libs/utils/launcherinterface.h @@ -27,9 +27,10 @@ #include "utils_global.h" +#include "processreaper.h" #include "processutils.h" +#include "singleton.h" -#include #include namespace Utils { @@ -40,15 +41,11 @@ class LauncherInterfacePrivate; class ProcessLauncherImpl; } -class QTCREATOR_UTILS_EXPORT LauncherInterface : public QObject +class QTCREATOR_UTILS_EXPORT LauncherInterface final + : public SingletonWithOptionalDependencies { - Q_OBJECT public: - static void startLauncher(const QString &pathToLauncher = {}); - static void stopLauncher(); - -signals: - void errorOccurred(const QString &error); + static void setPathToLauncher(const QString &pathToLauncher); private: friend class Utils::Internal::CallerHandle; @@ -63,10 +60,11 @@ private: static void unregisterHandle(quintptr token); LauncherInterface(); - ~LauncherInterface() override; + ~LauncherInterface(); QThread m_thread; Internal::LauncherInterfacePrivate *m_private; + friend class SingletonWithOptionalDependencies; }; } // namespace Utils diff --git a/src/libs/utils/processreaper.cpp b/src/libs/utils/processreaper.cpp index b3679c7d957..c6d2a071f50 100644 --- a/src/libs/utils/processreaper.cpp +++ b/src/libs/utils/processreaper.cpp @@ -36,8 +36,6 @@ using namespace Utils; namespace Utils { namespace Internal { -static ProcessReaper *d = nullptr; - class Reaper final : public QObject { public: @@ -57,7 +55,7 @@ private: Reaper::Reaper(QProcess *p, int timeoutMs) : m_process(p) { - d->m_reapers.append(this); + ProcessReaper::instance()->m_reapers.append(this); m_iterationTimer.setInterval(timeoutMs); m_iterationTimer.setSingleShot(true); @@ -68,7 +66,7 @@ Reaper::Reaper(QProcess *p, int timeoutMs) : m_process(p) Reaper::~Reaper() { - d->m_reapers.removeOne(this); + ProcessReaper::instance()->m_reapers.removeOne(this); } int Reaper::timeoutMs() const @@ -112,15 +110,8 @@ void Reaper::nextIteration() } // namespace Internal -ProcessReaper::ProcessReaper() -{ - QTC_ASSERT(Internal::d == nullptr, return); - Internal::d = this; -} - ProcessReaper::~ProcessReaper() { - QTC_ASSERT(Internal::d == this, return); while (!m_reapers.isEmpty()) { int alreadyWaited = 0; QList toDelete; @@ -145,8 +136,6 @@ ProcessReaper::~ProcessReaper() qDeleteAll(toDelete); toDelete.clear(); } - - Internal::d = nullptr; } void ProcessReaper::reap(QProcess *process, int timeoutMs) @@ -175,8 +164,6 @@ void ProcessReaper::reap(QProcess *process, int timeoutMs) return; } - QTC_ASSERT(Internal::d, return); - new Internal::Reaper(process, timeoutMs); } diff --git a/src/libs/utils/processreaper.h b/src/libs/utils/processreaper.h index d26325b6f02..f8485c12e39 100644 --- a/src/libs/utils/processreaper.h +++ b/src/libs/utils/processreaper.h @@ -27,6 +27,8 @@ #include "utils_global.h" +#include "singleton.h" + #include QT_BEGIN_NAMESPACE @@ -38,15 +40,16 @@ namespace Utils { namespace Internal { class Reaper; } class QTCREATOR_UTILS_EXPORT ProcessReaper final + : public SingletonWithOptionalDependencies { public: - ProcessReaper(); - ~ProcessReaper(); - static void reap(QProcess *process, int timeoutMs = 500); private: + ProcessReaper() = default; + ~ProcessReaper(); QList m_reapers; friend class Internal::Reaper; + friend class SingletonWithOptionalDependencies; }; } // namespace Utils diff --git a/src/libs/utils/singleton.cpp b/src/libs/utils/singleton.cpp new file mode 100644 index 00000000000..6bd79ca36f6 --- /dev/null +++ b/src/libs/utils/singleton.cpp @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "qtcassert.h" +#include "singleton.h" + +#include +#include +#include + +#include + +using namespace Utils; + +namespace Utils { + +// The order of elements reflects dependencies, i.e. +// if B requires A then B will follow A on this list +static QList s_singletonList; +static QMutex s_mutex; +static std::unordered_map s_staticDataList; + +Singleton::~Singleton() +{ + QMutexLocker locker(&s_mutex); + s_singletonList.removeAll(this); +} + +void Singleton::addSingleton(Singleton *singleton) +{ + QMutexLocker locker(&s_mutex); + s_singletonList.append(singleton); +} + +SingletonStaticData &Singleton::staticData(std::type_index index) +{ + QMutexLocker locker(&s_mutex); + return s_staticDataList[index]; +} + +// Note: it's caller responsibility to ensure that this function is being called when all other +// threads don't use any singleton. As a good practice: finish all other threads that were using +// singletons before this function is called. +// Some singletons (currently e.g. SshConnectionManager) can work only in main thread, +// so this method should be called from main thread only. +void Singleton::deleteAll() +{ + QTC_ASSERT(QThread::currentThread() == qApp->thread(), return); + QList oldList; + { + QMutexLocker locker(&s_mutex); + oldList = s_singletonList; + s_singletonList = {}; + } + // Keep the reverse order when deleting + while (!oldList.isEmpty()) + delete oldList.takeLast(); +} + +} // namespace Utils diff --git a/src/libs/utils/singleton.h b/src/libs/utils/singleton.h new file mode 100644 index 00000000000..4ba4dfecd03 --- /dev/null +++ b/src/libs/utils/singleton.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "utils_global.h" + +#include +#include + +#include +#include + +namespace Utils { + +class Singleton; + +struct SingletonStaticData +{ + Singleton *m_instance = nullptr; + QMutex m_mutex; +}; + +class QTCREATOR_UTILS_EXPORT Singleton +{ + Q_DISABLE_COPY_MOVE(Singleton) +public: + static void deleteAll(); + +private: + template + friend class SingletonWithOptionalDependencies; + + Singleton() = default; + virtual ~Singleton(); + static void addSingleton(Singleton *singleton); + static SingletonStaticData &staticData(std::type_index index); +}; + +template +class SingletonWithOptionalDependencies : public Singleton +{ +public: + Q_DISABLE_COPY_MOVE(SingletonWithOptionalDependencies) + static SingletonSubClass *instance() + { + SingletonStaticData &data = staticData(); + QMutexLocker locker(&data.m_mutex); + if (data.m_instance == nullptr) { + // instantiate all dependencies first + if constexpr (sizeof...(Dependencies)) + instantiateDependencies(); + data.m_instance = new SingletonSubClass; + // put instance into static list of registered instances + addSingleton(data.m_instance); + } + return static_cast(data.m_instance); + } + +protected: + SingletonWithOptionalDependencies() = default; + ~SingletonWithOptionalDependencies() override + { + SingletonStaticData &data = staticData(); + QMutexLocker locker(&data.m_mutex); + if (data.m_instance == this) + data.m_instance = nullptr; + } + +private: + template static void instantiateDependencies() + { + static_assert ((... && std::is_base_of_v), + "All Dependencies must derive from SingletonWithOptionalDependencies class."); + (..., Dependency::instance()); + } + static SingletonStaticData &staticData() + { + static SingletonStaticData &data = Singleton::staticData(std::type_index(typeid(SingletonSubClass))); + return data; + } +}; + +} // namespace Utils diff --git a/src/libs/utils/utils-lib.pri b/src/libs/utils/utils-lib.pri index 7ceac359e8d..ddaae4bb697 100644 --- a/src/libs/utils/utils-lib.pri +++ b/src/libs/utils/utils-lib.pri @@ -143,6 +143,7 @@ SOURCES += \ $$PWD/link.cpp \ $$PWD/linecolumn.cpp \ $$PWD/multitextcursor.cpp \ + $$PWD/singleton.cpp HEADERS += \ $$PWD/environmentfwd.h \ @@ -307,8 +308,9 @@ HEADERS += \ $$PWD/launcherinterface.h \ $$PWD/launcherpackets.h \ $$PWD/launchersocket.h \ - $$PWD/qtcsettings.h + $$PWD/qtcsettings.h \ $$PWD/multitextcursor.h \ + $$PWD/singleton.h FORMS += $$PWD/filewizardpage.ui \ $$PWD/projectintropage.ui \ diff --git a/src/libs/utils/utils.qbs b/src/libs/utils/utils.qbs index e6b1d0621dd..77f80dd81b8 100644 --- a/src/libs/utils/utils.qbs +++ b/src/libs/utils/utils.qbs @@ -264,6 +264,8 @@ Project { "shellcommand.h", "shellcommandpage.cpp", "shellcommandpage.h", + "singleton.cpp", + "singleton.h", "sizedarray.h", "smallstring.h", "smallstringiterator.h", diff --git a/src/plugins/mesonprojectmanager/tests/testmesoninfoparser.cpp b/src/plugins/mesonprojectmanager/tests/testmesoninfoparser.cpp index cbbf9042daf..e25fec5456e 100644 --- a/src/plugins/mesonprojectmanager/tests/testmesoninfoparser.cpp +++ b/src/plugins/mesonprojectmanager/tests/testmesoninfoparser.cpp @@ -27,7 +27,7 @@ #include "mesoninfoparser/mesoninfoparser.h" #include -#include +#include #include #include @@ -79,9 +79,8 @@ class AMesonInfoParser : public QObject private slots: void initTestCase() { - Utils::LauncherInterface::startLauncher( - QCoreApplication::instance()->applicationDirPath() + '/' - + QLatin1String(TEST_RELATIVE_LIBEXEC_PATH)); + Utils::LauncherInterface::setPathToLauncher(qApp->applicationDirPath() + '/' + + QLatin1String(TEST_RELATIVE_LIBEXEC_PATH)); } void shouldListTargets_data() @@ -121,11 +120,10 @@ private slots: void cleanupTestCase() { - Utils::LauncherInterface::stopLauncher(); + Utils::Singleton::deleteAll(); } private: - Utils::ProcessReaper processReaper; }; QTEST_MAIN(AMesonInfoParser) diff --git a/src/plugins/mesonprojectmanager/tests/testmesonwrapper.cpp b/src/plugins/mesonprojectmanager/tests/testmesonwrapper.cpp index c257434151c..7db2c49480d 100644 --- a/src/plugins/mesonprojectmanager/tests/testmesonwrapper.cpp +++ b/src/plugins/mesonprojectmanager/tests/testmesonwrapper.cpp @@ -26,7 +26,7 @@ #include "exewrappers/mesonwrapper.h" #include -#include +#include #include #include @@ -50,9 +50,8 @@ class AMesonWrapper : public QObject private slots: void initTestCase() { - Utils::LauncherInterface::startLauncher( - QCoreApplication::instance()->applicationDirPath() + '/' - + QLatin1String(TEST_RELATIVE_LIBEXEC_PATH)); + Utils::LauncherInterface::setPathToLauncher(qApp->applicationDirPath() + '/' + + QLatin1String(TEST_RELATIVE_LIBEXEC_PATH)); } void shouldFindMesonFromPATH() @@ -115,11 +114,10 @@ private slots: void cleanupTestCase() { - Utils::LauncherInterface::stopLauncher(); + Utils::Singleton::deleteAll(); } private: - Utils::ProcessReaper processReaper; }; QTEST_MAIN(AMesonWrapper) diff --git a/src/tools/processlauncher/CMakeLists.txt b/src/tools/processlauncher/CMakeLists.txt index 1cd0e85cd42..e0064c62b34 100644 --- a/src/tools/processlauncher/CMakeLists.txt +++ b/src/tools/processlauncher/CMakeLists.txt @@ -18,4 +18,6 @@ add_qtc_executable(qtcreator_processlauncher ${UTILSDIR}/processutils.h ${UTILSDIR}/qtcassert.cpp ${UTILSDIR}/qtcassert.h + ${UTILSDIR}/singleton.cpp + ${UTILSDIR}/singleton.h ) diff --git a/src/tools/processlauncher/processlauncher-main.cpp b/src/tools/processlauncher/processlauncher-main.cpp index c651a276cc5..7686925521d 100644 --- a/src/tools/processlauncher/processlauncher-main.cpp +++ b/src/tools/processlauncher/processlauncher-main.cpp @@ -25,9 +25,10 @@ #include "launcherlogging.h" #include "launchersockethandler.h" -#include "processreaper.h" +#include "singleton.h" #include +#include #include #ifdef Q_OS_WIN @@ -52,7 +53,8 @@ int main(int argc, char *argv[]) return 1; } - Utils::ProcessReaper processReaper; + auto cleanup = qScopeGuard([] { Utils::Singleton::deleteAll(); }); + Utils::Internal::LauncherSocketHandler launcher(app.arguments().constLast()); QTimer::singleShot(0, &launcher, &Utils::Internal::LauncherSocketHandler::start); return app.exec(); diff --git a/src/tools/processlauncher/processlauncher.pro b/src/tools/processlauncher/processlauncher.pro index 260e701e3c2..737cb366cfa 100644 --- a/src/tools/processlauncher/processlauncher.pro +++ b/src/tools/processlauncher/processlauncher.pro @@ -7,6 +7,8 @@ QT = core network UTILS_DIR = $$PWD/../../libs/utils +DEFINES *= QTCREATOR_UTILS_STATIC_LIB + INCLUDEPATH += $$UTILS_DIR HEADERS += \ @@ -15,7 +17,8 @@ HEADERS += \ $$UTILS_DIR/launcherpackets.h \ $$UTILS_DIR/processreaper.h \ $$UTILS_DIR/processutils.h \ - $$UTILS_DIR/qtcassert.h + $$UTILS_DIR/qtcassert.h \ + $$UTILS_DIR/singleton.h SOURCES += \ launcherlogging.cpp \ @@ -24,4 +27,5 @@ SOURCES += \ $$UTILS_DIR/launcherpackets.cpp \ $$UTILS_DIR/processreaper.cpp \ $$UTILS_DIR/processutils.cpp \ - $$UTILS_DIR/qtcassert.cpp + $$UTILS_DIR/qtcassert.cpp \ + $$UTILS_DIR/singleton.cpp diff --git a/src/tools/processlauncher/processlauncher.qbs b/src/tools/processlauncher/processlauncher.qbs index 1050d0d592b..b2fd708169c 100644 --- a/src/tools/processlauncher/processlauncher.qbs +++ b/src/tools/processlauncher/processlauncher.qbs @@ -30,6 +30,8 @@ QtcTool { "processutils.h", "qtcassert.cpp", "qtcassert.h", + "singleton.cpp", + "singleton.h", ] } } diff --git a/tests/auto/ssh/tst_ssh.cpp b/tests/auto/ssh/tst_ssh.cpp index 597d035e509..0990f5727f7 100644 --- a/tests/auto/ssh/tst_ssh.cpp +++ b/tests/auto/ssh/tst_ssh.cpp @@ -26,15 +26,14 @@ #include #include #include -#include #include #include #include #include #include -#include #include +#include #include #include @@ -134,17 +133,12 @@ private slots: void cleanupTestCase(); private: bool waitForConnection(SshConnection &connection); - - Utils::ProcessReaper *processReaper = nullptr; - SshConnectionManager *sshConnectionManager = nullptr; }; void tst_Ssh::initTestCase() { - processReaper = new Utils::ProcessReaper(); - Utils::LauncherInterface::startLauncher(qApp->applicationDirPath() + '/' - + QLatin1String(TEST_RELATIVE_LIBEXEC_PATH)); - sshConnectionManager = new SshConnectionManager(); + Utils::LauncherInterface::setPathToLauncher(qApp->applicationDirPath() + '/' + + QLatin1String(TEST_RELATIVE_LIBEXEC_PATH)); Utils::TemporaryDirectory::setMasterTemporaryDirectory(QDir::tempPath() + "/qtc-ssh-autotest-XXXXXX"); } @@ -647,9 +641,7 @@ void tst_Ssh::sftp() void tst_Ssh::cleanupTestCase() { - delete sshConnectionManager; - Utils::LauncherInterface::stopLauncher(); - delete processReaper; + Utils::Singleton::deleteAll(); } bool tst_Ssh::waitForConnection(SshConnection &connection) diff --git a/tests/auto/utils/qtcprocess/tst_qtcprocess.cpp b/tests/auto/utils/qtcprocess/tst_qtcprocess.cpp index a247e4f9638..2ad9eba89d1 100644 --- a/tests/auto/utils/qtcprocess/tst_qtcprocess.cpp +++ b/tests/auto/utils/qtcprocess/tst_qtcprocess.cpp @@ -27,8 +27,8 @@ #include #include #include -#include #include +#include #include #include @@ -213,7 +213,6 @@ private slots: private: void iteratorEditsHelper(OsType osType); - Utils::ProcessReaper processReaper; Environment envWindows; Environment envLinux; @@ -225,8 +224,8 @@ private: void tst_QtcProcess::initTestCase() { - Utils::LauncherInterface::startLauncher(qApp->applicationDirPath() + '/' - + QLatin1String(TEST_RELATIVE_LIBEXEC_PATH)); + Utils::LauncherInterface::setPathToLauncher(qApp->applicationDirPath() + '/' + + QLatin1String(TEST_RELATIVE_LIBEXEC_PATH)); if (qEnvironmentVariableIsSet(kExitCodeSubProcessCode)) exitCodeSubProcessMain(); if (qEnvironmentVariableIsSet(kRunBlockingStdOutSubProcessWithEndl)) @@ -285,7 +284,7 @@ void tst_QtcProcess::initTestCase() void tst_QtcProcess::cleanupTestCase() { - Utils::LauncherInterface::stopLauncher(); + Utils::Singleton::deleteAll(); } Q_DECLARE_METATYPE(ProcessArgs::SplitError) diff --git a/tests/unit/unittest/unittests-main.cpp b/tests/unit/unittest/unittests-main.cpp index 4d48f2c1dcc..a308b2a6a76 100644 --- a/tests/unit/unittest/unittests-main.cpp +++ b/tests/unit/unittest/unittests-main.cpp @@ -30,7 +30,7 @@ #include #include -#include +#include #include #include @@ -61,10 +61,8 @@ int main(int argc, char *argv[]) Sqlite::Database::activateLogging(); QGuiApplication application(argc, argv); - Utils::ProcessReaper processReaper; - Utils::LauncherInterface::startLauncher(qApp->applicationDirPath() + '/' - + QLatin1String(TEST_RELATIVE_LIBEXEC_PATH)); - auto cleanup = qScopeGuard([] { Utils::LauncherInterface::stopLauncher(); }); + Utils::LauncherInterface::setPathToLauncher(qApp->applicationDirPath() + '/' + + QLatin1String(TEST_RELATIVE_LIBEXEC_PATH)); testing::InitGoogleTest(&argc, argv); #ifdef WITH_BENCHMARKS benchmark::Initialize(&argc, argv); @@ -75,6 +73,7 @@ int main(int argc, char *argv[]) int testsHaveErrors = RUN_ALL_TESTS(); + Utils::Singleton::deleteAll(); #ifdef WITH_BENCHMARKS if (testsHaveErrors == 0 && application.arguments().contains(QStringLiteral("--with-benchmarks"))) benchmark::RunSpecifiedBenchmarks();