Introduce ProcessBlockingInterface

This replaces the ProcessInterface::waitFor...() methods.
It's not obligatory to provide this interface when
implementing ProcessInterface subclass. In this case
generic blocking implementation will be used.

The generic implementation usually isn't as efficient as
the custom one, however, for some sophisticated implementations
of process interface, like e.g. SshProcessInterface, providing
custom implementation is really difficult and error prone.

That's why we try to keep a balance: we provide two custom
implementations for QProcessImpl and for ProcessLauncherImpl,
as they are relatively easy to implement, and rely on
generic implementation for others.

Change-Id: Ifc8bd354479ec67b2e8f74f1510f8de8883e9b94
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Jarek Kobus
2022-06-08 14:24:40 +02:00
parent 0efb8d3346
commit 0b2899215f
8 changed files with 190 additions and 181 deletions

View File

@@ -89,21 +89,6 @@ CallerHandle::~CallerHandle()
qDeleteAll(m_signals); qDeleteAll(m_signals);
} }
bool CallerHandle::waitForStarted(int msecs)
{
return waitForSignal(msecs, SignalType::Started);
}
bool CallerHandle::waitForReadyRead(int msces)
{
return waitForSignal(msces, SignalType::ReadyRead);
}
bool CallerHandle::waitForFinished(int msecs)
{
return waitForSignal(msecs, SignalType::Done);
}
void CallerHandle::flush() void CallerHandle::flush()
{ {
flushFor(SignalType::NoSignal); flushFor(SignalType::NoSignal);
@@ -329,11 +314,11 @@ void CallerHandle::setProcessSetupData(ProcessSetupData *setup)
m_setup = setup; m_setup = setup;
} }
bool CallerHandle::waitForSignal(int msecs, SignalType newSignal) bool CallerHandle::waitForSignal(SignalType signalType, int msecs)
{ {
QTC_ASSERT(isCalledFromCallersThread(), return false); QTC_ASSERT(isCalledFromCallersThread(), return false);
QTC_ASSERT(m_launcherHandle, return false); QTC_ASSERT(m_launcherHandle, return false);
return m_launcherHandle->waitForSignal(msecs, newSignal); return m_launcherHandle->waitForSignal(signalType, msecs);
} }
// Called from caller's or launcher's thread. // Called from caller's or launcher's thread.
@@ -351,7 +336,7 @@ bool CallerHandle::isCalledFromLaunchersThread() const
} }
// Called from caller's thread exclusively. // Called from caller's thread exclusively.
bool LauncherHandle::waitForSignal(int msecs, CallerHandle::SignalType newSignal) bool LauncherHandle::waitForSignal(CallerHandle::SignalType newSignal, int msecs)
{ {
QTC_ASSERT(!isCalledFromLaunchersThread(), return false); QTC_ASSERT(!isCalledFromLaunchersThread(), return false);
QDeadlineTimer deadline(msecs); QDeadlineTimer deadline(msecs);

View File

@@ -73,9 +73,7 @@ public:
LauncherHandle *launcherHandle() const { return m_launcherHandle; } LauncherHandle *launcherHandle() const { return m_launcherHandle; }
void setLauncherHandle(LauncherHandle *handle) { QMutexLocker locker(&m_mutex); m_launcherHandle = handle; } void setLauncherHandle(LauncherHandle *handle) { QMutexLocker locker(&m_mutex); m_launcherHandle = handle; }
bool waitForStarted(int msecs); bool waitForSignal(CallerHandle::SignalType signalType, int msecs);
bool waitForReadyRead(int msces);
bool waitForFinished(int msecs);
// Returns the list of flushed signals. // Returns the list of flushed signals.
void flush(); void flush();
@@ -109,8 +107,6 @@ signals:
void done(const Utils::ProcessResultData &resultData); void done(const Utils::ProcessResultData &resultData);
private: private:
bool waitForSignal(int msecs, SignalType newSignal);
// Called from caller's thread exclusively. // Called from caller's thread exclusively.
void sendPacket(const Internal::LauncherPacket &packet); void sendPacket(const Internal::LauncherPacket &packet);
// Called from caller's or launcher's thread. // Called from caller's or launcher's thread.
@@ -158,7 +154,7 @@ public:
// Called from caller's thread, moved to launcher's thread afterwards. // Called from caller's thread, moved to launcher's thread afterwards.
LauncherHandle(quintptr token) : m_token(token) {} LauncherHandle(quintptr token) : m_token(token) {}
// Called from caller's thread exclusively. // Called from caller's thread exclusively.
bool waitForSignal(int msecs, CallerHandle::SignalType newSignal); bool waitForSignal(CallerHandle::SignalType newSignal, int msecs);
CallerHandle *callerHandle() const { return m_callerHandle; } CallerHandle *callerHandle() const { return m_callerHandle; }
void setCallerHandle(CallerHandle *handle) { QMutexLocker locker(&m_mutex); m_callerHandle = handle; } void setCallerHandle(CallerHandle *handle) { QMutexLocker locker(&m_mutex); m_callerHandle = handle; }

View File

@@ -85,13 +85,22 @@ enum class ProcessSignalType {
Done Done
}; };
class QTCREATOR_UTILS_EXPORT ProcessBlockingInterface : public QObject
{
private:
// Wait for:
// - Started is being called only in Starting state.
// - ReadyRead is being called in Starting or Running state.
// - Done is being called in Starting or Running state.
virtual bool waitForSignal(ProcessSignalType signalType, int msecs) = 0;
friend class Internal::QtcProcessPrivate;
};
class QTCREATOR_UTILS_EXPORT ProcessInterface : public QObject class QTCREATOR_UTILS_EXPORT ProcessInterface : public QObject
{ {
Q_OBJECT Q_OBJECT
public:
ProcessInterface(QObject *parent = nullptr) : QObject(parent) {}
signals: signals:
// This should be emitted when being in Starting state only. // This should be emitted when being in Starting state only.
// After emitting this signal the process enters Running state. // After emitting this signal the process enters Running state.
@@ -121,14 +130,7 @@ private:
// It's being called in Starting or Running state. // It's being called in Starting or Running state.
virtual void sendControlSignal(ControlSignal controlSignal) = 0; virtual void sendControlSignal(ControlSignal controlSignal) = 0;
// It's being called only in Starting state. virtual ProcessBlockingInterface *processBlockingInterface() const { return nullptr; }
virtual bool waitForStarted(int msecs) = 0;
// It's being called in Starting or Running state.
virtual bool waitForReadyRead(int msecs) = 0;
// It's being called in Starting or Running state.
virtual bool waitForFinished(int msecs) = 0;
friend class QtcProcess; friend class QtcProcess;
friend class Internal::QtcProcessPrivate; friend class Internal::QtcProcessPrivate;

View File

@@ -322,10 +322,34 @@ bool DefaultImpl::ensureProgramExists(const QString &program)
return false; return false;
} }
class QProcessBlockingImpl : public ProcessBlockingInterface
{
public:
QProcessBlockingImpl(QProcess *process) : m_process(process) {}
private:
bool waitForSignal(ProcessSignalType signalType, int msecs) final
{
switch (signalType) {
case ProcessSignalType::Started:
return m_process->waitForStarted(msecs);
case ProcessSignalType::ReadyRead:
return m_process->waitForReadyRead(msecs);
case ProcessSignalType::Done:
return m_process->waitForFinished(msecs);
}
return false;
}
QProcess *m_process = nullptr;
};
class QProcessImpl final : public DefaultImpl class QProcessImpl final : public DefaultImpl
{ {
public: public:
QProcessImpl() : m_process(new ProcessHelper(this)) QProcessImpl()
: m_process(new ProcessHelper(this))
, m_blockingImpl(new QProcessBlockingImpl(m_process))
{ {
connect(m_process, &QProcess::started, connect(m_process, &QProcess::started,
this, &QProcessImpl::handleStarted); this, &QProcessImpl::handleStarted);
@@ -361,9 +385,7 @@ private:
} }
} }
bool waitForStarted(int msecs) final { return m_process->waitForStarted(msecs); } virtual ProcessBlockingInterface *processBlockingInterface() const { return m_blockingImpl; }
bool waitForReadyRead(int msecs) final { return m_process->waitForReadyRead(msecs); }
bool waitForFinished(int msecs) final { return m_process->waitForFinished(msecs); }
void doDefaultStart(const QString &program, const QStringList &arguments) final void doDefaultStart(const QString &program, const QStringList &arguments) final
{ {
@@ -411,7 +433,8 @@ private:
emit done(result); emit done(result);
} }
ProcessHelper *m_process; ProcessHelper *m_process = nullptr;
QProcessBlockingImpl *m_blockingImpl = nullptr;
}; };
static uint uniqueToken() static uint uniqueToken()
@@ -420,6 +443,33 @@ static uint uniqueToken()
return ++globalUniqueToken; return ++globalUniqueToken;
} }
class ProcessLauncherBlockingImpl : public ProcessBlockingInterface
{
public:
ProcessLauncherBlockingImpl(CallerHandle *caller) : m_caller(caller) {}
private:
bool waitForSignal(ProcessSignalType signalType, int msecs) final
{
// TODO: Remove CallerHandle::SignalType
const CallerHandle::SignalType type = [signalType] {
switch (signalType) {
case ProcessSignalType::Started:
return CallerHandle::SignalType::Started;
case ProcessSignalType::ReadyRead:
return CallerHandle::SignalType::ReadyRead;
case ProcessSignalType::Done:
return CallerHandle::SignalType::Done;
}
QTC_CHECK(false);
return CallerHandle::SignalType::NoSignal;
}();
return m_caller->waitForSignal(type, msecs);
}
CallerHandle *m_caller = nullptr;
};
class ProcessLauncherImpl final : public DefaultImpl class ProcessLauncherImpl final : public DefaultImpl
{ {
Q_OBJECT Q_OBJECT
@@ -434,6 +484,7 @@ public:
this, &ProcessInterface::readyRead); this, &ProcessInterface::readyRead);
connect(m_handle, &CallerHandle::done, connect(m_handle, &CallerHandle::done,
this, &ProcessInterface::done); this, &ProcessInterface::done);
m_blockingImpl = new ProcessLauncherBlockingImpl(m_handle);
} }
~ProcessLauncherImpl() final ~ProcessLauncherImpl() final
{ {
@@ -462,9 +513,7 @@ private:
} }
} }
bool waitForStarted(int msecs) final { return m_handle->waitForStarted(msecs); } virtual ProcessBlockingInterface *processBlockingInterface() const { return m_blockingImpl; }
bool waitForReadyRead(int msecs) final { return m_handle->waitForReadyRead(msecs); }
bool waitForFinished(int msecs) final { return m_handle->waitForFinished(msecs); }
void doDefaultStart(const QString &program, const QStringList &arguments) final void doDefaultStart(const QString &program, const QStringList &arguments) final
{ {
@@ -476,6 +525,7 @@ private:
const uint m_token = 0; const uint m_token = 0;
// Lives in caller's thread. // Lives in caller's thread.
CallerHandle *m_handle = nullptr; CallerHandle *m_handle = nullptr;
ProcessLauncherBlockingImpl *m_blockingImpl = nullptr;
}; };
static ProcessImpl defaultProcessImpl() static ProcessImpl defaultProcessImpl()
@@ -535,13 +585,15 @@ private:
const ProcessResultData m_resultData; const ProcessResultData m_resultData;
}; };
class GeneralProcessBlockingImpl;
class ProcessInterfaceHandler : public QObject class ProcessInterfaceHandler : public QObject
{ {
public: public:
ProcessInterfaceHandler(QtcProcessPrivate *caller, ProcessInterface *process); ProcessInterfaceHandler(GeneralProcessBlockingImpl *caller, ProcessInterface *process);
// Called from caller's thread exclusively. // Called from caller's thread exclusively.
bool waitForSignal(int msecs, ProcessSignalType newSignal); bool waitForSignal(ProcessSignalType newSignal, int msecs);
void moveToCallerThread(); void moveToCallerThread();
private: private:
@@ -555,11 +607,44 @@ private:
void handleDone(const ProcessResultData &data); void handleDone(const ProcessResultData &data);
void appendSignal(ProcessInterfaceSignal *newSignal); void appendSignal(ProcessInterfaceSignal *newSignal);
QtcProcessPrivate *m_caller = nullptr; GeneralProcessBlockingImpl *m_caller = nullptr;
QMutex m_mutex; QMutex m_mutex;
QWaitCondition m_waitCondition; QWaitCondition m_waitCondition;
}; };
class GeneralProcessBlockingImpl : public ProcessBlockingInterface
{
public:
GeneralProcessBlockingImpl(QtcProcessPrivate *parent);
void flush() { flushSignals(takeAllSignals()); }
bool flushFor(ProcessSignalType signalType) {
return flushSignals(takeSignalsFor(signalType), &signalType);
}
bool shouldFlush() const { QMutexLocker locker(&m_mutex); return !m_signals.isEmpty(); }
// Called from ProcessInterfaceHandler thread exclusively.
void appendSignal(ProcessInterfaceSignal *launcherSignal);
private:
// Called from caller's thread exclusively
bool waitForSignal(ProcessSignalType newSignal, int msecs) final;
QList<ProcessInterfaceSignal *> takeAllSignals();
QList<ProcessInterfaceSignal *> takeSignalsFor(ProcessSignalType signalType);
bool flushSignals(const QList<ProcessInterfaceSignal *> &signalList,
ProcessSignalType *signalType = nullptr);
void handleStartedSignal(const StartedSignal *launcherSignal);
void handleReadyReadSignal(const ReadyReadSignal *launcherSignal);
void handleDoneSignal(const DoneSignal *launcherSignal);
QtcProcessPrivate *m_caller = nullptr;
std::unique_ptr<ProcessInterfaceHandler> m_processHandler;
mutable QMutex m_mutex;
QList<ProcessInterfaceSignal *> m_signals;
};
class QtcProcessPrivate : public QObject class QtcProcessPrivate : public QObject
{ {
public: public:
@@ -591,11 +676,18 @@ public:
void setProcessInterface(ProcessInterface *process) void setProcessInterface(ProcessInterface *process)
{ {
m_process.reset(process); m_process.reset(process);
m_processHandler.reset(new ProcessInterfaceHandler(this, process)); m_process->setParent(this);
connect(m_process.get(), &ProcessInterface::started,
this, &QtcProcessPrivate::handleStarted);
connect(m_process.get(), &ProcessInterface::readyRead,
this, &QtcProcessPrivate::handleReadyRead);
connect(m_process.get(), &ProcessInterface::done,
this, &QtcProcessPrivate::handleDone);
// In order to move the process into another thread together with handle m_blockingInterface.reset(process->processBlockingInterface());
m_process->setParent(m_processHandler.get()); if (!m_blockingInterface)
m_processHandler->setParent(this); m_blockingInterface.reset(new GeneralProcessBlockingImpl(this));
m_blockingInterface->setParent(this);
} }
CommandLine fullCommandLine() const CommandLine fullCommandLine() const
@@ -624,14 +716,11 @@ public:
} }
QtcProcess *q; QtcProcess *q;
std::unique_ptr<ProcessInterfaceHandler> m_processHandler; std::unique_ptr<ProcessBlockingInterface> m_blockingInterface;
std::unique_ptr<ProcessInterface> m_process; std::unique_ptr<ProcessInterface> m_process;
ProcessSetupData m_setup; ProcessSetupData m_setup;
void slotTimeout(); void slotTimeout();
void handleStartedSignal(const StartedSignal *launcherSignal);
void handleReadyReadSignal(const ReadyReadSignal *launcherSignal);
void handleDoneSignal(const DoneSignal *launcherSignal);
void handleStarted(qint64 processId, qint64 applicationMainThreadId); void handleStarted(qint64 processId, qint64 applicationMainThreadId);
void handleReadyRead(const QByteArray &outputData, const QByteArray &errorData); void handleReadyRead(const QByteArray &outputData, const QByteArray &errorData);
void handleDone(const ProcessResultData &data); void handleDone(const ProcessResultData &data);
@@ -647,31 +736,11 @@ public:
ProcessResult interpretExitCode(int exitCode); ProcessResult interpretExitCode(int exitCode);
// === ProcessInterfaceHandler related === bool waitForSignal(ProcessSignalType signalType, int msecs);
// Called from caller's thread exclusively
bool waitForSignal(int msecs, ProcessSignalType newSignal);
void flush() { flushSignals(takeAllSignals()); }
bool flushFor(ProcessSignalType signalType) {
return flushSignals(takeSignalsFor(signalType), &signalType);
}
QList<ProcessInterfaceSignal *> takeAllSignals();
QList<ProcessInterfaceSignal *> takeSignalsFor(ProcessSignalType signalType);
bool flushSignals(const QList<ProcessInterfaceSignal *> &signalList,
ProcessSignalType *signalType = nullptr);
bool shouldFlush() const { QMutexLocker locker(&m_mutex); return !m_signals.isEmpty(); }
Qt::ConnectionType connectionType() const; Qt::ConnectionType connectionType() const;
void sendControlSignal(ControlSignal controlSignal); void sendControlSignal(ControlSignal controlSignal);
// Called from ProcessInterfaceHandler thread exclusively.
void appendSignal(ProcessInterfaceSignal *launcherSignal);
mutable QMutex m_mutex;
QList<ProcessInterfaceSignal *> m_signals;
QTimer m_killTimer; QTimer m_killTimer;
// =======================================
QProcess::ProcessState m_state = QProcess::NotRunning; QProcess::ProcessState m_state = QProcess::NotRunning;
qint64 m_processId = 0; qint64 m_processId = 0;
qint64 m_applicationMainThreadId = 0; qint64 m_applicationMainThreadId = 0;
@@ -692,10 +761,11 @@ public:
Guard m_guard; Guard m_guard;
}; };
ProcessInterfaceHandler::ProcessInterfaceHandler(QtcProcessPrivate *caller, ProcessInterfaceHandler::ProcessInterfaceHandler(GeneralProcessBlockingImpl *caller,
ProcessInterface *process) ProcessInterface *process)
: m_caller(caller) : m_caller(caller)
{ {
process->disconnect();
connect(process, &ProcessInterface::started, connect(process, &ProcessInterface::started,
this, &ProcessInterfaceHandler::handleStarted); this, &ProcessInterfaceHandler::handleStarted);
connect(process, &ProcessInterface::readyRead, connect(process, &ProcessInterface::readyRead,
@@ -705,7 +775,7 @@ ProcessInterfaceHandler::ProcessInterfaceHandler(QtcProcessPrivate *caller,
} }
// Called from caller's thread exclusively. // Called from caller's thread exclusively.
bool ProcessInterfaceHandler::waitForSignal(int msecs, ProcessSignalType newSignal) bool ProcessInterfaceHandler::waitForSignal(ProcessSignalType newSignal, int msecs)
{ {
QDeadlineTimer deadline(msecs); QDeadlineTimer deadline(msecs);
while (true) { while (true) {
@@ -769,17 +839,20 @@ void ProcessInterfaceHandler::appendSignal(ProcessInterfaceSignal *newSignal)
} }
m_waitCondition.wakeOne(); m_waitCondition.wakeOne();
// call in callers thread // call in callers thread
QMetaObject::invokeMethod(m_caller, &QtcProcessPrivate::flush); QMetaObject::invokeMethod(m_caller, &GeneralProcessBlockingImpl::flush);
} }
// Called from caller's thread exclusively GeneralProcessBlockingImpl::GeneralProcessBlockingImpl(QtcProcessPrivate *parent)
bool QtcProcessPrivate::waitForSignal(int msecs, ProcessSignalType newSignal) : m_caller(parent)
, m_processHandler(new ProcessInterfaceHandler(this, parent->m_process.get()))
{ {
const QDeadlineTimer timeout(msecs); // In order to move the process interface into another thread together with handle
const QDeadlineTimer currentKillTimeout(m_killTimer.remainingTime()); parent->m_process.get()->setParent(m_processHandler.get());
const bool needsSplit = m_killTimer.isActive() ? timeout > currentKillTimeout : false; m_processHandler->setParent(this);
const QDeadlineTimer mainTimeout = needsSplit ? currentKillTimeout : timeout; }
bool GeneralProcessBlockingImpl::waitForSignal(ProcessSignalType newSignal, int msecs)
{
m_processHandler->setParent(nullptr); m_processHandler->setParent(nullptr);
QThread thread; QThread thread;
@@ -789,12 +862,7 @@ bool QtcProcessPrivate::waitForSignal(int msecs, ProcessSignalType newSignal)
// the caller here is blocked, so all signals should be buffered and we are going // the caller here is blocked, so all signals should be buffered and we are going
// to flush them from inside waitForSignal(). // to flush them from inside waitForSignal().
m_processHandler->moveToThread(&thread); m_processHandler->moveToThread(&thread);
bool result = m_processHandler->waitForSignal(mainTimeout.remainingTime(), newSignal); const bool result = m_processHandler->waitForSignal(newSignal, msecs);
if (!result && needsSplit) {
m_killTimer.stop();
sendControlSignal(ControlSignal::Kill);
result = m_processHandler->waitForSignal(timeout.remainingTime(), newSignal);
}
m_processHandler->moveToCallerThread(); m_processHandler->moveToCallerThread();
m_processHandler->setParent(this); m_processHandler->setParent(this);
thread.quit(); thread.quit();
@@ -803,14 +871,14 @@ bool QtcProcessPrivate::waitForSignal(int msecs, ProcessSignalType newSignal)
} }
// Called from caller's thread exclusively // Called from caller's thread exclusively
QList<ProcessInterfaceSignal *> QtcProcessPrivate::takeAllSignals() QList<ProcessInterfaceSignal *> GeneralProcessBlockingImpl::takeAllSignals()
{ {
QMutexLocker locker(&m_mutex); QMutexLocker locker(&m_mutex);
return std::exchange(m_signals, {}); return std::exchange(m_signals, {});
} }
// Called from caller's thread exclusively // Called from caller's thread exclusively
QList<ProcessInterfaceSignal *> QtcProcessPrivate::takeSignalsFor(ProcessSignalType signalType) QList<ProcessInterfaceSignal *> GeneralProcessBlockingImpl::takeSignalsFor(ProcessSignalType signalType)
{ {
// If we are flushing for ReadyRead or Done - flush all. // If we are flushing for ReadyRead or Done - flush all.
if (signalType != ProcessSignalType::Started) if (signalType != ProcessSignalType::Started)
@@ -840,7 +908,7 @@ QList<ProcessInterfaceSignal *> QtcProcessPrivate::takeSignalsFor(ProcessSignalT
} }
// Called from caller's thread exclusively // Called from caller's thread exclusively
bool QtcProcessPrivate::flushSignals(const QList<ProcessInterfaceSignal *> &signalList, bool GeneralProcessBlockingImpl::flushSignals(const QList<ProcessInterfaceSignal *> &signalList,
ProcessSignalType *signalType) ProcessSignalType *signalType)
{ {
bool signalMatched = false; bool signalMatched = false;
@@ -866,14 +934,50 @@ bool QtcProcessPrivate::flushSignals(const QList<ProcessInterfaceSignal *> &sign
return signalMatched; return signalMatched;
} }
// Called from caller's thread exclusively void GeneralProcessBlockingImpl::handleStartedSignal(const StartedSignal *aSignal)
{
m_caller->handleStarted(aSignal->processId(), aSignal->applicationMainThreadId());
}
void GeneralProcessBlockingImpl::handleReadyReadSignal(const ReadyReadSignal *aSignal)
{
m_caller->handleReadyRead(aSignal->stdOut(), aSignal->stdErr());
}
void GeneralProcessBlockingImpl::handleDoneSignal(const DoneSignal *aSignal)
{
m_caller->handleDone(aSignal->resultData());
}
// Called from ProcessInterfaceHandler thread exclusively.
void GeneralProcessBlockingImpl::appendSignal(ProcessInterfaceSignal *newSignal)
{
QMutexLocker locker(&m_mutex);
m_signals.append(newSignal);
}
bool QtcProcessPrivate::waitForSignal(ProcessSignalType newSignal, int msecs)
{
const QDeadlineTimer timeout(msecs);
const QDeadlineTimer currentKillTimeout(m_killTimer.remainingTime());
const bool needsSplit = m_killTimer.isActive() ? timeout > currentKillTimeout : false;
const QDeadlineTimer mainTimeout = needsSplit ? currentKillTimeout : timeout;
bool result = m_blockingInterface->waitForSignal(newSignal, mainTimeout.remainingTime());
if (!result && needsSplit) {
m_killTimer.stop();
sendControlSignal(ControlSignal::Kill);
result = m_blockingInterface->waitForSignal(newSignal, timeout.remainingTime());
}
return result;
}
Qt::ConnectionType QtcProcessPrivate::connectionType() const Qt::ConnectionType QtcProcessPrivate::connectionType() const
{ {
return (m_process->thread() == thread()) ? Qt::DirectConnection return (m_process->thread() == thread()) ? Qt::DirectConnection
: Qt::BlockingQueuedConnection; : Qt::BlockingQueuedConnection;
} }
// Called from caller's thread exclusively
void QtcProcessPrivate::sendControlSignal(ControlSignal controlSignal) void QtcProcessPrivate::sendControlSignal(ControlSignal controlSignal)
{ {
QTC_ASSERT(QThread::currentThread() == thread(), return); QTC_ASSERT(QThread::currentThread() == thread(), return);
@@ -885,13 +989,6 @@ void QtcProcessPrivate::sendControlSignal(ControlSignal controlSignal)
}, connectionType()); }, connectionType());
} }
// Called from ProcessInterfaceHandler thread exclusively.
void QtcProcessPrivate::appendSignal(ProcessInterfaceSignal *newSignal)
{
QMutexLocker locker(&m_mutex);
m_signals.append(newSignal);
}
void QtcProcessPrivate::clearForRun() void QtcProcessPrivate::clearForRun()
{ {
m_hangTimerCount = 0; m_hangTimerCount = 0;
@@ -1444,8 +1541,8 @@ bool QtcProcess::waitForStarted(int msecs)
return true; return true;
if (d->m_state == QProcess::NotRunning) if (d->m_state == QProcess::NotRunning)
return false; return false;
return s_waitForStarted.measureAndRun(&QtcProcessPrivate::waitForSignal, d, msecs, return s_waitForStarted.measureAndRun(&QtcProcessPrivate::waitForSignal, d,
ProcessSignalType::Started); ProcessSignalType::Started, msecs);
} }
bool QtcProcess::waitForReadyRead(int msecs) bool QtcProcess::waitForReadyRead(int msecs)
@@ -1453,7 +1550,7 @@ bool QtcProcess::waitForReadyRead(int msecs)
QTC_ASSERT(d->m_process, return false); QTC_ASSERT(d->m_process, return false);
if (d->m_state == QProcess::NotRunning) if (d->m_state == QProcess::NotRunning)
return false; return false;
return d->waitForSignal(msecs, ProcessSignalType::ReadyRead); return d->waitForSignal(ProcessSignalType::ReadyRead, msecs);
} }
bool QtcProcess::waitForFinished(int msecs) bool QtcProcess::waitForFinished(int msecs)
@@ -1461,7 +1558,7 @@ bool QtcProcess::waitForFinished(int msecs)
QTC_ASSERT(d->m_process, return false); QTC_ASSERT(d->m_process, return false);
if (d->m_state == QProcess::NotRunning) if (d->m_state == QProcess::NotRunning)
return false; return false;
return d->waitForSignal(msecs, ProcessSignalType::Done); return d->waitForSignal(ProcessSignalType::Done, msecs);
} }
QByteArray QtcProcess::readAllStandardOutput() QByteArray QtcProcess::readAllStandardOutput()
@@ -1511,9 +1608,9 @@ void QtcProcess::close()
d->m_process->disconnect(); d->m_process->disconnect();
d->m_process.release()->deleteLater(); d->m_process.release()->deleteLater();
} }
if (d->m_processHandler) { if (d->m_blockingInterface) {
d->m_processHandler->disconnect(); d->m_blockingInterface->disconnect();
d->m_processHandler.release()->deleteLater(); d->m_blockingInterface.release()->deleteLater();
} }
d->clearForRun(); d->clearForRun();
} }
@@ -1854,22 +1951,6 @@ void QtcProcessPrivate::slotTimeout()
} }
} }
void QtcProcessPrivate::handleStartedSignal(const StartedSignal *aSignal)
{
handleStarted(aSignal->processId(), aSignal->applicationMainThreadId());
}
void QtcProcessPrivate::handleReadyReadSignal(const ReadyReadSignal *aSignal)
{
handleReadyRead(aSignal->stdOut(), aSignal->stdErr());
}
void QtcProcessPrivate::handleDoneSignal(const DoneSignal *aSignal)
{
m_killTimer.stop();
handleDone(aSignal->resultData());
}
void QtcProcessPrivate::handleStarted(qint64 processId, qint64 applicationMainThreadId) void QtcProcessPrivate::handleStarted(qint64 processId, qint64 applicationMainThreadId)
{ {
QTC_CHECK(m_state == QProcess::Starting); QTC_CHECK(m_state == QProcess::Starting);
@@ -1908,6 +1989,7 @@ void QtcProcessPrivate::handleReadyRead(const QByteArray &outputData, const QByt
void QtcProcessPrivate::handleDone(const ProcessResultData &data) void QtcProcessPrivate::handleDone(const ProcessResultData &data)
{ {
m_killTimer.stop();
m_resultData = data; m_resultData = data;
switch (m_state) { switch (m_state) {

View File

@@ -50,12 +50,6 @@ private:
qint64 write(const QByteArray &) final { QTC_CHECK(false); return -1; } qint64 write(const QByteArray &) final { QTC_CHECK(false); return -1; }
void sendControlSignal(ControlSignal controlSignal) final; void sendControlSignal(ControlSignal controlSignal) final;
// intentionally no-op without an assert
bool waitForStarted(int) final { return false; }
bool waitForReadyRead(int) final { QTC_CHECK(false); return false; }
// intentionally no-op without an assert
bool waitForFinished(int) final { return false; }
// OK, however, impl looks a bit different (!= NotRunning vs == Running). // OK, however, impl looks a bit different (!= NotRunning vs == Running).
// Most probably changing it into (== Running) should be OK. // Most probably changing it into (== Running) should be OK.
bool isRunning() const; bool isRunning() const;

View File

@@ -168,10 +168,6 @@ private:
qint64 write(const QByteArray &data) override; qint64 write(const QByteArray &data) override;
void sendControlSignal(ControlSignal controlSignal) override; void sendControlSignal(ControlSignal controlSignal) override;
bool waitForStarted(int msecs) override;
bool waitForReadyRead(int msecs) override;
bool waitForFinished(int msecs) override;
private: private:
CommandLine fullLocalCommandLine(bool interactive); CommandLine fullLocalCommandLine(bool interactive);
@@ -288,27 +284,6 @@ void DockerProcessImpl::sendControlSignal(ControlSignal controlSignal)
{"kill", {QString("-%1").arg(signal), QString("%2").arg(m_remotePID)}}); {"kill", {QString("-%1").arg(signal), QString("%2").arg(m_remotePID)}});
} }
bool DockerProcessImpl::waitForStarted(int msecs)
{
Q_UNUSED(msecs)
QTC_CHECK(false);
return false;
}
bool DockerProcessImpl::waitForReadyRead(int msecs)
{
Q_UNUSED(msecs)
QTC_CHECK(false);
return false;
}
bool DockerProcessImpl::waitForFinished(int msecs)
{
Q_UNUSED(msecs)
QTC_CHECK(false);
return false;
}
IDeviceWidget *DockerDevice::createWidget() IDeviceWidget *DockerDevice::createWidget()
{ {
return new DockerDeviceWidget(sharedFromThis()); return new DockerDeviceWidget(sharedFromThis());

View File

@@ -497,27 +497,6 @@ qint64 SshProcessInterface::write(const QByteArray &data)
return d->m_process.writeRaw(data); return d->m_process.writeRaw(data);
} }
bool SshProcessInterface::waitForStarted(int msecs)
{
Q_UNUSED(msecs)
QTC_CHECK(false);
return false;
}
bool SshProcessInterface::waitForReadyRead(int msecs)
{
Q_UNUSED(msecs)
QTC_CHECK(false);
return false;
}
bool SshProcessInterface::waitForFinished(int msecs)
{
Q_UNUSED(msecs)
QTC_CHECK(false);
return false;
}
LinuxProcessInterface::LinuxProcessInterface(const LinuxDevice *linuxDevice) LinuxProcessInterface::LinuxProcessInterface(const LinuxDevice *linuxDevice)
: SshProcessInterface(linuxDevice) : SshProcessInterface(linuxDevice)
{ {

View File

@@ -60,10 +60,6 @@ private:
qint64 write(const QByteArray &data) final; qint64 write(const QByteArray &data) final;
void sendControlSignal(Utils::ControlSignal controlSignal) override = 0; void sendControlSignal(Utils::ControlSignal controlSignal) override = 0;
bool waitForStarted(int msecs) final;
bool waitForReadyRead(int msecs) final;
bool waitForFinished(int msecs) final;
friend class SshProcessInterfacePrivate; friend class SshProcessInterfacePrivate;
SshProcessInterfacePrivate *d = nullptr; SshProcessInterfacePrivate *d = nullptr;
}; };