From 2039880e75ce9375519729d1716e3627944fcae7 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Wed, 7 Jun 2023 12:28:31 +0200 Subject: [PATCH] ProcessStub: Don't block main thread while waiting for keypress Otherwise the request to exit from Qt Creator would be missed, making QtC hang on exit while waiting for the stub to exit. Fixes: QTCREATORBUG-15749 Change-Id: I26dfa2c8aa358c8d7ad662ef806f459d1bbb6ec2 Reviewed-by: Eike Ziller --- src/tools/process_stub/main.cpp | 59 +++++++++++++++++---------------- 1 file changed, 31 insertions(+), 28 deletions(-) diff --git a/src/tools/process_stub/main.cpp b/src/tools/process_stub/main.cpp index f606b063694..d5fdc2f4086 100644 --- a/src/tools/process_stub/main.cpp +++ b/src/tools/process_stub/main.cpp @@ -48,20 +48,16 @@ std::optional environmentVariables; QProcess inferiorProcess; int inferiorId{0}; -#ifndef Q_OS_WIN - #ifdef Q_OS_DARWIN // A memory mapped helper to retrieve the pid of the inferior process in debugMode static int *shared_child_pid = nullptr; #endif -using OSSocketNotifier = QSocketNotifier; -#else +#ifdef Q_OS_WIN Q_PROCESS_INFORMATION *win_process_information = nullptr; -using OSSocketNotifier = QWinEventNotifier; #endif -// Helper to read a single character from stdin in testMode -OSSocketNotifier *stdInNotifier; + +bool waitingForExitKeyPress = false; QThread processThread; @@ -77,8 +73,10 @@ std::optional readEnvFile(); void setupControlSocket(); void setupSignalHandlers(); void startProcess(const QString &program, const QStringList &arguments, const QString &workingDir); -void readKey(); +void onKeyPress(std::function callback); void sendSelfPid(); +void killInferior(); +void resumeInferior(); int main(int argc, char *argv[]) { @@ -117,7 +115,15 @@ int main(int argc, char *argv[]) if (debugMode) { qDebug() << "Press 'c' to continue or 'k' to kill, followed by 'enter'"; - readKey(); + + onKeyPress([] { + char ch; + std::cin >> ch; + if (ch == 'k') + killInferior(); + else + resumeInferior(); + }); } return a.exec(); @@ -169,15 +175,20 @@ void sendErrChDir() void doExit(int exitCode) { + if (waitingForExitKeyPress) + exit(exitCode); + if (controlSocket.state() == QLocalSocket::ConnectedState && controlSocket.bytesToWrite()) controlSocket.waitForBytesWritten(1000); if (!commandLineParser.value("wait").isEmpty()) { - std::cout << commandLineParser.value("wait").toStdString(); - std::cin.get(); - } + std::cout << commandLineParser.value("wait").toStdString() << std::endl; - exit(exitCode); + waitingForExitKeyPress = true; + onKeyPress([exitCode] { doExit(exitCode); }); + } else { + exit(exitCode); + } } void onInferiorFinished(int exitCode, QProcess::ExitStatus status) @@ -550,23 +561,15 @@ void setupControlSocket() controlSocket.connectToServer(commandLineParser.value("socket")); } -void onStdInReadyRead() -{ - char ch; - std::cin >> ch; - if (ch == 'k') { - killInferior(); - } else { - resumeInferior(); - } -} - -void readKey() +void onKeyPress(std::function callback) { #ifdef Q_OS_WIN - stdInNotifier = new QWinEventNotifier(GetStdHandle(STD_INPUT_HANDLE)); + // On windows, QWinEventNotifier() doesn't work for stdin, so we have to use a thread instead. + QThread *thread = QThread::create([] { std::cin.ignore(); }); + thread->start(); + QObject::connect(thread, &QThread::finished, &controlSocket, callback); #else - stdInNotifier = new QSocketNotifier(fileno(stdin), QSocketNotifier::Read); + static auto stdInNotifier = new QSocketNotifier(fileno(stdin), QSocketNotifier::Read); + QObject::connect(stdInNotifier, &QSocketNotifier::activated, callback); #endif - QObject::connect(stdInNotifier, &OSSocketNotifier::activated, &onStdInReadyRead); }