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):
@dbus.service.method('com.example.HelloWorld',
in_signature='s', out_signature='s')
def SayHelloTo(self, target):
return 'Hello, %s!' % target
my_object = HelloWorld(dbus.SessionBus(), '/Hello')
my_object.SayHelloTo('world')
# 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.
Simon
More information about the dbus
mailing list