DBus Specification questions

Simon McVittie smcv at collabora.com
Tue Mar 31 20:42:50 UTC 2020


On Tue, 31 Mar 2020 at 14:22:22 -0400, Robert Middleton wrote:
> Related question: I know that there have been issues with libdbus and
> multithreading, any thoughts on how to best handle this?

libdbus tries to be all things to all people, and support any or no
event-loop abstraction. Whatever you do, don't do that.

If your runtime environment has an event-loop abstraction with a coherent
model for how things are meant to work, like GLib's GMainContext or
Qt's...  QApplication? (it's a while since I've used Qt), then please
use that, and require your API users to use it too.

If you are inventing your own thing, decide whether each object is:

- fully thread-safe (any thread can call any externally-exposed method,
  signals/callbacks should document which context/thread they will get
  called in - this is hard to get right, and you will probably end up
  needing a worker thread that does all the actual I/O. See: GDBus)

- single-threaded (each thread must have its own separate instance of
  this object, and no other thread is allowed to touch it;
  see: systemd's sd-bus)

- something else (dangerous)

Definitely don't do what libdbus does, where the actual I/O might happen
in any thread or any mixture of threads according to the whim of the host
application, and there's an elaborate dance involving two overlapping
mutexes for a thread to get ownership of the I/O path, the ability to
dispatch messages to callbacks, or maybe both...

> I wasn't completely sure as there is an error
> org.freedesktop.DBus.Error.NoReply, which at least implies(to me) that
> this can come from other places.

Some implementations, like libdbus, use a D-Bus-style error name
and error message pair, synthesized locally rather than derived
from a message, to report errors. In particular, libdbus uses
org.freedesktop.DBus.Error.NoReply to signal "I was expecting a reply,
but then I timed out" to its callers. This avoids having to invent a
second, parallel error-reporting mechanism where D-Bus error messages
go through one API, locally-generated errors go through another, and
callers have to check two error indicators - libdbus usually turns all
error conditions into a DBusError object.

The vocabulary of standard D-Bus errors includes some that are only sent
and received over the bus, some that would only be synthesized locally
(notably Disconnected - how would you ever receive that?), and some that
can happen either way (like NoReply).

I don't think systemd's sd-bus does that so much: it uses a (name,
message) pair for error messages received from the bus, but returns a
negative errno code for locally-generated errors. That's also a valid
approach, with advantages and disadvantages. I personally prefer libdbus'
approach here, but it's a question of how you design your API.

In bindings/implementations for high-level languages (like dbus-python)
and bindings/implementations for low-level languages pretending to be
high-level via a runtime library (like GDBus), it's common to represent
both D-Bus error messages and locally-generated errors as an error object
or exception, whatever the language/runtime would normally use. For example,
dbus-python raises Python exceptions and GDBus raises GLib GErrors. In a
high-quality binding/implementation there'll usually be a way to extract
the D-Bus error name from the exception, so that you can match specific
errors by their machine-readable name if that makes sense in your
application.

> Now that I think about it though,
> can the daemon ever respond back with an error?

The dbus-daemon can respond to method calls with errors instead of
relaying them to a destination, yes. The system bus does this when it
needs to raise AccessDenied.

It can raise NoReply in two situations:

- the service that was meant to reply disconnected from the bus
  (e.g. crashed) before it had a chance to reply;

- the dbus-daemon has been configured to put a maximum timeout on
  all method calls (as I said, this has not been the default for a long
  time, but it is still possible to configure) and that timeout was reached

> Is there a list of
> well-known errors and who is responsible for generating the error?

The list of well-known errors is in dbus/dbus-protocol.h, but unfortunately
the circumstances in which each one is intended to be generated are not
really documented.

    smcv


More information about the dbus mailing list