Re: EggDBus



On Tue, 2008-12-23 at 10:53 +0100, Murray Cumming wrote:
> On Mon, 2008-12-22 at 11:01 -0500, David Zeuthen wrote:
> 
> > you'll have to use the supplied QUERY_INTERFACE macro for each of the
> > generated interfaces to get an interface proxy. For example
> > 
> >  DevkitDevice *device;
> > 
> >  device = DEVKIT_QUERY_INTERFACE_DEVICE (object_proxy);
> [snip]
> 
> Ah, so you hard-code the expected interfaces at build time. And
> DEVKIT_QUERY_INTERFACE_DEVICE() won't check that the interface is really
> provided by that object, though you could get an error when then trying
> to call a function of that interface. 
> 
> That's unfortunately not very helpful for Telepathy, for which various
> "connection managers" (providers of IM functionality for particular IM
> protocols) may or may not implement various additional interfaces, so
> you have to check if those interfaces are available and fall back to
> alternatives when possible.
> 
> Not that I think that's a good situation (I like non-dynamic static
> typing), but I guess there's no established way of doing
> parallel-installs of D-Bus APIs, so they tend to evolve by adding
> interfaces to stable versions, with some lag before those interfaces are
> actually provided by everything that should implement them.
> 
> Anyway, this is not very relevant to you.

Yeah, I think Telepathy does this in a reasonable way; I've been doing
the same things with some of the D-Bus services that I've maintained;
occasionally a new D-Bus interface is added to an object. Typically,
clients just rev the version they depend on; obviously with Telepathy
this is harder as you communicate with software on another system (I
*think* this is the way it works).

Anyway, with EggDBus you'd just introspect the object before you start
consuming interfaces (see below).

It's possibly that QUERY_INTERFACE() isn't a good name (inspired by
COM); perhaps it could be GET_INTERFACE() and then we'd do a
QUERY_INTERFACE() version that can return NULL if the remote object
doesn't implement said interface. But I'm not happy to change that
because it's a nice property that the current QUERY_INTERFACE() does no
IO... and 99% of all D-Bus services guarantee that one interface or
another is always available. So I think it's OK to require a bit more
work there.

(FWIW, there's really no good section yet in the D-Bus spec that says
what it means to break ABI for D-Bus services (or more interesting, how
to extend an interface while preserving ABI) so most people just go with
what they think is right and usually this is correct.)

> > Interface proxies are created on demand; e.g. only when used. There's no
> > automatic discovery happening.. there is however an easy to use
> > introspection facility
> > 
> > http://people.freedesktop.org/~david/eggdbus-0.1-docs/EggDBusObjectProxy.html#egg-dbus-object-proxy-introspect
> > 
> > that you can use to discover the available interfaces of a remote
> > object.
> [snip]
> 
> From that documentation I couldn't tell where to actually get the
> introspected information once that call has finished.

You get a C structure like this one (by calling introspect_finish()
back:

http://people.freedesktop.org/~david/eggdbus-0.1-docs/eggdbus-eggdbusinterface.html#EggDBusInterfaceNodeInfo

that is built from parsing the XML and then you can walk the childs.
Incidentally, it's the same data structures we use to store
introspection data for generated code; see

http://people.freedesktop.org/~david/eggdbusproperties.c.txt

for an example.

Btw, is it a problem for non C (and probably non-C++) these are raw C
structures? It's done this way so it can be stored in the read-only data
segments.

> [snip]
> > > Isn't D-Bus property getting and setting asynchronous? How can this
> > work
> > > with the non-async g_object_get() function?
> > 
> > Right now the first property_get() call on an interface proxy will
> > synchronously invoke (blocking in libdbus on the dbus fd, not blocking
> > in the main loop because that would cause reentrancy issues) the
> > GetAll() method on the org.fd.DBus.Properties interface.
> [snip]
> 
> As you say, this does mean that it's particularly important for property
> getting to be fast in the D-Bus service, meaning, for instance, that a
> Telepathy object shouldn't get the information from a remote server.

Yeah. I *think* D-Bus properties are designed to be fast; I mean, I
think they are designed to mirror GObject and Qt properties and at least
these are designed to be fast.

If properties are not fast in Telepathy D-Bus services that might be a
problem not only for EggDBus, also for things like d-feet and possibly
for other D-Bus bindings that map to native properties, I don't know.
Either way, for such services there's always the raw EggBusProperties
interface.

> [snip]
> > Setting a property currently involves doing a sync call from
> > property_set() that blocks until the server acknowledges the write with
> > a reply.
> 
> The Telepathy coders seem to have a strong dislike for blocking sync
> D-Bus calls even when the call can be expected to complete quickly,
> though I think that's partly due to problems with their version of sync
> calls, and how they use the mainloop, as well as some D-Bus bugs:
> http://lists.freedesktop.org/archives/telepathy/2008-November/002520.html
> and
> http://lists.freedesktop.org/archives/telepathy/2008-November/002521.html
>  
> Again, that's not particularly relevant to you. I'm just mentioning it
> because I have my head in all this stuff at the moment.

Yeah, I think this is largely the same set of problems that Bonobo
suffered from (reentrancy) and the main reason libdbus doesn't block in
the mainloop.

FWIW, with EggDBus you have the option to do either kind of blocking

http://people.freedesktop.org/~david/eggdbus-0.1-docs/EggDBusConnection.html#EggDBusCallFlags

depending on what behavior you want (by default we don't block in the
mainloop which I think is the right behavior).

FWIW, I've toyed around with the idea of guarding sync methods behind a
EGG_DBUS_I_KNOW_SYNC_METHODS_ARE_UHM_SYNC_AND_THAT_THEY_BLOCK
preprocessor symbol or something but I don't think it would help. Also,
I don't think it would help by not generating sync methods (even though
some people think that sync methods shouldn't be exposed at all, not
even in things like GIO) either.

> >  I have a TODO item to make this async but it's hard (though not
> > impossible) to implement correctly because of coherency issues. Note
> > that there's very few services in the wild with writable properties.
> > 
> > For changes, there's unfortunately no Changed() signal on the official
> > org.fd.DBus.Properties interface. For now I'm using a signal called
> > EggDBusChanged()) on said interface (embrace and extend!); FWIW, I'm
> > going to propose the Changed() signal on the D-Bus list.
> [snip]
> 
> > [1] : I'd argue that if property get/set can fail, then the provider of
> > the D-Bus service is doing something wrong and it shouldn't be a
> > property in the first place. But, hey, things like this can happen.
> [snip]
> 
> I agree that D-Bus APIs should document restrictions on the behaviour of
> implementations, such as whether they can fail and how long they may
> take, allowing application code to be simpler by avoiding async calls.
> That's something else that Telepathy doesn't seem happy to do.

Well, sync calls are useful for a couple of reasons

 - For writing (simple) command-line clients (where the user can
   escape via Ctrl+C etc.)

 - It should be perfectly fine to use sync calls from a thread [1]

    David

[1] : Note that EggDBus isn't yet thread-safe/aware; it's on the TODO
list to figure out what guarantees / behavior we want to provide and
then implement it.

This task also includes taking a look at libdbus-1 sources to check that
a sync call from one thread won't stall the D-Bus queue in another
thread.




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]