forked from qt-creator/qt-creator
Qmake: Prevent unresponsive processes from hanging Qt Creator
That is, processes run via qmake's system() function. Fun fact disovered while implementing this: "Canceling" the loading of a qmake project did nothing at all except making the progress bar red at the end of the parsing procedure. Now at least we terminate the currently running processes invoked by system(), so the parsing threads can continue and eventually finish. Task-number: QTCREATORBUG-24825 Task-number: QTCREATORBUG-25000 Task-number: QTCREATORBUG-25194 Change-Id: Ic92ef200d3a49bbdeff0429ae7038fe3f1935b38 Reviewed-by: Joerg Bornemann <joerg.bornemann@qt.io>
This commit is contained in:
@@ -666,6 +666,18 @@ void QmakeBuildSystem::asyncUpdate()
|
|||||||
Constants::PROFILE_EVALUATE);
|
Constants::PROFILE_EVALUATE);
|
||||||
|
|
||||||
m_asyncUpdateFutureInterface.reportStarted();
|
m_asyncUpdateFutureInterface.reportStarted();
|
||||||
|
const auto watcher = new QFutureWatcher<void>(this);
|
||||||
|
connect(watcher, &QFutureWatcher<void>::canceled, this, [this, watcher] {
|
||||||
|
if (!m_qmakeGlobals)
|
||||||
|
return;
|
||||||
|
watcher->disconnect();
|
||||||
|
m_qmakeGlobals->killProcesses();
|
||||||
|
});
|
||||||
|
connect(watcher, &QFutureWatcher<void>::finished, this, [watcher] {
|
||||||
|
watcher->disconnect();
|
||||||
|
watcher->deleteLater();
|
||||||
|
});
|
||||||
|
watcher->setFuture(m_asyncUpdateFutureInterface.future());
|
||||||
|
|
||||||
const Kit *const k = kit();
|
const Kit *const k = kit();
|
||||||
QtSupport::BaseQtVersion *const qtVersion = QtSupport::QtKitAspect::qtVersion(k);
|
QtSupport::BaseQtVersion *const qtVersion = QtSupport::QtKitAspect::qtVersion(k);
|
||||||
|
@@ -473,13 +473,28 @@ void QMakeEvaluator::runProcess(QProcess *proc, const QString &command) const
|
|||||||
proc->setProcessEnvironment(env);
|
proc->setProcessEnvironment(env);
|
||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
|
# ifdef PROEVALUATOR_THREAD_SAFE
|
||||||
|
m_option->mutex.lock();
|
||||||
|
if (m_option->canceled) {
|
||||||
|
m_option->mutex.unlock();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_option->runningProcs << proc;
|
||||||
|
# endif
|
||||||
# ifdef Q_OS_WIN
|
# ifdef Q_OS_WIN
|
||||||
proc->setNativeArguments(QLatin1String("/v:off /s /c \"") + command + QLatin1Char('"'));
|
proc->setNativeArguments(QLatin1String("/v:off /s /c \"") + command + QLatin1Char('"'));
|
||||||
proc->start(m_option->getEnv(QLatin1String("COMSPEC")), QStringList());
|
proc->start(m_option->getEnv(QLatin1String("COMSPEC")), QStringList());
|
||||||
# else
|
# else
|
||||||
proc->start(QLatin1String("/bin/sh"), QStringList() << QLatin1String("-c") << command);
|
proc->start(QLatin1String("/bin/sh"), QStringList() << QLatin1String("-c") << command);
|
||||||
|
# endif
|
||||||
|
# ifdef PROEVALUATOR_THREAD_SAFE
|
||||||
|
m_option->mutex.unlock();
|
||||||
# endif
|
# endif
|
||||||
proc->waitForFinished(-1);
|
proc->waitForFinished(-1);
|
||||||
|
# ifdef PROEVALUATOR_THREAD_SAFE
|
||||||
|
QMutexLocker(&m_option->mutex);
|
||||||
|
m_option->runningProcs.removeOne(proc);
|
||||||
|
# endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -490,7 +505,7 @@ QByteArray QMakeEvaluator::getCommandOutput(const QString &args, int *exitCode)
|
|||||||
QProcess proc;
|
QProcess proc;
|
||||||
runProcess(&proc, args);
|
runProcess(&proc, args);
|
||||||
*exitCode = (proc.exitStatus() == QProcess::NormalExit) ? proc.exitCode() : -1;
|
*exitCode = (proc.exitStatus() == QProcess::NormalExit) ? proc.exitCode() : -1;
|
||||||
QByteArray errout = proc.readAllStandardError();
|
QByteArray errout = proc.isReadable() ? proc.readAllStandardError() : QByteArray();
|
||||||
# ifdef PROEVALUATOR_FULL
|
# ifdef PROEVALUATOR_FULL
|
||||||
// FIXME: Qt really should have the option to set forwarding per channel
|
// FIXME: Qt really should have the option to set forwarding per channel
|
||||||
fputs(errout.constData(), stderr);
|
fputs(errout.constData(), stderr);
|
||||||
@@ -503,7 +518,7 @@ QByteArray QMakeEvaluator::getCommandOutput(const QString &args, int *exitCode)
|
|||||||
QString::fromLocal8Bit(errout));
|
QString::fromLocal8Bit(errout));
|
||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
out = proc.readAllStandardOutput();
|
out = proc.isReadable() ? proc.readAllStandardOutput() : QByteArray();
|
||||||
# ifdef Q_OS_WIN
|
# ifdef Q_OS_WIN
|
||||||
// FIXME: Qt's line end conversion on sequential files should really be fixed
|
// FIXME: Qt's line end conversion on sequential files should really be fixed
|
||||||
out.replace("\r\n", "\n");
|
out.replace("\r\n", "\n");
|
||||||
|
@@ -89,6 +89,17 @@ QMakeGlobals::~QMakeGlobals()
|
|||||||
qDeleteAll(baseEnvs);
|
qDeleteAll(baseEnvs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QMakeGlobals::killProcesses()
|
||||||
|
{
|
||||||
|
#ifdef PROEVALUATOR_THREAD_SAFE
|
||||||
|
QMutexLocker lock(&mutex);
|
||||||
|
canceled = true;
|
||||||
|
for (QProcess * const proc : runningProcs)
|
||||||
|
proc->kill();
|
||||||
|
runningProcs.clear();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
QString QMakeGlobals::cleanSpec(QMakeCmdLineParserState &state, const QString &spec)
|
QString QMakeGlobals::cleanSpec(QMakeCmdLineParserState &state, const QString &spec)
|
||||||
{
|
{
|
||||||
QString ret = QDir::cleanPath(spec);
|
QString ret = QDir::cleanPath(spec);
|
||||||
|
@@ -112,6 +112,8 @@ public:
|
|||||||
QString extra_cmds[4];
|
QString extra_cmds[4];
|
||||||
bool runSystemFunction = false;
|
bool runSystemFunction = false;
|
||||||
|
|
||||||
|
void killProcesses();
|
||||||
|
|
||||||
#ifdef PROEVALUATOR_DEBUG
|
#ifdef PROEVALUATOR_DEBUG
|
||||||
int debugLevel;
|
int debugLevel;
|
||||||
#endif
|
#endif
|
||||||
@@ -157,6 +159,8 @@ private:
|
|||||||
|
|
||||||
#ifdef PROEVALUATOR_THREAD_SAFE
|
#ifdef PROEVALUATOR_THREAD_SAFE
|
||||||
QMutex mutex;
|
QMutex mutex;
|
||||||
|
bool canceled = false;
|
||||||
|
QList<QProcess *> runningProcs;
|
||||||
#endif
|
#endif
|
||||||
QHash<QMakeBaseKey, QMakeBaseEnv *> baseEnvs;
|
QHash<QMakeBaseKey, QMakeBaseEnv *> baseEnvs;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user