A libev based mainloop and lost signals

Thiago Macieira thiago at kde.org
Wed Aug 11 09:58:43 PDT 2010


On Wednesday 11 August 2010 15:48:05 Thomas Themel wrote:
> Hi,
> 
> Excerpts from Thiago Macieira's message of Tue Aug 10 14:30:30 +0200 2010:
> > To make this work, you must not use _and_block. You must instead use
> > send_with_reply and make sure that the other thread doesn't pull your
> > reply before you do.
> 
> Well, send_with_reply is not an overly nice API for a multithreaded setup
> since I have a race between setting the DBusPendingCall's callback and the
> dispatching of the reply in the background thread.

That can easily be solved by taking a mutex lock around the D-Bus dispatcher. 
The background thread will be woken up out of select(2) or poll(2), but will 
block on trying to acquire the mutex.

When the foreground thread is done calling send_with_reply, it only needs to 
unlock that mutex.

Though I agree that libdbus-1 should be doing this on its own. A 
send_with_reply operation should not be interruptible. And I think it does 
that, in D-Bus 1.3.x.

> I'm also a little confused since the DBusConnection docs state
> 
>  * The most useful function to call from multiple threads at once
>  * is dbus_connection_send_with_reply_and_block(). That is,
>  * multiple threads can make method calls at the same time.

Yeah. That has nothing to do with the original problem, though (at least how I 
understood it).

If several threads are at the same time trying to send_with_reply_and_block, 
each will succeed in acquiring the lock to the connection and the transport, 
send their data, receive any pending messages (and put them in a queue, not 
process them), then return once they find their reply.

As long as none of those calls times out, this should happen quite quickly. 

Please note that this is affected by the bug fixed in 1.3.2: there was a 
condition in which the send_with_reply_and_block function unlocked the 
connection (while calling out to user code to change timer and watcher 
conditions), which meant that another thread could acquire the connection and 
find it in an inconsistent state.

At the same time, a mainloop can be running in another thread. While each 
blocking call is happening, the mainloop will not be able to invoke the 
dispatcher.

Note, however, that each send_with_reply_and_block, like I said above, will 
try to change states of timers and fd-watchers. Your event loop implementation 
must support changing state of those from *any* thread, not just the mainloop 
thread. This was the source of a number of bugs in QtDBus until I finally 
nailed it down around Qt 4.5.

If this is all that your code is doing, it's fine.

But what I had understood is that you're making calls from one thread that 
should be processed by the mainloop thread. That is, you're making calls to 
yourself.

If you're making calls to yourself while using and_block, the mainloop will 
not run, so there's no chance that the incoming call will be processed. If you 
want to make calls to yourself, either use send_with_reply + DBusPendingCall, 
or do what I did in QtDBus: bypass libdbus-1 and go straight to the target 
object. If you use DBusPendingCall, note that the object will notify you of 
activity from the mainloop thread, so you may need to sync back to the calling 
thread on your own.

-- 
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.freedesktop.org/archives/dbus/attachments/20100811/fc566158/attachment.pgp>


More information about the dbus mailing list