19 Sep 2003 16:40:57 -0400
Thoughts on signals. The older way I was thinking of this was "message
matching", see this thread for example:
We should still keep in mind the FAM/gconf use-case where you want to
get notification for a sub-hierarchy of a larger hierarchy.
I. Protocol/spec level
Right now there's a message type "signal", so in the 1-to-1 case each
signal emission always sends a message to the peer, and in the message
bus case similarly plus all clients of the bus receive each signal.
Signals are fully async right now, including connections (since there
are no connections).
So here are some desirable properties of the signal mechanism; I do not
believe it's possible to get all of them at once.
1. no round trips when starting up an app in order to request a signal
2. don't put signals with no listeners on the wire at all
3. have the bus only forward signals to clients that actually care
4. have signal connections associated with the well-known service
instead of the client instance currently providing the service,
and also allow them to be associated with a single instance
5. have it work the same way with and without the message bus
Essentially what we're missing right now is optimization 2 and 3, we
have the rest of it. To get these optimizations there has to be a sense
of "connecting" which introduces a round trip (or possible silent
failure, if ignoring the return value) for each connection, and makes
the bus and 1-to-1 cases different.
The connection can be in the bus, or in the client doing the emitting,
or both. If in the bus you get optimization 3, if in the client you get
If we do connections in the bus only, then the client always sends its
emissions to the bus, the bus sends to interested clients. In the 1-to-1
case, the peer always gets all signals.
If we do connections in the client only, then the client would need to
track the services that were connected and do a multicast to them. So
there's significant state synced from the bus to the emitting client. In
the 1-to-1 case, the state is simply a refcount for each signal, where
count > 0 means to send it over the wire.
If we did both the basic idea is that if there's a bus connection the
bus tells the client to send out the signal, and otherwise the bus tells
the client not to. This could get complicated.
I am leaning toward connections in the bus only, client always sends all
signal emissions over the wire. Implementation will require libdbus to
be more aware of whether it's connected to a bus or just a single peer.
II. libdbus/API level
Say a signal emission message is received, "Frobated emitted by
/foo/bar/baz service org.blah.foo"
What handlers in the application process should receive that signal?
The idea I have is that you can connect handlers to a given signal, the
first time you do so the remote connection is set up, subsequently
you're just adding a handler not requesting that a new message be sent
from the bus.
What is a "handler" that you can connect? A C callback? Or an object
method in the sense of "something you could invoke via D-BUS? If an
object method, probably we have to synthesize a DBusMessage for the
method call for each handler.
Perhaps the bus-side connection could even _store_ a method name, and we
could say that clients never receive a signal, they only receive method
calls that have been connected to a signal. That is, we could synthesize
a message invoking the connected method on the bus side.
I lean toward the "C callback" answer though; it seems to me that
usually you don't want to have to be a D-BUS server/object in order to
handle notification messages.
Anyway, not totally happy with the options here but essentially my
thought is that to get signals from the bus you have to subscribe, in
1-to-1 you get all signals, and then the in-process API lets you specify
C callbacks to invoke when a particular signal arrives (and
automatically subscribes to any signals that have callbacks).