[systemd-devel] [RFC] bus: add sd_bus_emit_object_{added, removed}()

David Herrmann dh.herrmann at gmail.com
Tue Mar 11 11:40:06 PDT 2014


Hi

On Tue, Mar 11, 2014 at 7:27 PM, Lennart Poettering
<lennart at poettering.net> wrote:
> On Tue, 18.02.14 00:02, David Herrmann (dh.herrmann at gmail.com) wrote:
>
> Sorry for the late review!
>
>> However, on object_removed() I cannot do that as node_vtable_get_userdata() is
>> very likely to return "0" for all these objects. So there is no way to figure
>> out which interfaces actually existed on that thing. We would require users to
>> call it *before* destroying/unlinking the actual object. I don't know whether
>> that's ok to assume?
>
> I would assume that it is OK to assume that. People should call this
> function before half-destroying their object. I mean we are not reading
> the properties after all, just the interfaces and I think that should be
> quite OK to require.
>
> Certainly something to document though one day...

Yepp, will add docs once I commit it.

>> +static int object_added_append_all_prefix(
>> +                sd_bus *bus,
>> +                sd_bus_message *m,
>> +                Set *s,
>> +                const char *prefix,
>> +                const char *path,
>> +                bool require_fallback) {
>> +
>
>> +                if (!streq_ptr(c->interface, previous_interface)) {
>> +                        /* interface already handled by a previous run? */
>> +                        if (set_get(s, c->interface))
>> +                                continue;
>
> We actually allow multiple vtables with the same interface, and order
> them together in the vtable list, so that we can iterate through them
> easily with trivial duplicate reduction. Keeping a Set object here
> appears unnecessary? Or did I miss something here?

A single call to object_added_append_all_prefix() doesn't need "Set
*s" as it's ordered (as you said). The problem is more subtle, see
object_added_append_all(), where I do this:

+        r = object_added_append_all_prefix(bus, m, s, path, path, false);
+        if (r < 0)
+                return r;
+        if (bus->nodes_modified)
+                return 0;
+
+        prefix = alloca(strlen(path) + 1);
+        OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
+                r = object_added_append_all_prefix(bus, m, s, prefix,
path, true);
+                if (r < 0)
+                        return r;
+                if (bus->nodes_modified)
+                        return 0;
+        }

First I call append_all_prefix() with the exact path, which cannot
ever fire the "if (set_get())" protection, as it's the first run.
However, the prefix-runs which I do afterwards will traverse the
parents, which might *also* implement the interface. They use
"require_fallback == true", so usually we're fine. However, if you
implement an interface explicitly on a child, but as fallback on the
parents, I _must_ avoid adding the interface twice. At least that's my
understanding of the vtable API, or should these be merged?
I looked at interfaces_added_append_one(), which skips parents if the
node already implements the interface. Therefore, I assumed I have to
skip parents, too. But I still need to traverse the parents, because
they might implement different interfaces that I haven't found, yet.

Thanks
David


More information about the systemd-devel mailing list