about signals

Havoc Pennington hp at redhat.com
Fri May 28 08:05:06 PDT 2004


On Thu, 2004-05-27 at 19:09, Olivier Andrieu wrote:
> 
> Well I don't known, you agreed « that's a bit odd » and then you said
> having the client setting the sender « makes their API all fugly »,
> which didn't quite convince me :)

Well, there were a couple of more substantive points ;-)

In particular the issue of accidentally talking to multiple remote apps
thinking you are talking to the same one. D-BUS deliberately makes
explicit connection/disconnection and supports lifecycle tracking. This
avoids race condition mess.

> The way I see it, services are not conceptually different from object
> paths and interfaces, it's part of the naming of a remote piece of
> code: service designates an application (process), the path designates
> an object (whatever that means in the language the remote application
> was written in), the interface + member name designates a method in
> the object. 

This isn't right though. The reason a well-known service is different is
that a base service name, object path, and interface uniquely and
exclusively identify an object. There are not "aliases"

A well-known service is not unique, apps can own any number of them.
i.e. a well-known service is effectively a "symlink"

Here's a concrete example. Say we have a KUniqueApplication equivalent
in D-BUS, that is an interface used to open a document. There is a
global object in the app with a method like OpenDocument().

Now, the app may own the services org.freedesktop.TextEditor and
org.freedesktop.HTMLEditor. Using *either* of these services, you can
call OpenDocument.

Now further imagine that this interface has some sort of signal -
DocumentOpened, I don't know. The problem if you include the service
name in the signal is *which service name do you include*

If you have service names in signals, then your object paths and
interfaces have to become per-service-name to get sane semantics where
each object is found under exactly one service name.

If you do this then services become "directories" or "folders" for
objects; in fact a service is pretty equivalent to prepending another 
element to the front of the object path.

>  > This would be more or less equivalent to the idea of a service. If you
>  > connected to the socket blah.Blah you'd expect it to be a particular
>  > daemon, but you wouldn't expect to use the name blah.Blah on an ongoing
>  > basis as you talk to it.
> 
> Well I would. Why not ? When I'm browsing pages at freedesktop.org,
> I'm using this name on an ongoing basis (viewing
> freedesktop.org/Software/Home, freedesktop.org/Software/dbus, etc.)
> even though that's just a way to 'locate' 131.252.208.82 .

That's because http is not a stateful protocol and you have to reconnect
every time ;-)

If you just connected once, it would be like ftp; you use the address to
connect, then you issue commands.

> Anyway, the problem is about 'connecting' signals. The way the glib
> API works right now is to present proxies to a service + object +
> interface triplet.

Remember there are two ways to do the proxy, one monitors the well-known
name (even as the owner of that name changes) and one monitors the
unique base service name.

Monitoring the well-known name is just a shortcut/optimization to avoid
recreating the proxy every time the service owner changes.

> So, we could avoid this redundant check which happens in _all_
> listeners and replace it by requiring the emitter to fill in the
> service (and the bus would continue its check to see if the emitter is
> not lying about its service ownership).

Except for the problem that the emitter has 0-N services, rather than 1
service! That's really what keeps this from working:

> and we would have:
> DBusMessage* dbus_message_new_signal        (const char  *service,
>                                              const char  *path,
>                                              const char  *interface,
>                                              const char  *name);
> 


_Which_ service?

Services are intended to be used like X selections, they are a resource
that the app can acquire to become "the" text editor rather than "a"
text editor.

So even if I know that this signal is only used via the TextEditor
service, there may be 5 apps all trying to claim the TextEditor service,
and I may or may not own it. I shouldn't be unable to emit the signal in
that case, since someone may still want to interact with my specific
text editor application - perhaps for example GEdit has _the_ TextEditor
service, but OpenOffice.org also supports the same interface with the
same signals. Or maybe 3 instances of GEdit are running, or one GEdit
and one KWrite. You can't stop emitting signals when you don't own the
service.

Also, a concern I have is that with DCOP people are frequently
auto-exporting remote interfaces for lots of objects. In that case
there's no sensible service name.

>  A method call never needs to use a unique name as
> its destination service: the way an application learns about unique
> names is through service announcements messages or activation
> messages. So it's always linked with a real service name.

Ideally, we would *always* use the unique name once we know what it is.

To be semantically clean we would do:

   unique_name = get_owner (well_known_name);

   invoke_method (unique_name);

The reason this gets reduced to:
 
   invoke_method (well_known_name);

is 1) an optimization to avoid round trips and 2) because sometimes you
don't care if the owner of well_known_name is not the same as it was
last time you performed a method call on that name.

>  Conversely,
> an application would be required to own a service before sending a
> signal. Simple rule: you need a real service name to send, either a
> message or a signal.

Here's another example. Say we want to do the accessibility interfaces
via D-BUS. Each application would export some standard global objects
with standard interfaces.

There's no sensible service for these apps to own (and in any case only
one of them could own it). We just have a fixed interface that we want
_all_ apps to support, and the interface will include signals.

>  > Remember signal emission/listening is supposed to work without a bus
>  > daemon at all, in the context of just a direct 1-to-1 connection.
>  > In that scenario the equivalent of keying your listener code off the
>  > service would be changing behavior depending on whether you connected to
>  > "host", "host.bar.com", or "localhost" to establish the connection.
> 
> I'm not sure I understand this. Services are about the bus routing
> and/or dropping messages, i.e. all service-dependent handling is done
> in the bus dameon. In the 1-to-1 case messages alway go directly to
> the peer. 

In the 1-to-1 case requiring someone to specify a service in order to
emit a signal would not make any sense.

Another way to phrase this is that service names should only be involved
in locating objects (creating the proxy), not in using objects. If you
have service names involved in using the proxy, then the proxy interface
is bus-specific and doesn't make sense for 1-to-1.

Havoc





More information about the dbus mailing list