Simplest mainloop that could possibly work

Havoc Pennington hp at redhat.com
Tue Oct 30 12:13:17 PDT 2007


Hi,

Andrew Clunis wrote:
> I had originally intended to use dbus_connection_read_write_dispatch()
> function, and have the other thread call
> dbus_connection_send()/dbus_connection_flush().  Of course, that's no
> good because dbus_connection_read_write_dispatch() blocks on read I/O.
> Thus, rather comically, the messages for transmission get buffered and
> are only sent once the service happens to *receive* a message.

This is probably a bug - there should be a wakeup to the 
read_write_dispatch when you send a message. I think someone may have 
posted a patch for it even, or at least there was a past thread 
discussing how to do the patch. Maybe I'm thinking of something in 
bugzilla. Anyway... you may find it's easier to fix this than do your 
own loop.

> So, it looks like I have to bite the bullet and write a non-toy
> mainloop. I'm having a lot of trouble grokking the Watch/Timeout stuff,
> though, and I haven't had much luck finding useful example code.
> 
> As far as I understand it, I'm supposed to call
> dbus_connection_set_watch_functions() and
> dbus_connection_set_timeout_functions().  I'm unclear as to what I
> should do once I have a poll() loop running on the FDs, however.

Some example code you could use is:
  - GLib bindings / main loop
  - Qt bindings / main loop
  - the main loop used by the bus daemon (which is in
    dbus/dbus-mainloop.c)

What you need to be clear on is what read, write, and dispatch mean. 
That is,
  - read from socket into buffer (add to incoming message queue)
  - write out buffer to socket (drain outgoing message queue)
  - dispatch (run handlers to drain incoming message queue)

Anytime there is data for reading or a timeout on the poll(), there may 
be changes to the incoming message queue. A timeout could e.g. add a 
timeout error message to the queue.

So, anytime you read, you need to dispatch (or at least check the 
dispatch status) in case there's stuff to dispatch.

When there is stuff in the outgoing queue, you'll have a write watch and 
will need to poll so you wake up when the socket is ready for writing.

Blocking happens whenever there's nothing to dispatch, and the socket 
has nothing to read, and we either have nothing to write or the socket 
is not ready for writing.

When threads are involved you also need a "wakeup main function" which 
solves the problem you are seeing with read_write_dispatch, i.e. if the 
main loop is blocking and another thread adds to the outgoing queue, the 
main loop has to be kicked out of the poll().

This is in no way trivial - it is definitely less work to fix the 
read_write_dispatch issue.

Another option is to try to use some main loop library (libevent? though 
I haven't tried that one myself), or cut-and-paste from something like GLib.

Havoc



More information about the dbus mailing list