[education/rkward] rkward/rbackend: Avoid use of QProcess:waitForReadyRead() without event loop.
Thomas Friedrichsmeier
null at kde.org
Mon Aug 1 18:30:28 BST 2022
Git commit 116142e8b9c8d43f4b3d85aa053e47518e149582 by Thomas Friedrichsmeier.
Committed on 01/08/2022 at 17:29.
Pushed by tfry into branch 'master'.
Avoid use of QProcess:waitForReadyRead() without event loop.
It seems to be broken in RHEL 8.6. See https://mail.kde.org/pipermail/rkward-devel/2022-August/005861.html
M +19 -7 rkward/rbackend/rkfrontendtransmitter.cpp
https://invent.kde.org/education/rkward/commit/116142e8b9c8d43f4b3d85aa053e47518e149582
diff --git a/rkward/rbackend/rkfrontendtransmitter.cpp b/rkward/rbackend/rkfrontendtransmitter.cpp
index 4492dfbe..13a0f939 100644
--- a/rkward/rbackend/rkfrontendtransmitter.cpp
+++ b/rkward/rbackend/rkfrontendtransmitter.cpp
@@ -130,7 +130,7 @@ void RKFrontendTransmitter::run () {
RK_DEBUG(RBACKEND, DL_INFO, "Setting working directory to %s", qPrintable (r_home));
backend->setWorkingDirectory (r_home);
#endif
-//#if defined(Q_OS_WIN)
+#if defined(Q_OS_WIN)
// On some windows systems, the _first_ invocation of the backend seems to fail as somehow process output from the backend (the token) never arrives.
// What appears to function as a workaround is start a dummy process, before that.
QProcess dummy;
@@ -139,7 +139,7 @@ void RKFrontendTransmitter::run () {
dummy.start(RKSessionVars::RBinary(), dummyargs, QIODevice::ReadOnly);
dummy.waitForFinished();
dummy.readAllStandardOutput();
-//#endif
+#endif
RK_DEBUG(RBACKEND, DL_DEBUG, "Starting backend. Timestamp %d", QDateTime::currentMSecsSinceEpoch(), token.length());
backend->start(RKSessionVars::RBinary(), args, QIODevice::ReadOnly);
@@ -152,6 +152,13 @@ void RKFrontendTransmitter::run () {
}
RK_DEBUG(RBACKEND, DL_DEBUG, "Startup done at %d. Received token length was %d", QDateTime::currentMSecsSinceEpoch(), token.length());
+ // Due to the need to call processEvents() inside waitReadLine() (see comment, there), the can be a race condition, where
+ // connectAndEnterLoop() was already called, but returned without doing anything. In that case, call it again, now.
+ if (server->hasPendingConnections()) {
+ if (token.isEmpty()) token = i18n("[No token received]");
+ connectAndEnterLoop();
+ }
+
exec ();
// It's ok to only give backend a short time to finish. We only get here, after QuitCommand has been handled by the backend
@@ -171,28 +178,33 @@ QString RKFrontendTransmitter::waitReadLine (QIODevice* con, int msecs) {
QElapsedTimer time;
time.start();
QByteArray ret;
+ QEventLoop loop;
do {
RK_DEBUG(RBACKEND, DL_DEBUG, "Time %d, buffer %d, available %d", QDateTime::currentMSecsSinceEpoch(), ret.length(), con->bytesAvailable());
ret.append(con->readLine());
RK_DEBUG(RBACKEND, DL_DEBUG, "Time2 %d, buffer %d, available %d", QDateTime::currentMSecsSinceEpoch(), ret.length(), con->bytesAvailable());
if (ret.contains('\n')) break;
RK_DEBUG(RBACKEND, DL_DEBUG, "Time3 %d", QDateTime::currentMSecsSinceEpoch());
- con->waitForReadyRead(500);
+ //con->waitForReadyRead(500); -> See https://mail.kde.org/pipermail/rkward-devel/2022-August/005861.html : Never returns on RHEL 8.6
+ // as a workaround, sleep, then process events
+ msleep(100);
+ loop.processEvents();
} while(time.elapsed() < msecs);
return QString::fromLocal8Bit(ret);
}
void RKFrontendTransmitter::connectAndEnterLoop () {
- RK_TRACE (RBACKEND);
- RK_ASSERT (server->hasPendingConnections ());
+ RK_TRACE(RBACKEND);
+ RK_ASSERT(server->hasPendingConnections());
+ if (token.isEmpty()) return; // See comment in c'tor
QLocalSocket *con = server->nextPendingConnection ();
server->close ();
// handshake
- QString token_c = waitReadLine(con, 1000).trimmed();
+ QString token_c = waitReadLine(con, 2000).trimmed();
if (token_c != token) handleTransmissionError (i18n ("Error during handshake with backend process. Expected token '%1', received token '%2'", token, token_c));
- QString version_c = waitReadLine(con, 1000).trimmed();
+ QString version_c = waitReadLine(con, 2000).trimmed();
if (version_c != RKWARD_VERSION) handleTransmissionError (i18n ("Version mismatch during handshake with backend process. Frontend is version '%1' while backend is '%2'.\nPlease fix your installation.", QString (RKWARD_VERSION), version_c));
setConnection (con);
More information about the rkward-tracker
mailing list