[Qt-interest] return to command line but the GUI is still alive
Thiago Macieira
thiago at kde.org
Tue Jan 26 14:06:16 CET 2010
Em Terça-feira 26 Janeiro 2010, às 12:16:21, Srdjan Todorovic escreveu:
> Hi,
>
> On 26/01/2010, Thiago Macieira <thiago at kde.org> wrote:
> > Remember these rules about fork():
> >
> > 1) one side must either execve() or _exit(). That's a strict rule and
> > independent of Qt.
>
> Did you really mean ::_exit(...) instead ::exit(...) ?
> I thought it was acceptable to use ::exit(...).
Yes, I did.
Using exit(3) is not fine for *both* sides of the fork. Only one side can use
it.
The other side must use _exit(2).
And if you have more than one fork, then the rule applies to whole group.
For each PROCESS (including all its forks), it must call exit(3) at most once
(zero times is also ok). All the rest of the forks must either _exit(2) or
execve(2).
Also remember that "return from main" counts as a call to exit(3). I.e., the
actual program entry point is equivalent to:
exit(main(argc, argv));
Case in point:
A few weeks ago, a KDE / Phonon developer contacted me about a bug in QtDBus.
He showed me the backtrace of the crash (Q_ASSERT(false) in
qdbusintegrator.cpp QDBusConnectionPrivate::connectSignal). I looked at the
warning the code printed and I concluded it was an impossible situation.
We looked at the D-Bus traffic and we concluded that the D-Bus server had sent
us an invalid reply. So we started wondering if the problem was a bug in the
server.
But when we looked at the entire set of D-Bus traffic, we noticed that there was
more than one reply to the same call. (Each D-Bus message contains an ID and
each reply-type message (error or normal reply) contains a field saying "I'm
reply to call with ID nn")
So something in the process was sending more than one message with the same
ID. A quick look at D-Bus code showed it was impossible to reuse IDs.
So we strace(1)d the process to find out where it was happening. That's when we
realised that the process forked not once, but twice. And the each side of the
fork was sending D-Bus messages with the same IDs.
With a bit more of tracing, we found where the forks were: inside libvlc, in
completely unrelated code. A quick chat to j-b on the #qt channel led to VLC
being fixed:
http://git.videolan.org/?p=vlc.git;a=commitdiff;h=7868eb4ae83b5d195412eb6bca032ca37dd8d30d
Look at what the fix was:
- exit (EXIT_FAILURE);
+ _exit (EXIT_FAILURE);
What happens is that after a fork, all file descriptors are still shared with
the parent process (there's no Copy-On-Write for file descriptors). So if both
sides write to the socket, they should coordinate that to avoid data
corruption. The D-Bus library doesn't do that (there's a simple integer
counter for the IDs, but memory *is* Copy-On-Write).
If you call exit(3) instead of _exit(2), then the C library will call all
registered at-exit destructors, which include all C++ static object
destructors.
So what happened was that the libvlc fork exited improperly, causing QtDBus to
close its D-Bus connections "cleanly" by writing to the socket. Each fork did
that, thus causing socket data corruption.
And when the master process tried to use D-Bus again, it would receive a reply
to one of the forked calls, thus yielding the impossible situation, hence the
assert.
--
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
Senior Product Manager - Nokia, Qt Development Frameworks
PGP/GPG: 0x6EF45358; fingerprint:
E067 918B B660 DBD1 105C 966C 33F5 F005 6EF4 5358
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 190 bytes
Desc: This is a digitally signed message part.
Url : http://lists.qt-project.org/pipermail/qt-interest-old/attachments/20100126/20a0b752/attachment.bin
More information about the Qt-interest-old
mailing list