]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-bus: when installing a match make sure not to apply it to already queued messages
authorLennart Poettering <lennart@poettering.net>
Fri, 29 Mar 2019 14:43:40 +0000 (15:43 +0100)
committerLennart Poettering <lennart@poettering.net>
Thu, 11 Jul 2019 10:18:51 +0000 (12:18 +0200)
This tweaks match installation a bit: the match callbacks are now only
called for messages read after the AddMatch() reply was received and
never anything already read before. Thus, installing a match gives you a
time guarantee: only messages received after it will be matched.

This is useful when listening to PropertiesChanged signals as an example
to ensure that only changes after the point the match was installed are
honoured, nothing before.

src/libsystemd/sd-bus/bus-control.c
src/libsystemd/sd-bus/bus-control.h
src/libsystemd/sd-bus/bus-internal.h
src/libsystemd/sd-bus/bus-match.c
src/libsystemd/sd-bus/sd-bus.c

index f817cf0a850d49ba959339eb33fc0dbf8043b1fc..b7ca79bb583f5b999c2fba00a45936574ca6ea93 100644 (file)
@@ -803,9 +803,12 @@ _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **r
 
 int bus_add_match_internal(
                 sd_bus *bus,
-                const char *match) {
+                const char *match,
+                uint64_t *ret_counter) {
 
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
         const char *e;
+        int r;
 
         assert(bus);
 
@@ -814,16 +817,24 @@ int bus_add_match_internal(
 
         e = append_eavesdrop(bus, match);
 
-        return sd_bus_call_method(
+        r = sd_bus_call_method(
                         bus,
                         "org.freedesktop.DBus",
                         "/org/freedesktop/DBus",
                         "org.freedesktop.DBus",
                         "AddMatch",
                         NULL,
-                        NULL,
+                        &reply,
                         "s",
                         e);
+        if (r < 0)
+                return r;
+
+        /* If the caller asked for it, return the read counter of the reply */
+        if (ret_counter)
+                *ret_counter = reply->read_counter;
+
+        return r;
 }
 
 int bus_add_match_internal_async(
index 3fb52b67c6ad399aaead6661e3d1a628f0b788db..eb1ae75c147e784bf5d74879ed54d01c63c9491b 100644 (file)
@@ -3,7 +3,7 @@
 
 #include "sd-bus.h"
 
-int bus_add_match_internal(sd_bus *bus, const char *match);
+int bus_add_match_internal(sd_bus *bus, const char *match, uint64_t *ret_counter);
 int bus_add_match_internal_async(sd_bus *bus, sd_bus_slot **ret, const char *match, sd_bus_message_handler_t callback, void *userdata);
 
 int bus_remove_match_internal(sd_bus *bus, const char *match);
index f6289daac68485be88896cc0a8bc838ab7dd2d16..6d2c1e84051a8ac0df1f365b69a6ca973c7957a7 100644 (file)
@@ -44,6 +44,11 @@ struct match_callback {
 
         unsigned last_iteration;
 
+        /* Don't dispatch this slot with with messages that arrived in any iteration before or at the this
+         * one. We use this to ensure that matches don't apply "retroactively" and thus can confuse the
+         * caller: matches will only match incoming messages from the moment on the match was installed. */
+        uint64_t after;
+
         char *match_string;
 
         struct bus_match_node *match_node;
index 14204eeb6b2d35ea614515d6467d69df9c393c9f..57ce8cca0439bf1dce0669ccbc5608c601aee0ef 100644 (file)
@@ -287,8 +287,16 @@ int bus_match_run(
         case BUS_MATCH_LEAF:
 
                 if (bus) {
-                        if (node->leaf.callback->last_iteration == bus->iteration_counter)
-                                return 0;
+                        /* Don't run this match as long as the AddMatch() call is not complete yet.
+                         *
+                         * Don't run this match unless the 'after' counter has been reached.
+                         *
+                         * Don't run this match more than once per iteration */
+
+                        if (node->leaf.callback->install_slot ||
+                            m->read_counter <= node->leaf.callback->after ||
+                            node->leaf.callback->last_iteration == bus->iteration_counter)
+                                return bus_match_run(bus, node->next, m);
 
                         node->leaf.callback->last_iteration = bus->iteration_counter;
                 }
index 5b624d51ed03bb185b1bfa6a67a94cac77ed7fec..303dcea106ff2f3a63950d75f3b9d074ebcf1328 100644 (file)
@@ -3327,7 +3327,7 @@ static int bus_add_match_full(
                                  * then make it floating. */
                                 r = sd_bus_slot_set_floating(s->match_callback.install_slot, true);
                         } else
-                                r = bus_add_match_internal(bus, s->match_callback.match_string);
+                                r = bus_add_match_internal(bus, s->match_callback.match_string, &s->match_callback.after);
                         if (r < 0)
                                 goto finish;