diff options
author | Alex Trotsenko <alex1973tr@gmail.com> | 2021-01-05 18:59:40 +0200 |
---|---|---|
committer | Oswald Buddenhagen <oswald.buddenhagen@gmx.de> | 2021-01-09 13:15:54 +0000 |
commit | 6a6d12ea4b90d24839f13b92237dbc8cce5eaf9d (patch) | |
tree | 382a1e3647d41fe1f211aaa1e26d76620af0ccd6 /src/corelib/io/qprocess_unix.cpp | |
parent | 05706bd2b005dd159be34107cc43c92e7f12eb35 (diff) |
Split QProcessPrivate::_q_processDied()
The completion of the child process can take place asynchronously or in
one of the waitFor...() functions. In both cases, we used the same
handler (_q_processDied()), which caused several problems:
a. technically, waitForReadyRead() should have taken into account the
result of the calls to _q_canRead...() slots inside the
_q_processDied() function:
- the user calls waitForReadyRead();
- forkfd descriptor becomes signaled, while a grandchild
process is still alive;
- as readyRead() signal has not been emitted, _q_processDied()
is called;
- the grandchild process writes to stdout pipe;
- now data arrives, and _q_processDied() will collect it, but
won't report it.
b. we had a bug with recursions on Unix:
- death notification comes asynchronously;
- waitForDeadChild() closes forkfd;
- _q_canRead...() emits readyRead();
- a slot connected to readyRead() calls waitForFinished();
- waitForFinished() hangs (forkfd == -1).
c. for blocking functions, drainOutputPipes() was called twice on
Windows.
By introducing a new processFinished() function, we leave the read
operations in the _q_processDied() slot, while the process completion
code is guaranteed to run only once.
Change-Id: I5f9d09bc68a058169de4d9e490b48fc0b35e94cd
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
Diffstat (limited to 'src/corelib/io/qprocess_unix.cpp')
-rw-r--r-- | src/corelib/io/qprocess_unix.cpp | 11 |
1 files changed, 6 insertions, 5 deletions
diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp index 1ca4a0d65e..17a1425d3f 100644 --- a/src/corelib/io/qprocess_unix.cpp +++ b/src/corelib/io/qprocess_unix.cpp @@ -754,8 +754,10 @@ bool QProcessPrivate::waitForReadyRead(const QDeadlineTimer &deadline) if (processState == QProcess::NotRunning) return false; + // We do this after checking the pipes, so we cannot reach it as long + // as there is any data left to be read from an already dead process. if (qt_pollfd_check(poller.forkfd(), POLLIN)) { - _q_processDied(); + processFinished(); return false; } } @@ -796,7 +798,7 @@ bool QProcessPrivate::waitForBytesWritten(const QDeadlineTimer &deadline) return false; if (qt_pollfd_check(poller.forkfd(), POLLIN)) { - _q_processDied(); + processFinished(); return false; } } @@ -837,7 +839,7 @@ bool QProcessPrivate::waitForFinished(const QDeadlineTimer &deadline) return true; if (qt_pollfd_check(poller.forkfd(), POLLIN)) { - _q_processDied(); + processFinished(); return true; } } @@ -850,8 +852,7 @@ void QProcessPrivate::findExitCode() void QProcessPrivate::waitForDeadChild() { - if (forkfd == -1) - return; // child has already been reaped + Q_ASSERT(forkfd != -1); // read the process information from our fd forkfd_info info; |