[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