D-Bus is killing me

Simon McVittie simon.mcvittie at collabora.co.uk
Sun Dec 17 17:27:07 PST 2006

On Mon, 18 Dec 2006 at 00:25:23 +0000, Mystilleef wrote:
> My application, a text editor, can spawn multiple instances of itself.
> I use D-Bus to ensure all instances use the same process. I also use
> D-Bus for inter-instance communication.

The "unique process, running it again opens a new window in the same process"
idiom is an appropriate use of D-Bus; Epiphany, for one, uses it. However,
I'm not clear on why you're using an inter-process communication mechanism
for intra-process communication.

> For example, via D-Bus I can
> show users all open documents, and allow them to manipulate the
> documents (e.g close a specific document, focus a specific document
> window, close all running instances, switch quickly between documents etc).
> Perhaps my D-Bus usage is unconventional and uncommon.

Yes, it is, if I understand correctly. There's nothing wrong with
exposing this sort of functionality on the D-Bus so other processes can
"remote-control" yours, but when you're making calls within a process,
there seems to be no point in marshalling arguments, sending a message to
the bus daemon, receiving a message from the bus daemon, unmarshalling
arguments, and then doing the whole lot again for the reply, when you
could just make a local function call.

One sensible approach would be to have a single process and make local
calls between "instances" if they need to interact. Another would be to
have a process per "instance", all communicating via D-Bus. Which to use
depends how much your "instances" interact. Your approach seems to be
giving you the worst of both worlds - are you actually gaining anything
from having all your "instances" in a single process space?

Hint: in dbus-python you can call exported methods of a dbus.service.Object
locally by just calling the method on it: despite the @method decorator,
it's still available as a normal Python method, as if the decorator
wasn't present. For example:

	class HelloWorld(dbus.service.Object):
			in_signature='s', out_signature='s')
		def SayHelloTo(self, target):
			return 'Hello, %s!' % target

	my_object = HelloWorld(dbus.SessionBus(), '/Hello')

	# returns 'Hello, world!' without going via D-Bus

For signals you could either use D-Bus signals, Python callbacks, or
GLib signals.

> All these work
> for the most part, but they can be unreliable. For example, when stress
> testing my application I quickly realized, D-Bus begins to error out
> (or crash, can't remember) after spawning a hundred instances of my
> application.

Each Connection can only have some limited number of method calls in
progress at a time (this is a policy in the bus daemon, to prevent a
buggy program from causing denial of service for the whole session).
The error message is something like "Limit on number of pending calls
reached" - you'll immediately get that thrown as a DBusException from
each method call above the limit.

> Another problem I had is that instances of my application
> were still responding to signals, even after they were no longer in
> use.

When you register a signal handler, the Connection references the callback,
preventing the callback from being garbage-collected. In the common case
where the callback is actually an object method, this indirectly references
the object and prevents that from being GC'd either. I would guess that
GLib does the same for signal handlers and other callbacks.

(A scheme where the callback is weakly referenced, and the signal
handler silently de-registers when the object goes away, is harder than
you might think - there'd have to be an ugly special case for bound
methods, which are in practice what receive signals 90% of the time,
and I don't want to make dbus-python's semantics any more complicated
than they already are.)

In dbus-python 0.80 rc releases, it's certainly possible to disconnect
signal handlers. There's even a unit test.

Before 0.80 I'm honestly not sure whether signal handler disconnection works
or not; the code appears to support it, but I've seen dbus-python apps
that include workarounds for it not working. This may have been a historical
bug that's long since been fixed.


More information about the dbus mailing list