forked from qt-creator/qt-creator
Move ProcessReaper into lib/utils
Reuse ProcessReaper inside process launcher. Automatically reap all internal QProcesses of QtcProcess (either direct child of QtcProcess in QProcessImpl or indirectly inside process launcher). Make ProcessReaper work again on QProcess instead of on QtcProcess, so it may still be reused for non-QtcProcesses. Change-Id: I950cac5cec28f17ae97fe474d6a4e48c01d6aaa2 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
@@ -38,6 +38,7 @@
|
||||
#include <utils/hostosinfo.h>
|
||||
#include <utils/launcherinterface.h>
|
||||
#include <utils/optional.h>
|
||||
#include <utils/processreaper.h>
|
||||
#include <utils/qtcsettings.h>
|
||||
#include <utils/temporarydirectory.h>
|
||||
|
||||
@@ -534,6 +535,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(); });
|
||||
|
||||
|
@@ -121,6 +121,7 @@ add_qtc_library(Utils
|
||||
portlist.cpp portlist.h
|
||||
predicates.h
|
||||
processhandle.cpp processhandle.h
|
||||
processreaper.cpp processreaper.h
|
||||
processutils.cpp processutils.h
|
||||
progressindicator.cpp progressindicator.h
|
||||
projectintropage.cpp projectintropage.h projectintropage.ui
|
||||
|
@@ -28,6 +28,7 @@
|
||||
#include "filepath.h"
|
||||
#include "launcherpackets.h"
|
||||
#include "launchersocket.h"
|
||||
#include "processreaper.h"
|
||||
#include "qtcassert.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
@@ -143,7 +144,7 @@ void LauncherInterfacePrivate::doStop()
|
||||
m_process->disconnect();
|
||||
m_socket->shutdown();
|
||||
m_process->waitForFinished(3000);
|
||||
m_process->deleteLater();
|
||||
ProcessReaper::reap(m_process);
|
||||
m_process = nullptr;
|
||||
}
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Copyright (C) 2021 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
@@ -23,29 +23,26 @@
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "reaper.h"
|
||||
#include "reaper_p.h"
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/qtcprocess.h>
|
||||
#include "processreaper.h"
|
||||
#include "qtcassert.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QProcess>
|
||||
#include <QThread>
|
||||
#include <QTimer>
|
||||
|
||||
using namespace Utils;
|
||||
|
||||
namespace Core {
|
||||
namespace Utils {
|
||||
namespace Internal {
|
||||
|
||||
static ProcessReapers *d = nullptr;
|
||||
static ProcessReaper *d = nullptr;
|
||||
|
||||
class ProcessReaper final : public QObject
|
||||
class Reaper final : public QObject
|
||||
{
|
||||
public:
|
||||
ProcessReaper(QtcProcess *p, int timeoutMs);
|
||||
~ProcessReaper() final;
|
||||
Reaper(QProcess *p, int timeoutMs);
|
||||
~Reaper() final;
|
||||
|
||||
int timeoutMs() const;
|
||||
bool isFinished() const;
|
||||
@@ -53,28 +50,28 @@ public:
|
||||
|
||||
private:
|
||||
mutable QTimer m_iterationTimer;
|
||||
QtcProcess *m_process;
|
||||
QProcess *m_process = nullptr;
|
||||
int m_emergencyCounter = 0;
|
||||
QProcess::ProcessState m_lastState = QProcess::NotRunning;
|
||||
};
|
||||
|
||||
ProcessReaper::ProcessReaper(QtcProcess *p, int timeoutMs) : m_process(p)
|
||||
Reaper::Reaper(QProcess *p, int timeoutMs) : m_process(p)
|
||||
{
|
||||
d->m_reapers.append(this);
|
||||
|
||||
m_iterationTimer.setInterval(timeoutMs);
|
||||
m_iterationTimer.setSingleShot(true);
|
||||
connect(&m_iterationTimer, &QTimer::timeout, this, &ProcessReaper::nextIteration);
|
||||
connect(&m_iterationTimer, &QTimer::timeout, this, &Reaper::nextIteration);
|
||||
|
||||
QMetaObject::invokeMethod(this, &ProcessReaper::nextIteration, Qt::QueuedConnection);
|
||||
QMetaObject::invokeMethod(this, &Reaper::nextIteration, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
ProcessReaper::~ProcessReaper()
|
||||
Reaper::~Reaper()
|
||||
{
|
||||
d->m_reapers.removeOne(this);
|
||||
}
|
||||
|
||||
int ProcessReaper::timeoutMs() const
|
||||
int Reaper::timeoutMs() const
|
||||
{
|
||||
const int remaining = m_iterationTimer.remainingTime();
|
||||
if (remaining < 0)
|
||||
@@ -83,12 +80,12 @@ int ProcessReaper::timeoutMs() const
|
||||
return remaining;
|
||||
}
|
||||
|
||||
bool ProcessReaper::isFinished() const
|
||||
bool Reaper::isFinished() const
|
||||
{
|
||||
return !m_process;
|
||||
}
|
||||
|
||||
void ProcessReaper::nextIteration()
|
||||
void Reaper::nextIteration()
|
||||
{
|
||||
QProcess::ProcessState state = m_process ? m_process->state() : QProcess::NotRunning;
|
||||
if (state == QProcess::NotRunning || m_emergencyCounter > 5) {
|
||||
@@ -113,19 +110,23 @@ void ProcessReaper::nextIteration()
|
||||
++m_emergencyCounter;
|
||||
}
|
||||
|
||||
ProcessReapers::ProcessReapers()
|
||||
} // namespace Internal
|
||||
|
||||
ProcessReaper::ProcessReaper()
|
||||
{
|
||||
d = this;
|
||||
QTC_ASSERT(Internal::d == nullptr, return);
|
||||
Internal::d = this;
|
||||
}
|
||||
|
||||
ProcessReapers::~ProcessReapers()
|
||||
ProcessReaper::~ProcessReaper()
|
||||
{
|
||||
QTC_ASSERT(Internal::d == this, return);
|
||||
while (!m_reapers.isEmpty()) {
|
||||
int alreadyWaited = 0;
|
||||
QList<ProcessReaper *> toDelete;
|
||||
QList<Internal::Reaper *> toDelete;
|
||||
|
||||
// push reapers along:
|
||||
foreach (ProcessReaper *pr, m_reapers) {
|
||||
for (Internal::Reaper *pr : qAsConst(m_reapers)) {
|
||||
const int timeoutMs = pr->timeoutMs();
|
||||
if (alreadyWaited < timeoutMs) {
|
||||
const unsigned long toSleep = static_cast<unsigned long>(timeoutMs - alreadyWaited);
|
||||
@@ -145,25 +146,30 @@ ProcessReapers::~ProcessReapers()
|
||||
toDelete.clear();
|
||||
}
|
||||
|
||||
d = nullptr;
|
||||
Internal::d = nullptr;
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
namespace Reaper {
|
||||
|
||||
void reap(QtcProcess *process, int timeoutMs)
|
||||
void ProcessReaper::reap(QProcess *process, int timeoutMs)
|
||||
{
|
||||
if (!process)
|
||||
return;
|
||||
|
||||
QTC_ASSERT(QThread::currentThread() == process->thread(), return);
|
||||
|
||||
process->disconnect();
|
||||
process->setParent(nullptr);
|
||||
if (process->state() == QProcess::NotRunning) {
|
||||
process->deleteLater();
|
||||
return;
|
||||
} else {
|
||||
process->kill();
|
||||
}
|
||||
|
||||
// Neither can move object with a parent into a different thread
|
||||
// nor reaping the process with a parent makes any sense.
|
||||
process->setParent(nullptr);
|
||||
if (process->thread() != qApp->thread()) {
|
||||
process->moveToThread(qApp->thread());
|
||||
if (process->thread() != QCoreApplication::instance()->thread()) {
|
||||
process->moveToThread(QCoreApplication::instance()->thread());
|
||||
QMetaObject::invokeMethod(process, [process, timeoutMs] {
|
||||
reap(process, timeoutMs);
|
||||
}); // will be queued
|
||||
@@ -172,9 +178,8 @@ void reap(QtcProcess *process, int timeoutMs)
|
||||
|
||||
QTC_ASSERT(Internal::d, return);
|
||||
|
||||
new Internal::ProcessReaper(process, timeoutMs);
|
||||
new Internal::Reaper(process, timeoutMs);
|
||||
}
|
||||
|
||||
} // namespace Reaper
|
||||
} // namespace Core
|
||||
} // namespace Utils
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Copyright (C) 2021 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
@@ -25,25 +25,28 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "utils_global.h"
|
||||
|
||||
#include <QList>
|
||||
|
||||
namespace Core {
|
||||
namespace Internal {
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QProcess;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class CorePlugin;
|
||||
class ProcessReaper;
|
||||
namespace Utils {
|
||||
|
||||
class ProcessReapers final
|
||||
namespace Internal { class Reaper; }
|
||||
|
||||
class QTCREATOR_UTILS_EXPORT ProcessReaper final
|
||||
{
|
||||
public:
|
||||
ProcessReaper();
|
||||
~ProcessReaper();
|
||||
|
||||
static void reap(QProcess *process, int timeoutMs = 500);
|
||||
private:
|
||||
~ProcessReapers();
|
||||
ProcessReapers();
|
||||
|
||||
QList<ProcessReaper *> m_reapers;
|
||||
|
||||
friend class CorePlugin;
|
||||
friend class ProcessReaper;
|
||||
QList<Internal::Reaper *> m_reapers;
|
||||
friend class Internal::Reaper;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace Core
|
||||
} // namespace Utils
|
@@ -31,6 +31,7 @@
|
||||
#include "launcherinterface.h"
|
||||
#include "launcherpackets.h"
|
||||
#include "launchersocket.h"
|
||||
#include "processreaper.h"
|
||||
#include "qtcassert.h"
|
||||
#include "stringutils.h"
|
||||
|
||||
@@ -278,86 +279,90 @@ class QProcessImpl : public ProcessInterface
|
||||
public:
|
||||
QProcessImpl(QObject *parent, ProcessMode processMode)
|
||||
: ProcessInterface(parent, processMode)
|
||||
, m_process(parent)
|
||||
, m_process(new ProcessHelper(parent))
|
||||
{
|
||||
connect(&m_process, &QProcess::started,
|
||||
connect(m_process, &QProcess::started,
|
||||
this, &QProcessImpl::handleStarted);
|
||||
connect(&m_process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
|
||||
connect(m_process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
|
||||
this, &ProcessInterface::finished);
|
||||
connect(&m_process, &QProcess::errorOccurred,
|
||||
connect(m_process, &QProcess::errorOccurred,
|
||||
this, &ProcessInterface::errorOccurred);
|
||||
connect(&m_process, &QProcess::readyReadStandardOutput,
|
||||
connect(m_process, &QProcess::readyReadStandardOutput,
|
||||
this, &ProcessInterface::readyReadStandardOutput);
|
||||
connect(&m_process, &QProcess::readyReadStandardError,
|
||||
connect(m_process, &QProcess::readyReadStandardError,
|
||||
this, &ProcessInterface::readyReadStandardError);
|
||||
}
|
||||
~QProcessImpl() override
|
||||
{
|
||||
ProcessReaper::reap(m_process);
|
||||
}
|
||||
|
||||
QByteArray readAllStandardOutput() override { return m_process.readAllStandardOutput(); }
|
||||
QByteArray readAllStandardError() override { return m_process.readAllStandardError(); }
|
||||
QByteArray readAllStandardOutput() override { return m_process->readAllStandardOutput(); }
|
||||
QByteArray readAllStandardError() override { return m_process->readAllStandardError(); }
|
||||
|
||||
void setProcessEnvironment(const QProcessEnvironment &environment) override
|
||||
{ m_process.setProcessEnvironment(environment); }
|
||||
{ m_process->setProcessEnvironment(environment); }
|
||||
void setWorkingDirectory(const QString &dir) override
|
||||
{ m_process.setWorkingDirectory(dir); }
|
||||
{ m_process->setWorkingDirectory(dir); }
|
||||
void start(const QString &program, const QStringList &arguments, const QByteArray &writeData) override
|
||||
{
|
||||
m_processStartHandler.setProcessMode(processMode());
|
||||
m_processStartHandler.setWriteData(writeData);
|
||||
if (isBelowNormalPriority())
|
||||
m_processStartHandler.setBelowNormalPriority(&m_process);
|
||||
m_processStartHandler.setNativeArguments(&m_process, nativeArguments());
|
||||
m_processStartHandler.setBelowNormalPriority(m_process);
|
||||
m_processStartHandler.setNativeArguments(m_process, nativeArguments());
|
||||
if (isLowPriority())
|
||||
m_process.setLowPriority();
|
||||
m_process->setLowPriority();
|
||||
if (isUnixTerminalDisabled())
|
||||
m_process.setUnixTerminalDisabled();
|
||||
m_process.start(program, arguments, m_processStartHandler.openMode());
|
||||
m_processStartHandler.handleProcessStart(&m_process);
|
||||
m_process->setUnixTerminalDisabled();
|
||||
m_process->start(program, arguments, m_processStartHandler.openMode());
|
||||
m_processStartHandler.handleProcessStart(m_process);
|
||||
}
|
||||
void terminate() override
|
||||
{ m_process.terminate(); }
|
||||
{ m_process->terminate(); }
|
||||
void kill() override
|
||||
{ m_process.kill(); }
|
||||
{ m_process->kill(); }
|
||||
void close() override
|
||||
{ m_process.close(); }
|
||||
{ m_process->close(); }
|
||||
qint64 write(const QByteArray &data) override
|
||||
{ return m_process.write(data); }
|
||||
{ return m_process->write(data); }
|
||||
|
||||
void setStandardInputFile(const QString &fileName) override
|
||||
{ m_process.setStandardInputFile(fileName); }
|
||||
{ m_process->setStandardInputFile(fileName); }
|
||||
void setProcessChannelMode(QProcess::ProcessChannelMode mode) override
|
||||
{ m_process.setProcessChannelMode(mode); }
|
||||
{ m_process->setProcessChannelMode(mode); }
|
||||
|
||||
QString program() const override
|
||||
{ return m_process.program(); }
|
||||
{ return m_process->program(); }
|
||||
QProcess::ProcessError error() const override
|
||||
{ return m_process.error(); }
|
||||
{ return m_process->error(); }
|
||||
QProcess::ProcessState state() const override
|
||||
{ return m_process.state(); }
|
||||
{ return m_process->state(); }
|
||||
qint64 processId() const override
|
||||
{ return m_process.processId(); }
|
||||
{ return m_process->processId(); }
|
||||
int exitCode() const override
|
||||
{ return m_process.exitCode(); }
|
||||
{ return m_process->exitCode(); }
|
||||
QProcess::ExitStatus exitStatus() const override
|
||||
{ return m_process.exitStatus(); }
|
||||
{ return m_process->exitStatus(); }
|
||||
QString errorString() const override
|
||||
{ return m_process.errorString(); }
|
||||
{ return m_process->errorString(); }
|
||||
void setErrorString(const QString &str) override
|
||||
{ m_process.setErrorString(str); }
|
||||
{ m_process->setErrorString(str); }
|
||||
|
||||
bool waitForStarted(int msecs) override
|
||||
{ return m_process.waitForStarted(msecs); }
|
||||
{ return m_process->waitForStarted(msecs); }
|
||||
bool waitForReadyRead(int msecs) override
|
||||
{ return m_process.waitForReadyRead(msecs); }
|
||||
{ return m_process->waitForReadyRead(msecs); }
|
||||
bool waitForFinished(int msecs) override
|
||||
{ return m_process.waitForFinished(msecs); }
|
||||
{ return m_process->waitForFinished(msecs); }
|
||||
|
||||
private:
|
||||
void handleStarted()
|
||||
{
|
||||
m_processStartHandler.handleProcessStarted(&m_process);
|
||||
m_processStartHandler.handleProcessStarted(m_process);
|
||||
emit started();
|
||||
}
|
||||
ProcessHelper m_process;
|
||||
ProcessHelper *m_process;
|
||||
ProcessStartHandler m_processStartHandler;
|
||||
};
|
||||
|
||||
|
@@ -84,6 +84,7 @@ SOURCES += \
|
||||
$$PWD/json.cpp \
|
||||
$$PWD/portlist.cpp \
|
||||
$$PWD/processhandle.cpp \
|
||||
$$PWD/processreaper.cpp \
|
||||
$$PWD/processutils.cpp \
|
||||
$$PWD/appmainwindow.cpp \
|
||||
$$PWD/basetreeview.cpp \
|
||||
@@ -222,6 +223,7 @@ HEADERS += \
|
||||
$$PWD/runextensions.h \
|
||||
$$PWD/portlist.h \
|
||||
$$PWD/processhandle.h \
|
||||
$$PWD/processreaper.h \
|
||||
$$PWD/processutils.h \
|
||||
$$PWD/appmainwindow.h \
|
||||
$$PWD/basetreeview.h \
|
||||
|
@@ -218,6 +218,8 @@ Project {
|
||||
"portlist.h",
|
||||
"processhandle.cpp",
|
||||
"processhandle.h",
|
||||
"processreaper.cpp",
|
||||
"processreaper.h",
|
||||
"processutils.cpp",
|
||||
"processutils.h",
|
||||
"progressindicator.cpp",
|
||||
|
@@ -39,7 +39,6 @@
|
||||
#include <android/androidconstants.h>
|
||||
#include <coreplugin/icore.h>
|
||||
#include <coreplugin/progressmanager/progressmanager.h>
|
||||
#include <coreplugin/reaper.h>
|
||||
#include <cppeditor/cppeditorconstants.h>
|
||||
#include <cppeditor/cppprojectupdater.h>
|
||||
#include <cppeditor/generatedcodemodelsupport.h>
|
||||
|
@@ -28,7 +28,6 @@
|
||||
#include "cmakeparser.h"
|
||||
|
||||
#include <coreplugin/progressmanager/progressmanager.h>
|
||||
#include <coreplugin/reaper.h>
|
||||
#include <projectexplorer/buildsystem.h>
|
||||
#include <projectexplorer/projectexplorerconstants.h>
|
||||
#include <projectexplorer/taskhub.h>
|
||||
@@ -57,11 +56,7 @@ CMakeProcess::CMakeProcess()
|
||||
|
||||
CMakeProcess::~CMakeProcess()
|
||||
{
|
||||
if (m_process) {
|
||||
m_process->disconnect();
|
||||
Core::Reaper::reap(m_process.release());
|
||||
}
|
||||
|
||||
m_process.reset();
|
||||
m_parser.flush();
|
||||
|
||||
if (m_future) {
|
||||
|
@@ -135,7 +135,6 @@ add_qtc_plugin(Core
|
||||
progressmanager/progressbar.cpp progressmanager/progressbar.h
|
||||
progressmanager/progressmanager.cpp progressmanager/progressmanager.h progressmanager/progressmanager_p.h
|
||||
progressmanager/progressview.cpp progressmanager/progressview.h
|
||||
reaper.cpp reaper.h reaper_p.h
|
||||
rightpane.cpp rightpane.h
|
||||
settingsdatabase.cpp settingsdatabase.h
|
||||
shellcommand.cpp shellcommand.h
|
||||
|
@@ -32,7 +32,6 @@
|
||||
#include "iwizardfactory.h"
|
||||
#include "mainwindow.h"
|
||||
#include "modemanager.h"
|
||||
#include "reaper_p.h"
|
||||
#include "themechooser.h"
|
||||
|
||||
#include <coreplugin/actionmanager/actionmanager.h>
|
||||
@@ -96,13 +95,11 @@ CorePlugin::CorePlugin()
|
||||
qRegisterMetaType<Utils::CommandLine>();
|
||||
qRegisterMetaType<Utils::FilePath>();
|
||||
m_instance = this;
|
||||
m_reaper = new ProcessReapers;
|
||||
setupSystemEnvironment();
|
||||
}
|
||||
|
||||
CorePlugin::~CorePlugin()
|
||||
{
|
||||
delete m_reaper;
|
||||
IWizardFactory::destroyFeatureProvider();
|
||||
Find::destroy();
|
||||
|
||||
|
@@ -44,7 +44,6 @@ namespace Internal {
|
||||
class EditMode;
|
||||
class MainWindow;
|
||||
class Locator;
|
||||
class ProcessReapers;
|
||||
|
||||
class CorePlugin : public ExtensionSystem::IPlugin
|
||||
{
|
||||
@@ -93,7 +92,6 @@ private:
|
||||
MainWindow *m_mainWindow = nullptr;
|
||||
EditMode *m_editMode = nullptr;
|
||||
Locator *m_locator = nullptr;
|
||||
ProcessReapers *m_reaper = nullptr;
|
||||
Utils::Environment m_startupSystemEnvironment;
|
||||
Utils::EnvironmentItems m_environmentChanges;
|
||||
};
|
||||
|
@@ -54,7 +54,6 @@ SOURCES += corejsextensions.cpp \
|
||||
progressmanager/progressview.cpp \
|
||||
progressmanager/progressbar.cpp \
|
||||
progressmanager/futureprogress.cpp \
|
||||
reaper.cpp \
|
||||
coreplugin.cpp \
|
||||
modemanager.cpp \
|
||||
basefilewizard.cpp \
|
||||
@@ -161,8 +160,6 @@ HEADERS += corejsextensions.h \
|
||||
progressmanager/progressbar.h \
|
||||
progressmanager/futureprogress.h \
|
||||
progressmanager/progressmanager.h \
|
||||
reaper.h \
|
||||
reaper_p.h \
|
||||
icontext.h \
|
||||
icore.h \
|
||||
imode.h \
|
||||
|
@@ -144,9 +144,6 @@ Project {
|
||||
"plugindialog.h",
|
||||
"plugininstallwizard.cpp",
|
||||
"plugininstallwizard.h",
|
||||
"reaper.cpp",
|
||||
"reaper.h",
|
||||
"reaper_p.h",
|
||||
"rightpane.cpp",
|
||||
"rightpane.h",
|
||||
"settingsdatabase.cpp",
|
||||
|
@@ -27,7 +27,6 @@
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
#include <coreplugin/messagemanager.h>
|
||||
#include <coreplugin/reaper.h>
|
||||
#include <utils/macroexpander.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
@@ -199,12 +198,7 @@ void ExecuteFilter::removeProcess()
|
||||
return;
|
||||
|
||||
m_taskQueue.dequeue();
|
||||
m_process->disconnect();
|
||||
if (m_process->state() == QProcess::NotRunning)
|
||||
m_process->deleteLater();
|
||||
else
|
||||
Reaper::reap(m_process);
|
||||
|
||||
delete m_process;
|
||||
m_process = nullptr;
|
||||
}
|
||||
|
||||
|
@@ -28,7 +28,6 @@
|
||||
#include "../messagemanager.h"
|
||||
|
||||
#include <coreplugin/editormanager/editormanager.h>
|
||||
#include <coreplugin/reaper.h>
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/commandline.h>
|
||||
#include <utils/environment.h>
|
||||
@@ -156,10 +155,7 @@ void SpotlightIterator::killProcess()
|
||||
QMutexLocker lock(&m_mutex);
|
||||
m_finished = true;
|
||||
m_waitForItems.wakeAll();
|
||||
if (m_process->state() == QProcess::NotRunning)
|
||||
m_process.reset();
|
||||
else
|
||||
Reaper::reap(m_process.release());
|
||||
m_process.reset();
|
||||
}
|
||||
|
||||
void SpotlightIterator::ensureNext()
|
||||
|
@@ -1,38 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 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 "core_global.h"
|
||||
|
||||
namespace Utils { class QtcProcess; }
|
||||
|
||||
namespace Core {
|
||||
namespace Reaper {
|
||||
|
||||
CORE_EXPORT void reap(Utils::QtcProcess *p, int timeoutMs = 500);
|
||||
|
||||
} // namespace Reaper
|
||||
} // namespace Core
|
@@ -34,8 +34,6 @@
|
||||
#include "target.h"
|
||||
#include "task.h"
|
||||
|
||||
#include <coreplugin/reaper.h>
|
||||
|
||||
#include <utils/fileutils.h>
|
||||
#include <utils/outputformatter.h>
|
||||
#include <utils/qtcassert.h>
|
||||
@@ -255,7 +253,7 @@ void AbstractProcessStep::setLowPriority()
|
||||
|
||||
void AbstractProcessStep::doCancel()
|
||||
{
|
||||
Core::Reaper::reap(d->m_process.release());
|
||||
d->m_process.reset();
|
||||
}
|
||||
|
||||
ProcessParameters *AbstractProcessStep::processParameters()
|
||||
|
@@ -11,6 +11,10 @@ add_qtc_executable(qtcreator_processlauncher
|
||||
processlauncher-main.cpp
|
||||
${UTILSDIR}/launcherpackets.cpp
|
||||
${UTILSDIR}/launcherpackets.h
|
||||
${UTILSDIR}/processreaper.cpp
|
||||
${UTILSDIR}/processreaper.h
|
||||
${UTILSDIR}/processutils.cpp
|
||||
${UTILSDIR}/processutils.h
|
||||
${UTILSDIR}/qtcassert.cpp
|
||||
${UTILSDIR}/qtcassert.h
|
||||
)
|
||||
|
@@ -26,12 +26,12 @@
|
||||
#include "launchersockethandler.h"
|
||||
|
||||
#include "launcherlogging.h"
|
||||
#include "processreaper.h"
|
||||
#include "processutils.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QLocalSocket>
|
||||
#include <QProcess>
|
||||
#include <QTimer>
|
||||
|
||||
namespace Utils {
|
||||
namespace Internal {
|
||||
@@ -41,43 +41,13 @@ class Process : public ProcessHelper
|
||||
Q_OBJECT
|
||||
public:
|
||||
Process(quintptr token, QObject *parent = nullptr) :
|
||||
ProcessHelper(parent), m_token(token), m_stopTimer(new QTimer(this))
|
||||
{
|
||||
m_stopTimer->setSingleShot(true);
|
||||
connect(m_stopTimer, &QTimer::timeout, this, &Process::cancel);
|
||||
}
|
||||
|
||||
void cancel()
|
||||
{
|
||||
if (state() == QProcess::NotRunning) {
|
||||
deleteLater();
|
||||
return;
|
||||
}
|
||||
switch (m_stopState) {
|
||||
case StopState::Inactive:
|
||||
m_stopState = StopState::Terminating;
|
||||
m_stopTimer->start(3000);
|
||||
terminate();
|
||||
break;
|
||||
case StopState::Terminating:
|
||||
m_stopState = StopState::Killing;
|
||||
m_stopTimer->start(3000);
|
||||
kill();
|
||||
break;
|
||||
case StopState::Killing:
|
||||
m_stopState = StopState::Inactive;
|
||||
deleteLater(); // TODO: employ something like Core::Reaper here
|
||||
break;
|
||||
}
|
||||
}
|
||||
ProcessHelper(parent), m_token(token) { }
|
||||
|
||||
quintptr token() const { return m_token; }
|
||||
ProcessStartHandler *processStartHandler() { return &m_processStartHandler; }
|
||||
|
||||
private:
|
||||
const quintptr m_token;
|
||||
QTimer * const m_stopTimer;
|
||||
enum class StopState { Inactive, Terminating, Killing } m_stopState = StopState::Inactive;
|
||||
ProcessStartHandler m_processStartHandler;
|
||||
};
|
||||
|
||||
@@ -97,7 +67,7 @@ LauncherSocketHandler::~LauncherSocketHandler()
|
||||
m_socket->close();
|
||||
}
|
||||
for (auto it = m_processes.cbegin(); it != m_processes.cend(); ++it)
|
||||
it.value()->disconnect();
|
||||
ProcessReaper::reap(it.value());
|
||||
}
|
||||
|
||||
void LauncherSocketHandler::start()
|
||||
@@ -269,13 +239,15 @@ void LauncherSocketHandler::handleStopPacket()
|
||||
{
|
||||
Process * const process = m_processes.value(m_packetParser.token());
|
||||
if (!process) {
|
||||
logWarn("got stop request for unknown process");
|
||||
// This can happen when the process finishes on its own at about the same time the client
|
||||
// sends the request. In this case the process was already deleted.
|
||||
logDebug("got stop request for unknown process");
|
||||
return;
|
||||
}
|
||||
if (process->state() == QProcess::NotRunning) {
|
||||
// This can happen if the process finishes on its own at about the same time the client
|
||||
// sends the request.
|
||||
logDebug("got stop request when process was not running");
|
||||
// This shouldn't happen, since as soon as process finishes or error occurrs
|
||||
// the process is being removed.
|
||||
logWarn("got stop request when process was not running");
|
||||
} else {
|
||||
// We got the client request to stop the starting / running process.
|
||||
// We report process exit to the client.
|
||||
@@ -331,11 +303,7 @@ void LauncherSocketHandler::removeProcess(quintptr token)
|
||||
|
||||
Process *process = it.value();
|
||||
m_processes.erase(it);
|
||||
process->disconnect();
|
||||
if (process->state() != QProcess::NotRunning)
|
||||
process->cancel();
|
||||
else
|
||||
process->deleteLater();
|
||||
ProcessReaper::reap(process);
|
||||
}
|
||||
|
||||
Process *LauncherSocketHandler::senderProcess() const
|
||||
|
@@ -25,6 +25,7 @@
|
||||
|
||||
#include "launcherlogging.h"
|
||||
#include "launchersockethandler.h"
|
||||
#include "processreaper.h"
|
||||
|
||||
#include <QtCore/qcoreapplication.h>
|
||||
#include <QtCore/qtimer.h>
|
||||
@@ -51,6 +52,7 @@ int main(int argc, char *argv[])
|
||||
return 1;
|
||||
}
|
||||
|
||||
Utils::ProcessReaper processReaper;
|
||||
Utils::Internal::LauncherSocketHandler launcher(app.arguments().constLast());
|
||||
QTimer::singleShot(0, &launcher, &Utils::Internal::LauncherSocketHandler::start);
|
||||
return app.exec();
|
||||
|
@@ -13,11 +13,15 @@ HEADERS += \
|
||||
launcherlogging.h \
|
||||
launchersockethandler.h \
|
||||
$$UTILS_DIR/launcherpackets.h \
|
||||
$$UTILS_DIR/processutils.h
|
||||
$$UTILS_DIR/processreaper.h \
|
||||
$$UTILS_DIR/processutils.h \
|
||||
$$UTILS_DIR/qtcassert.h
|
||||
|
||||
SOURCES += \
|
||||
launcherlogging.cpp \
|
||||
launchersockethandler.cpp \
|
||||
processlauncher-main.cpp \
|
||||
$$UTILS_DIR/launcherpackets.cpp \
|
||||
$$UTILS_DIR/processutils.cpp
|
||||
$$UTILS_DIR/processreaper.cpp \
|
||||
$$UTILS_DIR/processutils.cpp \
|
||||
$$UTILS_DIR/qtcassert.cpp
|
||||
|
@@ -23,8 +23,12 @@ QtcTool {
|
||||
files: [
|
||||
"launcherpackets.cpp",
|
||||
"launcherpackets.h",
|
||||
"processreaper.cpp",
|
||||
"processreaper.h",
|
||||
"processutils.cpp",
|
||||
"processutils.h",
|
||||
"qtcassert.cpp",
|
||||
"qtcassert.h",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@@ -27,6 +27,7 @@
|
||||
#include <utils/hostosinfo.h>
|
||||
#include <utils/launcherinterface.h>
|
||||
#include <utils/porting.h>
|
||||
#include <utils/processreaper.h>
|
||||
#include <utils/qtcprocess.h>
|
||||
#include <utils/stringutils.h>
|
||||
|
||||
@@ -203,6 +204,7 @@ private slots:
|
||||
private:
|
||||
void iteratorEditsHelper(OsType osType);
|
||||
|
||||
Utils::ProcessReaper processReaper;
|
||||
Environment envWindows;
|
||||
Environment envLinux;
|
||||
|
||||
|
@@ -30,6 +30,7 @@
|
||||
|
||||
#include <sqliteglobal.h>
|
||||
#include <utils/launcherinterface.h>
|
||||
#include <utils/processreaper.h>
|
||||
#include <utils/temporarydirectory.h>
|
||||
|
||||
#include <QGuiApplication>
|
||||
@@ -60,6 +61,7 @@ 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(); });
|
||||
|
Reference in New Issue
Block a user