diff --git a/src/libs/utils/process.cpp b/src/libs/utils/process.cpp index d11164734b4..69ba2ce1920 100644 --- a/src/libs/utils/process.cpp +++ b/src/libs/utils/process.cpp @@ -1865,43 +1865,45 @@ void Process::setWriteData(const QByteArray &writeData) void Process::runBlocking(EventLoopMode eventLoopMode) { - // Attach a dynamic property with info about blocking type - d->storeEventLoopDebugInfo(int(eventLoopMode)); - QDateTime startTime; static const int blockingThresholdMs = qtcEnvironmentVariableIntValue("QTC_PROCESS_THRESHOLD"); - if (blockingThresholdMs > 0 && isMainThread()) - startTime = QDateTime::currentDateTime(); - Process::start(); - // Remove the dynamic property so that it's not reused in subseqent start() - d->storeEventLoopDebugInfo({}); + auto starter = [this, eventLoopMode, &startTime] { + // Attach a dynamic property with info about blocking type + d->storeEventLoopDebugInfo(int(eventLoopMode)); + + if (blockingThresholdMs > 0 && isMainThread()) + startTime = QDateTime::currentDateTime(); + start(); + + // Remove the dynamic property so that it's not reused in subseqent start() + d->storeEventLoopDebugInfo({}); + }; if (eventLoopMode == EventLoopMode::On) { - // Start failure is triggered immediately if the executable cannot be found in the path. - // In this case the process is left in NotRunning state. - // Do not start the event loop in that case. - if (state() == QProcess::Starting) { - QTimer timer(this); - connect(&timer, &QTimer::timeout, d, &ProcessPrivate::slotTimeout); - timer.setInterval(1000); - timer.start(); + QTimer timer(this); + connect(&timer, &QTimer::timeout, d, &ProcessPrivate::slotTimeout); + timer.setInterval(1000); + timer.start(); #ifdef QT_GUI_LIB - if (isGuiEnabled()) - QGuiApplication::setOverrideCursor(Qt::WaitCursor); + if (isGuiEnabled()) + QGuiApplication::setOverrideCursor(Qt::WaitCursor); #endif - QEventLoop eventLoop(this); - QTC_ASSERT(!d->m_eventLoop, return); - d->m_eventLoop = &eventLoop; - eventLoop.exec(QEventLoop::ExcludeUserInputEvents); - d->m_eventLoop = nullptr; - timer.stop(); + QEventLoop eventLoop(this); + QTC_ASSERT(!d->m_eventLoop, return); + d->m_eventLoop = &eventLoop; + // Queue the call to start() so that it's executed after the nested event loop is started, + // otherwise it fails on Windows with QProcessImpl. See QTCREATORBUG-30066. + QMetaObject::invokeMethod(this, starter, Qt::QueuedConnection); + eventLoop.exec(QEventLoop::ExcludeUserInputEvents); + d->m_eventLoop = nullptr; + timer.stop(); #ifdef QT_GUI_LIB - if (isGuiEnabled()) - QGuiApplication::restoreOverrideCursor(); + if (isGuiEnabled()) + QGuiApplication::restoreOverrideCursor(); #endif - } } else { + starter(); if (!waitForStarted(d->m_maxHangTimerCount * 1000)) { d->m_result = ProcessResult::StartFailed; return; diff --git a/tests/auto/utils/process/tst_process.cpp b/tests/auto/utils/process/tst_process.cpp index 8cb04b7c28e..0ea1c63255f 100644 --- a/tests/auto/utils/process/tst_process.cpp +++ b/tests/auto/utils/process/tst_process.cpp @@ -1595,17 +1595,7 @@ void tst_Process::eventLoopMode() subConfig.setupSubProcess(&process); process.setProcessImpl(processImpl); process.runBlocking(eventLoopMode); - const ProcessResult actualResult = process.result(); - - // FIXME: On Windows, Process::runBlocking(EventLoopMode::On) and ProcessImpl::QProcess fails - // with ProcessResult::StartFailed. Details: QTCREATORBUG-30066 - const bool isFailingCombination = HostOsInfo::isWindowsHost() - && processImpl == ProcessImpl::QProcess - && eventLoopMode == EventLoopMode::On; - const ProcessResult expectedResult = isFailingCombination ? ProcessResult::StartFailed - : ProcessResult::FinishedWithSuccess; - - QCOMPARE(actualResult, expectedResult); + QCOMPARE(process.result(), ProcessResult::FinishedWithSuccess); } QTEST_GUILESS_MAIN(tst_Process)