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