[Qt-interest] QProcess could close the reading pipe, thus killing the child process with SIGPIPE
Thiago Macieira
thiago.macieira at trolltech.com
Sun May 3 18:21:32 CEST 2009
Jan Kundrát wrote:
>Thiago Macieira wrote:
>> It's not a problem.
>>
>> That slot should not be called unless there's something to be read. If
>> there's a read of 0, that means the pipe has closed. So the code is
>> right.
>
>Hi Thiago,
>OK, that makes sense. I've tried to go through the Qt sources to a call
>to select() or poll(), but it's probably buried deep inside the glib
>event loop, so I gave up. Let's assume for a while that the OS is
>correct for a while.
You can also run your application with QT_NO_GLIB=1, which will make the
Qt event loop system avoid glib and instead use its own implementation,
which you can find in src/corelib/kernel (the QAbstractEventDispatcher and
QEventDispatcherUnix classes). The main thread in a GUI program will use
the X11 dispatcher (src/gui/kernel), but that's just for handling the X11
socket and its events.
>This QProcess is created in a separate thread. This thread has its own
>event loop and I'm not touching the process in any other thread at all.
>I've attached the relevant code, but let me explain what it is supposed
>to do:
You're talking about QProcess here, but your code is actually talking
about socket.
Not that it should matter because the behaviour should be the same. But
QAbstractSocket has a lot more testing and workarounds for broken systems
than QProcess does. For example, some systems are known to produce
spurious read events (Windows) even when there's nothing to be read.
Linux is actually fairly well behaved in that aspect.
>* There's a QueuedConnection between the readyReady() and one method
Shouldn't be needed. Read the description of the "Won't fix" in the task
217111.
>* The processLine is a bit more complex; due to the nature of the
>protocol in question, we don't know whether we will have to read some
>more data before that line is processed. That means that from inside a
>(queued) slot connected to readyRead, we sometimes call
>waitForReadyRead(), read(size) and readLine(). Is that safe?
It's safe in an unencrypted socket, but not in a process. Again, I refer
to the description in task 217111: there's a workaround for buggy user
code that does waitForReadyRead inside the readyRead slot in
QAbstractSocket. That code is not present in QProcess and is the same code
that makes waitForReadyRead in QSslSocket impossible.
So you have three different behaviour, depending on the task, due to this
workaround:
- QTcpSocket: waitForReadyRead inside readyRead() works, but doesn't
actually emit the signal
- QProcess: waitForReadyRead inside readyRead() works *and* emits the
signal, which means your slot will recurse (this is the original and
intended behaviour)
- QSslSocket: waitForReadyRead inside readyRead() does not work and will
lock up (because QTcpSocket doesn't emit readyRead())
So here it's important to know which class you're using.
If you don't want to handle the difference, you should do as I described in
task 217111: if you don't have enough data, simply return and wait for
readyRead() to be emitted again with more data.
If you don't want to do your own buffering, you can use the peek() function
to read the data but not discard from the QIODevice buffers. In the context
of an IMAP parser, I'd use readLine() and store that line only. If there
are any continuations, then you return and wait for more data, until all
data has been received (you know the number of bytes).
>If there's no bug in my OS, I'd guess that somehow I managed to read the
>data that interrupted the select() deep inside the event loop. However,
>I don't see how that could happen, given that the event loop should run
>in the same thread as my handler (right?). Is that a possible scenario?
No. From your initial description, the select loop got a read activation
on the file descriptor, but when checking the number of bytes, we got 0.
(Note that the code didn't actually try to read, but simply did an
FIONREAD) The only case in which a zero-read doesn't mean EOF is that of
zero-length UDP datagrams.
A pipe or a TCP socket are stream devices. They never produce zero-reads
unless it's EOF.
From your description, I can only think of bug in the OS. If you can
reproduce this, let me know. But I need a small testcase for that.
The code you posted seemed right at first glance, except for the
waitForReadyRead calls (and the use of a thread in the first place). The
use of a thread points to the only other possibility here: there's a
threading mismatch and the QIODevice object *is* actually being touched
from outside its thread. I'm going to take a quick look at your code.
--
Thiago Macieira - thiago.macieira (AT) nokia.com
Senior Product Manager - Nokia, Qt Software
Sandakerveien 116, NO-0402 Oslo, Norway
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: This is a digitally signed message part.
Url : http://lists.qt-project.org/pipermail/qt-interest-old/attachments/20090503/2a8fd43e/attachment.bin
More information about the Qt-interest-old
mailing list