chiark / gitweb /
sd-bus: introduce sd_bus_slot objects encapsulating callbacks or vtables attached...
authorLennart Poettering <lennart@poettering.net>
Wed, 14 May 2014 23:15:30 +0000 (01:15 +0200)
committerLennart Poettering <lennart@poettering.net>
Wed, 14 May 2014 23:15:30 +0000 (01:15 +0200)
This makes callback behaviour more like sd-event or sd-resolve, and
creates proper object for unregistering callbacks.

Taking the refernce to the slot is optional. If not taken life time of
the slot will be bound to the underlying bus object (or in the case of
an async call until the reply has been recieved).

34 files changed:
Makefile.am
src/bus-proxyd/bus-proxyd.c
src/core/dbus.c
src/hostname/hostnamed.c
src/libsystemd/libsystemd.sym.m4
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/bus-match.h
src/libsystemd/sd-bus/bus-objects.c
src/libsystemd/sd-bus/bus-objects.h
src/libsystemd/sd-bus/bus-slot.c [new file with mode: 0644]
src/libsystemd/sd-bus/bus-slot.h [new file with mode: 0644]
src/libsystemd/sd-bus/bus-track.c
src/libsystemd/sd-bus/bus-util.c
src/libsystemd/sd-bus/bus-util.h
src/libsystemd/sd-bus/busctl.c
src/libsystemd/sd-bus/sd-bus.c
src/libsystemd/sd-bus/test-bus-chat.c
src/libsystemd/sd-bus/test-bus-kernel-bloom.c
src/libsystemd/sd-bus/test-bus-kernel.c
src/libsystemd/sd-bus/test-bus-match.c
src/libsystemd/sd-bus/test-bus-objects.c
src/locale/localed.c
src/login/logind-seat-dbus.c
src/login/logind-session-dbus.c
src/login/logind-user-dbus.c
src/login/logind.c
src/machine/machine-dbus.c
src/machine/machined.c
src/network/networkd-link.c
src/systemctl/systemctl.c
src/systemd/sd-bus.h
src/timedate/timedated.c

index 653fcfc..89b1d4e 100644 (file)
@@ -2119,6 +2119,8 @@ libsystemd_internal_la_SOURCES = \
        src/libsystemd/sd-bus/bus-track.h \
        src/libsystemd/sd-bus/bus-util.c \
        src/libsystemd/sd-bus/bus-util.h \
+       src/libsystemd/sd-bus/bus-slot.c \
+       src/libsystemd/sd-bus/bus-slot.h \
        src/libsystemd/sd-bus/bus-protocol.h \
        src/libsystemd/sd-bus/kdbus.h \
        src/libsystemd/sd-bus/sd-memfd.c \
index c5f9f00..e095d61 100644 (file)
@@ -40,6 +40,7 @@
 #include "bus-internal.h"
 #include "bus-message.h"
 #include "bus-util.h"
+#include "bus-internal.h"
 #include "build.h"
 #include "strv.h"
 #include "def.h"
@@ -551,7 +552,7 @@ static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) {
                 if (r < 0)
                         return synthetic_reply_method_errno(m, r, NULL);
 
-                r = sd_bus_add_match(a, match, NULL, NULL);
+                r = sd_bus_add_match(a, NULL, match, NULL, NULL);
                 if (r < 0)
                         return synthetic_reply_method_errno(m, r, NULL);
 
@@ -564,7 +565,9 @@ static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) {
                 if (r < 0)
                         return synthetic_reply_method_errno(m, r, NULL);
 
-                r = sd_bus_remove_match(a, match, NULL, NULL);
+                r = bus_remove_match_by_string(a, match, NULL, NULL);
+                if (r == 0)
+                        return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_MATCH_RULE_NOT_FOUND, "Match rule not found"));
                 if (r < 0)
                         return synthetic_reply_method_errno(m, r, NULL);
 
@@ -739,9 +742,10 @@ static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) {
                 r = sd_bus_release_name(a, name);
                 if (r < 0) {
                         if (r == -ESRCH)
-                                synthetic_reply_method_return(m, "u", BUS_NAME_NON_EXISTENT);
+                                return synthetic_reply_method_return(m, "u", BUS_NAME_NON_EXISTENT);
                         if (r == -EADDRINUSE)
-                                synthetic_reply_method_return(m, "u", BUS_NAME_NOT_OWNER);
+                                return synthetic_reply_method_return(m, "u", BUS_NAME_NOT_OWNER);
+
                         return synthetic_reply_method_errno(m, r, NULL);
                 }
 
@@ -1177,7 +1181,7 @@ int main(int argc, char *argv[]) {
                         goto finish;
                 }
 
-                r = sd_bus_add_match(a, match, NULL, NULL);
+                r = sd_bus_add_match(a, NULL, match, NULL, NULL);
                 if (r < 0) {
                         log_error("Failed to add match for NameLost: %s", strerror(-r));
                         goto finish;
@@ -1198,7 +1202,7 @@ int main(int argc, char *argv[]) {
                         goto finish;
                 }
 
-                r = sd_bus_add_match(a, match, NULL, NULL);
+                r = sd_bus_add_match(a, NULL, match, NULL, NULL);
                 if (r < 0) {
                         log_error("Failed to add match for NameAcquired: %s", strerror(-r));
                         goto finish;
index 189d925..fb8e496 100644 (file)
@@ -310,7 +310,7 @@ static int find_unit(Manager *m, sd_bus *bus, const char *path, Unit **unit, sd_
                 sd_bus_message *message;
                 pid_t pid;
 
-                message = sd_bus_get_current(bus);
+                message = sd_bus_get_current_message(bus);
                 if (!message)
                         return 0;
 
@@ -536,58 +536,58 @@ static int bus_setup_api_vtables(Manager *m, sd_bus *bus) {
         assert(bus);
 
 #ifdef HAVE_SELINUX
-        r = sd_bus_add_filter(bus, selinux_filter, m);
+        r = sd_bus_add_filter(bus, NULL, selinux_filter, m);
         if (r < 0) {
                 log_error("Failed to add SELinux access filter: %s", strerror(-r));
                 return r;
         }
 #endif
 
-        r = sd_bus_add_object_vtable(bus, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", bus_manager_vtable, m);
+        r = sd_bus_add_object_vtable(bus, NULL, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", bus_manager_vtable, m);
         if (r < 0) {
                 log_error("Failed to register Manager vtable: %s", strerror(-r));
                 return r;
         }
 
-        r = sd_bus_add_fallback_vtable(bus, "/org/freedesktop/systemd1/job", "org.freedesktop.systemd1.Job", bus_job_vtable, bus_job_find, m);
+        r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/job", "org.freedesktop.systemd1.Job", bus_job_vtable, bus_job_find, m);
         if (r < 0) {
                 log_error("Failed to register Job vtable: %s", strerror(-r));
                 return r;
         }
 
-        r = sd_bus_add_node_enumerator(bus, "/org/freedesktop/systemd1/job", bus_job_enumerate, m);
+        r = sd_bus_add_node_enumerator(bus, NULL, "/org/freedesktop/systemd1/job", bus_job_enumerate, m);
         if (r < 0) {
                 log_error("Failed to add job enumerator: %s", strerror(-r));
                 return r;
         }
 
-        r = sd_bus_add_fallback_vtable(bus, "/org/freedesktop/systemd1/unit", "org.freedesktop.systemd1.Unit", bus_unit_vtable, bus_unit_find, m);
+        r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", "org.freedesktop.systemd1.Unit", bus_unit_vtable, bus_unit_find, m);
         if (r < 0) {
                 log_error("Failed to register Unit vtable: %s", strerror(-r));
                 return r;
         }
 
-        r = sd_bus_add_node_enumerator(bus, "/org/freedesktop/systemd1/unit", bus_unit_enumerate, m);
+        r = sd_bus_add_node_enumerator(bus, NULL, "/org/freedesktop/systemd1/unit", bus_unit_enumerate, m);
         if (r < 0) {
                 log_error("Failed to add job enumerator: %s", strerror(-r));
                 return r;
         }
 
         for (t = 0; t < _UNIT_TYPE_MAX; t++) {
-                r = sd_bus_add_fallback_vtable(bus, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, unit_vtable[t]->bus_vtable, bus_unit_interface_find, m);
+                r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, unit_vtable[t]->bus_vtable, bus_unit_interface_find, m);
                 if (r < 0)  {
                         log_error("Failed to register type specific vtable for %s: %s", unit_vtable[t]->bus_interface, strerror(-r));
                         return r;
                 }
 
                 if (unit_vtable[t]->cgroup_context_offset > 0) {
-                        r = sd_bus_add_fallback_vtable(bus, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_unit_cgroup_vtable, bus_unit_cgroup_find, m);
+                        r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_unit_cgroup_vtable, bus_unit_cgroup_find, m);
                         if (r < 0) {
                                 log_error("Failed to register control group unit vtable for %s: %s", unit_vtable[t]->bus_interface, strerror(-r));
                                 return r;
                         }
 
-                        r = sd_bus_add_fallback_vtable(bus, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_cgroup_vtable, bus_cgroup_context_find, m);
+                        r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_cgroup_vtable, bus_cgroup_context_find, m);
                         if (r < 0) {
                                 log_error("Failed to register control group vtable for %s: %s", unit_vtable[t]->bus_interface, strerror(-r));
                                 return r;
@@ -595,7 +595,7 @@ static int bus_setup_api_vtables(Manager *m, sd_bus *bus) {
                 }
 
                 if (unit_vtable[t]->exec_context_offset > 0) {
-                        r = sd_bus_add_fallback_vtable(bus, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_exec_vtable, bus_exec_context_find, m);
+                        r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_exec_vtable, bus_exec_context_find, m);
                         if (r < 0) {
                                 log_error("Failed to register execute vtable for %s: %s", unit_vtable[t]->bus_interface, strerror(-r));
                                 return r;
@@ -603,7 +603,7 @@ static int bus_setup_api_vtables(Manager *m, sd_bus *bus) {
                 }
 
                 if (unit_vtable[t]->kill_context_offset > 0) {
-                        r = sd_bus_add_fallback_vtable(bus, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_kill_vtable, bus_kill_context_find, m);
+                        r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_kill_vtable, bus_kill_context_find, m);
                         if (r < 0) {
                                 log_error("Failed to register kill vtable for %s: %s", unit_vtable[t]->bus_interface, strerror(-r));
                                 return r;
@@ -622,6 +622,7 @@ static int bus_setup_disconnected_match(Manager *m, sd_bus *bus) {
 
         r = sd_bus_add_match(
                         bus,
+                        NULL,
                         "sender='org.freedesktop.DBus.Local',"
                         "type='signal',"
                         "path='/org/freedesktop/DBus/Local',"
@@ -710,6 +711,7 @@ static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void
 
                 r = sd_bus_add_match(
                                 bus,
+                                NULL,
                                 "type='signal',"
                                 "interface='org.freedesktop.systemd1.Agent',"
                                 "member='Released',"
@@ -780,6 +782,7 @@ static int bus_setup_api(Manager *m, sd_bus *bus) {
 
         r = sd_bus_add_match(
                         bus,
+                        NULL,
                         "type='signal',"
                         "sender='org.freedesktop.DBus',"
                         "path='/org/freedesktop/DBus',"
@@ -791,6 +794,7 @@ static int bus_setup_api(Manager *m, sd_bus *bus) {
 
         r = sd_bus_add_match(
                         bus,
+                        NULL,
                         "type='signal',"
                         "sender='org.freedesktop.DBus',"
                         "path='/org/freedesktop/DBus',"
@@ -874,6 +878,7 @@ static int bus_setup_system(Manager *m, sd_bus *bus) {
          * the system bus */
         r = sd_bus_add_match(
                         bus,
+                        NULL,
                         "type='signal',"
                         "interface='org.freedesktop.systemd1.Agent',"
                         "member='Released',"
index 2be6dcd..48cbbdb 100644 (file)
@@ -591,7 +591,7 @@ static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) {
                 return r;
         }
 
-        r = sd_bus_add_object_vtable(bus, "/org/freedesktop/hostname1", "org.freedesktop.hostname1", hostname_vtable, c);
+        r = sd_bus_add_object_vtable(bus, NULL, "/org/freedesktop/hostname1", "org.freedesktop.hostname1", hostname_vtable, c);
         if (r < 0) {
                 log_error("Failed to register object: %s", strerror(-r));
                 return r;
index 14d9dcf..7545ae4 100644 (file)
@@ -173,7 +173,6 @@ m4_ifdef(`ENABLE_KDBUS',
         sd_bus_send_to;
         sd_bus_call;
         sd_bus_call_async;
-        sd_bus_call_async_cancel;
         sd_bus_get_fd;
         sd_bus_get_events;
         sd_bus_get_timeout;
@@ -181,27 +180,26 @@ m4_ifdef(`ENABLE_KDBUS',
         sd_bus_process_priority;
         sd_bus_wait;
         sd_bus_flush;
-        sd_bus_get_current;
+        sd_bus_get_current_message;
+        sd_bus_get_current_slot;
         sd_bus_get_tid;
         sd_bus_attach_event;
         sd_bus_detach_event;
         sd_bus_get_event;
         sd_bus_add_filter;
-        sd_bus_remove_filter;
         sd_bus_add_match;
-        sd_bus_remove_match;
         sd_bus_add_object;
-        sd_bus_remove_object;
         sd_bus_add_fallback;
-        sd_bus_remove_fallback;
         sd_bus_add_object_vtable;
-        sd_bus_remove_object_vtable;
         sd_bus_add_fallback_vtable;
-        sd_bus_remove_fallback_vtable;
         sd_bus_add_node_enumerator;
-        sd_bus_remove_node_enumerator;
         sd_bus_add_object_manager;
-        sd_bus_remove_object_manager;
+        sd_bus_slot_ref;
+        sd_bus_slot_unref;
+        sd_bus_slot_get_bus;
+        sd_bus_slot_get_userdata;
+        sd_bus_slot_set_userdata;
+        sd_bus_slot_get_current_message;
         sd_bus_message_new_signal;
         sd_bus_message_new_method_call;
         sd_bus_message_new_method_return;
index 420e091..aa290ed 100644 (file)
@@ -22,6 +22,7 @@
 ***/
 
 #include "sd-bus.h"
+#include "bus-match.h"
 
 int bus_add_match_internal(sd_bus *bus, const char *match, struct bus_match_component *components, unsigned n_components, uint64_t cookie);
 int bus_remove_match_internal(sd_bus *bus, const char *match, uint64_t cookie);
index 3dceb8a..042d352 100644 (file)
@@ -40,7 +40,6 @@
 
 struct reply_callback {
         sd_bus_message_handler_t callback;
-        void *userdata;
         usec_t timeout;
         uint64_t cookie;
         unsigned prioq_idx;
@@ -48,13 +47,23 @@ struct reply_callback {
 
 struct filter_callback {
         sd_bus_message_handler_t callback;
-        void *userdata;
 
         unsigned last_iteration;
 
         LIST_FIELDS(struct filter_callback, callbacks);
 };
 
+struct match_callback {
+        sd_bus_message_handler_t callback;
+
+        uint64_t cookie;
+        unsigned last_iteration;
+
+        char *match_string;
+
+        struct bus_match_node *match_node;
+};
+
 struct node {
         char *path;
         struct node *parent;
@@ -64,8 +73,7 @@ struct node {
         LIST_HEAD(struct node_callback, callbacks);
         LIST_HEAD(struct node_vtable, vtables);
         LIST_HEAD(struct node_enumerator, enumerators);
-
-        bool object_manager;
+        LIST_HEAD(struct node_object_manager, object_managers);
 };
 
 struct node_callback {
@@ -73,7 +81,6 @@ struct node_callback {
 
         bool is_fallback;
         sd_bus_message_handler_t callback;
-        void *userdata;
 
         unsigned last_iteration;
 
@@ -84,20 +91,24 @@ struct node_enumerator {
         struct node *node;
 
         sd_bus_node_enumerator_t callback;
-        void *userdata;
 
         unsigned last_iteration;
 
         LIST_FIELDS(struct node_enumerator, enumerators);
 };
 
+struct node_object_manager {
+        struct node *node;
+
+        LIST_FIELDS(struct node_object_manager, object_managers);
+};
+
 struct node_vtable {
         struct node *node;
 
         char *interface;
         bool is_fallback;
         const sd_bus_vtable *vtable;
-        void *userdata;
         sd_bus_object_find_t find;
 
         unsigned last_iteration;
@@ -114,6 +125,37 @@ struct vtable_member {
         const sd_bus_vtable *vtable;
 };
 
+typedef enum BusSlotType {
+        _BUS_SLOT_DISCONNECTED,
+        BUS_REPLY_CALLBACK,
+        BUS_FILTER_CALLBACK,
+        BUS_MATCH_CALLBACK,
+        BUS_NODE_CALLBACK,
+        BUS_NODE_ENUMERATOR,
+        BUS_NODE_VTABLE,
+        BUS_NODE_OBJECT_MANAGER,
+} BusSlotType;
+
+struct sd_bus_slot {
+        unsigned n_ref;
+        sd_bus *bus;
+        void *userdata;
+        BusSlotType type;
+        bool floating;
+
+        LIST_FIELDS(sd_bus_slot, slots);
+
+        union {
+                struct reply_callback reply_callback;
+                struct filter_callback filter_callback;
+                struct match_callback match_callback;
+                struct node_callback node_callback;
+                struct node_enumerator node_enumerator;
+                struct node_object_manager node_object_manager;
+                struct node_vtable node_vtable;
+        };
+};
+
 enum bus_state {
         BUS_UNSET,
         BUS_OPENING,
@@ -231,7 +273,6 @@ struct sd_bus {
         char *exec_path;
         char **exec_argv;
 
-        uint64_t hello_cookie;
         unsigned iteration_counter;
 
         void *kdbus_buffer;
@@ -260,7 +301,8 @@ struct sd_bus {
         sd_event *event;
         int event_priority;
 
-        sd_bus_message *current;
+        sd_bus_message *current_message;
+        sd_bus_slot *current_slot;
 
         sd_bus **default_bus_ptr;
         pid_t tid;
@@ -276,6 +318,8 @@ struct sd_bus {
         unsigned bloom_n_hash;
 
         sd_bus_track *track_queue;
+
+        LIST_HEAD(sd_bus_slot, slots);
 };
 
 #define BUS_DEFAULT_TIMEOUT ((usec_t) (25 * USEC_PER_SEC))
@@ -340,3 +384,5 @@ int bus_set_address_system(sd_bus *bus);
 int bus_set_address_user(sd_bus *bus);
 int bus_set_address_system_remote(sd_bus *b, const char *host);
 int bus_set_address_system_container(sd_bus *b, const char *machine);
+
+int bus_remove_match_by_string(sd_bus *bus, const char *match, sd_bus_message_handler_t callback, void *userdata);
index c54ca8d..b868159 100644 (file)
@@ -116,6 +116,9 @@ static void bus_match_node_free(struct bus_match_node *node) {
 static bool bus_match_node_maybe_free(struct bus_match_node *node) {
         assert(node);
 
+        if (node->type == BUS_MATCH_ROOT)
+                return false;
+
         if (node->child)
                 return false;
 
@@ -275,10 +278,10 @@ int bus_match_run(
         case BUS_MATCH_LEAF:
 
                 if (bus) {
-                        if (node->leaf.last_iteration == bus->iteration_counter)
+                        if (node->leaf.callback->last_iteration == bus->iteration_counter)
                                 return 0;
 
-                        node->leaf.last_iteration = bus->iteration_counter;
+                        node->leaf.callback->last_iteration = bus->iteration_counter;
                 }
 
                 r = sd_bus_message_rewind(m, true);
@@ -287,9 +290,17 @@ int bus_match_run(
 
                 /* Run the callback. And then invoke siblings. */
                 if (node->leaf.callback) {
+                        sd_bus_slot *slot;
+
                         _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
 
-                        r = node->leaf.callback(bus, m, node->leaf.userdata, &error_buffer);
+                        slot = container_of(node->leaf.callback, sd_bus_slot, match_callback);
+                        if (bus)
+                                bus->current_slot = slot;
+                        r = node->leaf.callback->callback(bus, m, slot->userdata, &error_buffer);
+                        if (bus)
+                                bus->current_slot = NULL;
+
                         r = bus_maybe_reply_error(m, r, &error_buffer);
                         if (r != 0)
                                 return r;
@@ -535,16 +546,13 @@ static int bus_match_find_compare_value(
 
 static int bus_match_add_leaf(
                 struct bus_match_node *where,
-                sd_bus_message_handler_t callback,
-                void *userdata,
-                uint64_t cookie,
-                struct bus_match_node **ret) {
+                struct match_callback *callback) {
 
         struct bus_match_node *n;
 
         assert(where);
         assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
-        assert(ret);
+        assert(callback);
 
         n = new0(struct bus_match_node, 1);
         if (!n)
@@ -555,13 +563,12 @@ static int bus_match_add_leaf(
         n->next = where->child;
         if (n->next)
                 n->next->prev = n;
+
         n->leaf.callback = callback;
-        n->leaf.userdata = userdata;
-        n->leaf.cookie = cookie;
+        callback->match_node = n;
 
         where->child = n;
 
-        *ret = n;
         return 1;
 }
 
@@ -578,9 +585,13 @@ static int bus_match_find_leaf(
         assert(ret);
 
         for (c = where->child; c; c = c->next) {
+                sd_bus_slot *s;
+
+                s = container_of(c->leaf.callback, sd_bus_slot, match_callback);
+
                 if (c->type == BUS_MATCH_LEAF &&
-                    c->leaf.callback == callback &&
-                    c->leaf.userdata == userdata) {
+                    c->leaf.callback->callback == callback &&
+                    s->userdata == userdata) {
                         *ret = c;
                         return 1;
                 }
@@ -892,16 +903,14 @@ int bus_match_add(
                 struct bus_match_node *root,
                 struct bus_match_component *components,
                 unsigned n_components,
-                sd_bus_message_handler_t callback,
-                void *userdata,
-                uint64_t cookie,
-                struct bus_match_node **ret) {
+                struct match_callback *callback) {
 
         unsigned i;
         struct bus_match_node *n;
         int r;
 
         assert(root);
+        assert(callback);
 
         n = root;
         for (i = 0; i < n_components; i++) {
@@ -912,29 +921,56 @@ int bus_match_add(
                         return r;
         }
 
-        r = bus_match_add_leaf(n, callback, userdata, cookie, &n);
-        if (r < 0)
-                return r;
+        return bus_match_add_leaf(n, callback);
+}
 
-        if (ret)
-                *ret = n;
+int bus_match_remove(
+                struct bus_match_node *root,
+                struct match_callback *callback) {
 
-        return 0;
+        struct bus_match_node *node, *pp;
+
+        assert(root);
+        assert(callback);
+
+        node = callback->match_node;
+        if (!node)
+                return 0;
+
+        assert(node->type == BUS_MATCH_LEAF);
+
+        callback->match_node = NULL;
+
+        /* Free the leaf */
+        pp = node->parent;
+        bus_match_node_free(node);
+
+        /* Prune the tree above */
+        while (pp) {
+                node = pp;
+                pp = node->parent;
+
+                if (!bus_match_node_maybe_free(node))
+                        break;
+        }
+
+        return 1;
 }
 
-int bus_match_remove(
+int bus_match_find(
                 struct bus_match_node *root,
                 struct bus_match_component *components,
                 unsigned n_components,
                 sd_bus_message_handler_t callback,
                 void *userdata,
-                uint64_t *cookie) {
+                struct match_callback **ret) {
 
-        unsigned i;
         struct bus_match_node *n, **gc;
+        unsigned i;
         int r;
 
         assert(root);
+        assert(ret);
 
         gc = newa(struct bus_match_node*, n_components);
 
@@ -954,24 +990,8 @@ int bus_match_remove(
         if (r <= 0)
                 return r;
 
-        if (cookie)
-                *cookie = n->leaf.cookie;
-
-        /* Free the leaf */
-        bus_match_node_free(n);
-
-        /* Prune the tree above */
-        for (i = n_components; i > 0; i --) {
-                struct bus_match_node *p = gc[i-1]->parent;
-
-                if (!bus_match_node_maybe_free(gc[i-1]))
-                        break;
-
-                if (!bus_match_node_maybe_free(p))
-                        break;
-        }
-
-        return r;
+        *ret = n->leaf.callback;
+        return 1;
 }
 
 void bus_match_free(struct bus_match_node *node) {
@@ -1065,7 +1085,7 @@ void bus_match_dump(struct bus_match_node *node, unsigned level) {
         } else if (node->type == BUS_MATCH_ROOT)
                 puts(" root");
         else if (node->type == BUS_MATCH_LEAF)
-                printf(" %p/%p\n", node->leaf.callback, node->leaf.userdata);
+                printf(" %p/%p\n", node->leaf.callback->callback, container_of(node->leaf.callback, sd_bus_slot, match_callback)->userdata);
         else
                 putchar('\n');
 
index 056082b..af5f65d 100644 (file)
@@ -58,10 +58,7 @@ struct bus_match_node {
                         uint8_t u8;
                 } value;
                 struct {
-                        sd_bus_message_handler_t callback;
-                        void *userdata;
-                        unsigned last_iteration;
-                        uint64_t cookie;
+                        struct match_callback *callback;
                 } leaf;
                 struct {
                         /* If this is set, then the child is NULL */
@@ -78,8 +75,10 @@ struct bus_match_component {
 
 int bus_match_run(sd_bus *bus, struct bus_match_node *root, sd_bus_message *m);
 
-int bus_match_add(struct bus_match_node *root, struct bus_match_component *components, unsigned n_components, sd_bus_message_handler_t callback, void *userdata, uint64_t cookie, struct bus_match_node **ret);
-int bus_match_remove(struct bus_match_node *root, struct bus_match_component *components, unsigned n_components, sd_bus_message_handler_t callback, void *userdata, uint64_t *cookie);
+int bus_match_add(struct bus_match_node *root, struct bus_match_component *components, unsigned n_components, struct match_callback *callback);
+int bus_match_remove(struct bus_match_node *root, struct match_callback *callback);
+
+int bus_match_find(struct bus_match_node *root, struct bus_match_component *components, unsigned n_components, sd_bus_message_handler_t callback, void *userdata, struct match_callback **ret);
 
 void bus_match_free(struct bus_match_node *node);
 
index 8b12e89..f160e23 100644 (file)
@@ -28,8 +28,9 @@
 #include "bus-type.h"
 #include "bus-signature.h"
 #include "bus-introspect.h"
-#include "bus-objects.h"
 #include "bus-util.h"
+#include "bus-slot.h"
+#include "bus-objects.h"
 
 static int node_vtable_get_userdata(
                 sd_bus *bus,
@@ -38,6 +39,7 @@ static int node_vtable_get_userdata(
                 void **userdata,
                 sd_bus_error *error) {
 
+        sd_bus_slot *s;
         void *u;
         int r;
 
@@ -45,9 +47,13 @@ static int node_vtable_get_userdata(
         assert(path);
         assert(c);
 
-        u = c->userdata;
+        s = container_of(c, sd_bus_slot, node_vtable);
+        u = s->userdata;
         if (c->find) {
+                bus->current_slot = s;
                 r = c->find(bus, path, c->interface, u, &u, error);
+                bus->current_slot = NULL;
+
                 if (r < 0)
                         return r;
                 if (sd_bus_error_is_set(error))
@@ -113,7 +119,10 @@ static int add_enumerated_to_set(
                 if (bus->nodes_modified)
                         return 0;
 
-                r = c->callback(bus, prefix, c->userdata, &children, error);
+                bus->current_slot = container_of(c, sd_bus_slot, node_enumerator);
+                r = c->callback(bus, prefix, bus->current_slot->userdata, &children, error);
+                bus->current_slot = NULL;
+
                 if (r < 0)
                         return r;
                 if (sd_bus_error_is_set(error))
@@ -257,7 +266,10 @@ static int node_callbacks_run(
                 if (r < 0)
                         return r;
 
-                r = c->callback(bus, m, c->userdata, &error_buffer);
+                bus->current_slot = container_of(c, sd_bus_slot, node_callback);
+                r = c->callback(bus, m, bus->current_slot->userdata, &error_buffer);
+                bus->current_slot = NULL;
+
                 r = bus_maybe_reply_error(m, r, &error_buffer);
                 if (r != 0)
                         return r;
@@ -382,7 +394,11 @@ static int method_callbacks_run(
         m->enforced_reply_signature = strempty(c->vtable->x.method.result);
 
         if (c->vtable->x.method.handler) {
+
+                bus->current_slot = container_of(c->parent, sd_bus_slot, node_vtable);
                 r = c->vtable->x.method.handler(bus, m, u, &error);
+                bus->current_slot = NULL;
+
                 return bus_maybe_reply_error(m, r, &error);
         }
 
@@ -396,6 +412,7 @@ static int method_callbacks_run(
 
 static int invoke_property_get(
                 sd_bus *bus,
+                sd_bus_slot *slot,
                 const sd_bus_vtable *v,
                 const char *path,
                 const char *interface,
@@ -408,6 +425,7 @@ static int invoke_property_get(
         int r;
 
         assert(bus);
+        assert(slot);
         assert(v);
         assert(path);
         assert(interface);
@@ -415,7 +433,11 @@ static int invoke_property_get(
         assert(reply);
 
         if (v->x.property.get) {
+
+                bus->current_slot = slot;
                 r = v->x.property.get(bus, path, interface, property, reply, userdata, error);
+                bus->current_slot = NULL;
+
                 if (r < 0)
                         return r;
                 if (sd_bus_error_is_set(error))
@@ -453,6 +475,7 @@ static int invoke_property_get(
 
 static int invoke_property_set(
                 sd_bus *bus,
+                sd_bus_slot *slot,
                 const sd_bus_vtable *v,
                 const char *path,
                 const char *interface,
@@ -464,6 +487,7 @@ static int invoke_property_set(
         int r;
 
         assert(bus);
+        assert(slot);
         assert(v);
         assert(path);
         assert(interface);
@@ -471,7 +495,11 @@ static int invoke_property_set(
         assert(value);
 
         if (v->x.property.set) {
+
+                bus->current_slot = slot;
                 r = v->x.property.set(bus, path, interface, property, value, userdata, error);
+                bus->current_slot = NULL;
+
                 if (r < 0)
                         return r;
                 if (sd_bus_error_is_set(error))
@@ -527,6 +555,7 @@ static int property_get_set_callbacks_run(
 
         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+        sd_bus_slot *slot;
         void *u = NULL;
         int r;
 
@@ -544,6 +573,8 @@ static int property_get_set_callbacks_run(
         if (bus->nodes_modified)
                 return 0;
 
+        slot = container_of(c->parent, sd_bus_slot, node_vtable);
+
         *found_object = true;
 
         r = sd_bus_message_new_method_return(m, &reply);
@@ -567,7 +598,7 @@ static int property_get_set_callbacks_run(
                  * PropertiesChanged signals broadcast contents
                  * anyway. */
 
-                r = invoke_property_get(bus, c->vtable, m->path, c->interface, c->member, reply, u, &error);
+                r = invoke_property_get(bus, slot, c->vtable, m->path, c->interface, c->member, reply, u, &error);
                 if (r < 0)
                         return bus_maybe_reply_error(m, r, &error);
 
@@ -598,7 +629,7 @@ static int property_get_set_callbacks_run(
                 if (r < 0)
                         return bus_maybe_reply_error(m, r, &error);
 
-                r = invoke_property_set(bus, c->vtable, m->path, c->interface, c->member, m, u, &error);
+                r = invoke_property_set(bus, slot, c->vtable, m->path, c->interface, c->member, m, u, &error);
                 if (r < 0)
                         return bus_maybe_reply_error(m, r, &error);
 
@@ -626,6 +657,7 @@ static int vtable_append_one_property(
                 void *userdata,
                 sd_bus_error *error) {
 
+        sd_bus_slot *slot;
         int r;
 
         assert(bus);
@@ -646,7 +678,9 @@ static int vtable_append_one_property(
         if (r < 0)
                 return r;
 
-        r = invoke_property_get(bus, v, path, c->interface, v->x.property.member, reply, vtable_property_convert_userdata(v, userdata), error);
+        slot = container_of(c, sd_bus_slot, node_vtable);
+
+        r = invoke_property_get(bus, slot, v, path, c->interface, v->x.property.member, reply, vtable_property_convert_userdata(v, userdata), error);
         if (r < 0)
                 return r;
         if (bus->nodes_modified)
@@ -783,7 +817,7 @@ static bool bus_node_with_object_manager(sd_bus *bus, struct node *n) {
         assert(bus);
         assert(n);
 
-        if (n->object_manager)
+        if (n->object_managers)
                 return true;
 
         if (n->parent)
@@ -827,7 +861,7 @@ static bool bus_node_exists(
                         return false;
         }
 
-        return !require_fallback && (n->enumerators || n->object_manager);
+        return !require_fallback && (n->enumerators || n->object_managers);
 }
 
 static int process_introspect(
@@ -1421,7 +1455,7 @@ static struct node *bus_node_allocate(sd_bus *bus, const char *path) {
         return n;
 }
 
-static void bus_node_gc(sd_bus *b, struct node *n) {
+void bus_node_gc(sd_bus *b, struct node *n) {
         assert(b);
 
         if (!n)
@@ -1431,7 +1465,7 @@ static void bus_node_gc(sd_bus *b, struct node *n) {
             n->callbacks ||
             n->vtables ||
             n->enumerators ||
-            n->object_manager)
+            n->object_managers)
                 return;
 
         assert(hashmap_remove(b->nodes, n->path) == n);
@@ -1446,12 +1480,13 @@ static void bus_node_gc(sd_bus *b, struct node *n) {
 
 static int bus_add_object(
                 sd_bus *bus,
+                sd_bus_slot **slot,
                 bool fallback,
                 const char *path,
                 sd_bus_message_handler_t callback,
                 void *userdata) {
 
-        struct node_callback *c;
+        sd_bus_slot *s;
         struct node *n;
         int r;
 
@@ -1464,136 +1499,49 @@ static int bus_add_object(
         if (!n)
                 return -ENOMEM;
 
-        c = new0(struct node_callback, 1);
-        if (!c) {
+        s = bus_slot_allocate(bus, !slot, BUS_NODE_CALLBACK, sizeof(struct node_callback), userdata);
+        if (!s) {
                 r = -ENOMEM;
                 goto fail;
         }
 
-        c->node = n;
-        c->callback = callback;
-        c->userdata = userdata;
-        c->is_fallback = fallback;
+        s->node_callback.callback = callback;
+        s->node_callback.is_fallback = fallback;
 
-        LIST_PREPEND(callbacks, n->callbacks, c);
+        s->node_callback.node = n;
+        LIST_PREPEND(callbacks, n->callbacks, &s->node_callback);
         bus->nodes_modified = true;
 
+        if (slot)
+                *slot = s;
+
         return 0;
 
 fail:
-        free(c);
+        sd_bus_slot_unref(s);
         bus_node_gc(bus, n);
+
         return r;
 }
 
-static int bus_remove_object(
+_public_ int sd_bus_add_object(
                 sd_bus *bus,
-                bool fallback,
+                sd_bus_slot **slot,
                 const char *path,
                 sd_bus_message_handler_t callback,
                 void *userdata) {
 
-        struct node_callback *c;
-        struct node *n;
-
-        assert_return(bus, -EINVAL);
-        assert_return(object_path_is_valid(path), -EINVAL);
-        assert_return(callback, -EINVAL);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        n = hashmap_get(bus->nodes, path);
-        if (!n)
-                return 0;
-
-        LIST_FOREACH(callbacks, c, n->callbacks)
-                if (c->callback == callback && c->userdata == userdata && c->is_fallback == fallback)
-                        break;
-        if (!c)
-                return 0;
-
-        LIST_REMOVE(callbacks, n->callbacks, c);
-        free(c);
-
-        bus_node_gc(bus, n);
-        bus->nodes_modified = true;
-
-        return 1;
-}
-
-_public_ int sd_bus_add_object(sd_bus *bus,
-                               const char *path,
-                               sd_bus_message_handler_t callback,
-                               void *userdata) {
-
-        return bus_add_object(bus, false, path, callback, userdata);
-}
-
-_public_ int sd_bus_remove_object(sd_bus *bus,
-                                  const char *path,
-                                  sd_bus_message_handler_t callback,
-                                  void *userdata) {
-
-        return bus_remove_object(bus, false, path, callback, userdata);
-}
-
-_public_ int sd_bus_add_fallback(sd_bus *bus,
-                                 const char *prefix,
-                                 sd_bus_message_handler_t callback,
-                                 void *userdata) {
-
-        return bus_add_object(bus, true, prefix, callback, userdata);
-}
-
-_public_ int sd_bus_remove_fallback(sd_bus *bus,
-                                    const char *prefix,
-                                    sd_bus_message_handler_t callback,
-                                    void *userdata) {
-
-        return bus_remove_object(bus, true, prefix, callback, userdata);
+        return bus_add_object(bus, slot, false, path, callback, userdata);
 }
 
-static void free_node_vtable(sd_bus *bus, struct node_vtable *w) {
-        assert(bus);
-
-        if (!w)
-                return;
-
-        if (w->interface && w->node && w->vtable) {
-                const sd_bus_vtable *v;
-
-                for (v = w->vtable; v->type != _SD_BUS_VTABLE_END; v++) {
-                        struct vtable_member *x = NULL;
-
-                        switch (v->type) {
-
-                        case _SD_BUS_VTABLE_METHOD: {
-                                struct vtable_member key;
-
-                                key.path = w->node->path;
-                                key.interface = w->interface;
-                                key.member = v->x.method.member;
-
-                                x = hashmap_remove(bus->vtable_methods, &key);
-                                break;
-                        }
-
-                        case _SD_BUS_VTABLE_PROPERTY:
-                        case _SD_BUS_VTABLE_WRITABLE_PROPERTY: {
-                                struct vtable_member key;
-
-                                key.path = w->node->path;
-                                key.interface = w->interface;
-                                key.member = v->x.property.member;
-                                x = hashmap_remove(bus->vtable_properties, &key);
-                                break;
-                        }}
-
-                        free(x);
-                }
-        }
+_public_ int sd_bus_add_fallback(
+                sd_bus *bus,
+                sd_bus_slot **slot,
+                const char *prefix,
+                sd_bus_message_handler_t callback,
+                void *userdata) {
 
-        free(w->interface);
-        free(w);
+        return bus_add_object(bus, slot, true, prefix, callback, userdata);
 }
 
 static unsigned long vtable_member_hash_func(const void *a, const uint8_t hash_key[HASH_KEY_SIZE]) {
@@ -1637,6 +1585,7 @@ static int vtable_member_compare_func(const void *a, const void *b) {
 
 static int add_object_vtable_internal(
                 sd_bus *bus,
+                sd_bus_slot **slot,
                 const char *path,
                 const char *interface,
                 const sd_bus_vtable *vtable,
@@ -1644,7 +1593,8 @@ static int add_object_vtable_internal(
                 sd_bus_object_find_t find,
                 void *userdata) {
 
-        struct node_vtable *c = NULL, *i, *existing = NULL;
+        sd_bus_slot *s;
+        struct node_vtable *i, *existing = NULL;
         const sd_bus_vtable *v;
         struct node *n;
         int r;
@@ -1690,25 +1640,23 @@ static int add_object_vtable_internal(
                 }
         }
 
-        c = new0(struct node_vtable, 1);
-        if (!c) {
+        s = bus_slot_allocate(bus, !slot, BUS_NODE_VTABLE, sizeof(struct node_vtable), userdata);
+        if (!s) {
                 r = -ENOMEM;
                 goto fail;
         }
 
-        c->node = n;
-        c->is_fallback = fallback;
-        c->vtable = vtable;
-        c->userdata = userdata;
-        c->find = find;
+        s->node_vtable.is_fallback = fallback;
+        s->node_vtable.vtable = vtable;
+        s->node_vtable.find = find;
 
-        c->interface = strdup(interface);
-        if (!c->interface) {
+        s->node_vtable.interface = strdup(interface);
+        if (!s->node_vtable.interface) {
                 r = -ENOMEM;
                 goto fail;
         }
 
-        for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
+        for (v = s->node_vtable.vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
 
                 switch (v->type) {
 
@@ -1730,9 +1678,9 @@ static int add_object_vtable_internal(
                                 goto fail;
                         }
 
-                        m->parent = c;
+                        m->parent = &s->node_vtable;
                         m->path = n->path;
-                        m->interface = c->interface;
+                        m->interface = s->node_vtable.interface;
                         m->member = v->x.method.member;
                         m->vtable = v;
 
@@ -1773,9 +1721,9 @@ static int add_object_vtable_internal(
                                 goto fail;
                         }
 
-                        m->parent = c;
+                        m->parent = &s->node_vtable;
                         m->path = n->path;
-                        m->interface = c->interface;
+                        m->interface = s->node_vtable.interface;
                         m->member = v->x.property.member;
                         m->vtable = v;
 
@@ -1805,110 +1753,53 @@ static int add_object_vtable_internal(
                 }
         }
 
-        LIST_INSERT_AFTER(vtables, n->vtables, existing, c);
+        s->node_vtable.node = n;
+        LIST_INSERT_AFTER(vtables, n->vtables, existing, &s->node_vtable);
         bus->nodes_modified = true;
 
+        if (slot)
+                *slot = s;
+
         return 0;
 
 fail:
-        if (c)
-                free_node_vtable(bus, c);
-
-        bus_node_gc(bus, n);
-        return r;
-}
-
-static int remove_object_vtable_internal(
-                sd_bus *bus,
-                const char *path,
-                const char *interface,
-                const sd_bus_vtable *vtable,
-                bool fallback,
-                sd_bus_object_find_t find,
-                void *userdata) {
-
-        struct node_vtable *c;
-        struct node *n;
-
-        assert_return(bus, -EINVAL);
-        assert_return(object_path_is_valid(path), -EINVAL);
-        assert_return(interface_name_is_valid(interface), -EINVAL);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        n = hashmap_get(bus->nodes, path);
-        if (!n)
-                return 0;
-
-        LIST_FOREACH(vtables, c, n->vtables)
-                if (streq(c->interface, interface) &&
-                    c->is_fallback == fallback &&
-                    c->vtable == vtable &&
-                    c->find == find &&
-                    c->userdata == userdata)
-                        break;
-
-        if (!c)
-                return 0;
-
-        LIST_REMOVE(vtables, n->vtables, c);
-
-        free_node_vtable(bus, c);
+        sd_bus_slot_unref(s);
         bus_node_gc(bus, n);
 
-        bus->nodes_modified = true;
-
-        return 1;
+        return r;
 }
 
 _public_ int sd_bus_add_object_vtable(
                 sd_bus *bus,
+                sd_bus_slot **slot,
                 const char *path,
                 const char *interface,
                 const sd_bus_vtable *vtable,
                 void *userdata) {
 
-        return add_object_vtable_internal(bus, path, interface, vtable, false, NULL, userdata);
-}
-
-_public_ int sd_bus_remove_object_vtable(
-                sd_bus *bus,
-                const char *path,
-                const char *interface,
-                const sd_bus_vtable *vtable,
-                void *userdata) {
-
-        return remove_object_vtable_internal(bus, path, interface, vtable, false, NULL, userdata);
+        return add_object_vtable_internal(bus, slot, path, interface, vtable, false, NULL, userdata);
 }
 
 _public_ int sd_bus_add_fallback_vtable(
                 sd_bus *bus,
-                const char *path,
-                const char *interface,
-                const sd_bus_vtable *vtable,
-                sd_bus_object_find_t find,
-                void *userdata) {
-
-        return add_object_vtable_internal(bus, path, interface, vtable, true, find, userdata);
-}
-
-_public_ int sd_bus_remove_fallback_vtable(
-                sd_bus *bus,
-                const char *path,
+                sd_bus_slot **slot,
+                const char *prefix,
                 const char *interface,
                 const sd_bus_vtable *vtable,
                 sd_bus_object_find_t find,
                 void *userdata) {
 
-        return remove_object_vtable_internal(bus, path, interface, vtable, true, find, userdata);
+        return add_object_vtable_internal(bus, slot, prefix, interface, vtable, true, find, userdata);
 }
 
 _public_ int sd_bus_add_node_enumerator(
                 sd_bus *bus,
+                sd_bus_slot **slot,
                 const char *path,
                 sd_bus_node_enumerator_t callback,
                 void *userdata) {
 
-        struct node_enumerator *c;
+        sd_bus_slot *s;
         struct node *n;
         int r;
 
@@ -1921,61 +1812,28 @@ _public_ int sd_bus_add_node_enumerator(
         if (!n)
                 return -ENOMEM;
 
-        c = new0(struct node_enumerator, 1);
-        if (!c) {
+        s = bus_slot_allocate(bus, !slot, BUS_NODE_ENUMERATOR, sizeof(struct node_enumerator), userdata);
+        if (!s) {
                 r = -ENOMEM;
                 goto fail;
         }
 
-        c->node = n;
-        c->callback = callback;
-        c->userdata = userdata;
-
-        LIST_PREPEND(enumerators, n->enumerators, c);
+        s->node_enumerator.callback = callback;
 
+        s->node_enumerator.node = n;
+        LIST_PREPEND(enumerators, n->enumerators, &s->node_enumerator);
         bus->nodes_modified = true;
 
+        if (slot)
+                *slot = s;
+
         return 0;
 
 fail:
-        free(c);
-        bus_node_gc(bus, n);
-        return r;
-}
-
-_public_ int sd_bus_remove_node_enumerator(
-                sd_bus *bus,
-                const char *path,
-                sd_bus_node_enumerator_t callback,
-                void *userdata) {
-
-        struct node_enumerator *c;
-        struct node *n;
-
-        assert_return(bus, -EINVAL);
-        assert_return(object_path_is_valid(path), -EINVAL);
-        assert_return(callback, -EINVAL);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        n = hashmap_get(bus->nodes, path);
-        if (!n)
-                return 0;
-
-        LIST_FOREACH(enumerators, c, n->enumerators)
-                if (c->callback == callback && c->userdata == userdata)
-                        break;
-
-        if (!c)
-                return 0;
-
-        LIST_REMOVE(enumerators, n->enumerators, c);
-        free(c);
-
+        sd_bus_slot_unref(s);
         bus_node_gc(bus, n);
 
-        bus->nodes_modified = true;
-
-        return 1;
+        return r;
 }
 
 static int emit_properties_changed_on_interface(
@@ -2481,8 +2339,10 @@ _public_ int sd_bus_emit_interfaces_removed(sd_bus *bus, const char *path, const
         return sd_bus_emit_interfaces_removed_strv(bus, path, interfaces);
 }
 
-_public_ int sd_bus_add_object_manager(sd_bus *bus, const char *path) {
+_public_ int sd_bus_add_object_manager(sd_bus *bus, sd_bus_slot **slot, const char *path) {
+        sd_bus_slot *s;
         struct node *n;
+        int r;
 
         assert_return(bus, -EINVAL);
         assert_return(object_path_is_valid(path), -EINVAL);
@@ -2492,28 +2352,24 @@ _public_ int sd_bus_add_object_manager(sd_bus *bus, const char *path) {
         if (!n)
                 return -ENOMEM;
 
-        n->object_manager = true;
-        bus->nodes_modified = true;
-        return 0;
-}
-
-_public_ int sd_bus_remove_object_manager(sd_bus *bus, const char *path) {
-        struct node *n;
+        s = bus_slot_allocate(bus, !slot, BUS_NODE_OBJECT_MANAGER, sizeof(struct node_object_manager), NULL);
+        if (!s) {
+                r = -ENOMEM;
+                goto fail;
+        }
 
-        assert_return(bus, -EINVAL);
-        assert_return(object_path_is_valid(path), -EINVAL);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
+        s->node_object_manager.node = n;
+        LIST_PREPEND(object_managers, n->object_managers, &s->node_object_manager);
+        bus->nodes_modified = true;
 
-        n = hashmap_get(bus->nodes, path);
-        if (!n)
-                return 0;
+        if (slot)
+                *slot = s;
 
-        if (!n->object_manager)
-                return 0;
+        return 0;
 
-        n->object_manager = false;
-        bus->nodes_modified = true;
+fail:
+        sd_bus_slot_unref(s);
         bus_node_gc(bus, n);
 
-        return 1;
+        return r;
 }
index 420edd9..4373fae 100644 (file)
@@ -24,3 +24,4 @@
 #include "bus-internal.h"
 
 int bus_process_object(sd_bus *bus, sd_bus_message *m);
+void bus_node_gc(sd_bus *b, struct node *n);
diff --git a/src/libsystemd/sd-bus/bus-slot.c b/src/libsystemd/sd-bus/bus-slot.c
new file mode 100644 (file)
index 0000000..8e38992
--- /dev/null
@@ -0,0 +1,244 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2013 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "sd-bus.h"
+#include "bus-control.h"
+#include "bus-objects.h"
+#include "bus-slot.h"
+
+sd_bus_slot *bus_slot_allocate(
+                sd_bus *bus,
+                bool floating,
+                BusSlotType type,
+                size_t extra,
+                void *userdata) {
+
+        sd_bus_slot *slot;
+
+        assert(bus);
+
+        slot = malloc0(offsetof(sd_bus_slot, reply_callback) + extra);
+        if (!slot)
+                return NULL;
+
+        slot->n_ref = 1;
+        slot->type = type;
+        slot->bus = bus;
+        slot->floating = floating;
+        slot->userdata = userdata;
+
+        if (!floating)
+                sd_bus_ref(bus);
+
+        LIST_PREPEND(slots, bus->slots, slot);
+
+        return slot;
+}
+
+_public_ sd_bus_slot* sd_bus_slot_ref(sd_bus_slot *slot) {
+        assert_return(slot, NULL);
+
+        assert(slot->n_ref > 0);
+
+        slot->n_ref++;
+        return slot;
+}
+
+void bus_slot_disconnect(sd_bus_slot *slot) {
+        sd_bus *bus;
+
+        assert(slot);
+
+        switch (slot->type) {
+
+        case _BUS_SLOT_DISCONNECTED:
+                /* Already disconnected... */
+                return;
+
+        case BUS_REPLY_CALLBACK:
+
+                if (slot->reply_callback.cookie != 0)
+                        hashmap_remove(slot->bus->reply_callbacks, &slot->reply_callback.cookie);
+
+                if (slot->reply_callback.timeout != 0)
+                        prioq_remove(slot->bus->reply_callbacks_prioq, &slot->reply_callback, &slot->reply_callback.prioq_idx);
+
+                break;
+
+        case BUS_FILTER_CALLBACK:
+                slot->bus->filter_callbacks_modified = true;
+                LIST_REMOVE(callbacks, slot->bus->filter_callbacks, &slot->filter_callback);
+                break;
+
+        case BUS_MATCH_CALLBACK:
+
+                if (slot->bus->bus_client)
+                        bus_remove_match_internal(slot->bus, slot->match_callback.match_string, slot->match_callback.cookie);
+
+                slot->bus->match_callbacks_modified = true;
+                bus_match_remove(&slot->bus->match_callbacks, &slot->match_callback);
+
+                free(slot->match_callback.match_string);
+
+                break;
+
+        case BUS_NODE_CALLBACK:
+
+                if (slot->node_callback.node) {
+                        LIST_REMOVE(callbacks, slot->node_callback.node->callbacks, &slot->node_callback);
+                        slot->bus->nodes_modified = true;
+
+                        bus_node_gc(slot->bus, slot->node_callback.node);
+                }
+
+                break;
+
+        case BUS_NODE_ENUMERATOR:
+
+                if (slot->node_enumerator.node) {
+                        LIST_REMOVE(enumerators, slot->node_enumerator.node->enumerators, &slot->node_enumerator);
+                        slot->bus->nodes_modified = true;
+
+                        bus_node_gc(slot->bus, slot->node_enumerator.node);
+                }
+
+                break;
+
+        case BUS_NODE_OBJECT_MANAGER:
+
+                if (slot->node_object_manager.node) {
+                        LIST_REMOVE(object_managers, slot->node_object_manager.node->object_managers, &slot->node_object_manager);
+                        slot->bus->nodes_modified = true;
+
+                        bus_node_gc(slot->bus, slot->node_object_manager.node);
+                }
+
+                break;
+
+        case BUS_NODE_VTABLE:
+
+                if (slot->node_vtable.node && slot->node_vtable.interface && slot->node_vtable.vtable) {
+                        const sd_bus_vtable *v;
+
+                        for (v = slot->node_vtable.vtable; v->type != _SD_BUS_VTABLE_END; v++) {
+                                struct vtable_member *x = NULL;
+
+                                switch (v->type) {
+
+                                case _SD_BUS_VTABLE_METHOD: {
+                                        struct vtable_member key;
+
+                                        key.path = slot->node_vtable.node->path;
+                                        key.interface = slot->node_vtable.interface;
+                                        key.member = v->x.method.member;
+
+                                        x = hashmap_remove(slot->bus->vtable_methods, &key);
+                                        break;
+                                }
+
+                                case _SD_BUS_VTABLE_PROPERTY:
+                                case _SD_BUS_VTABLE_WRITABLE_PROPERTY: {
+                                        struct vtable_member key;
+
+                                        key.path = slot->node_vtable.node->path;
+                                        key.interface = slot->node_vtable.interface;
+                                        key.member = v->x.method.member;
+
+
+                                        x = hashmap_remove(slot->bus->vtable_properties, &key);
+                                        break;
+                                }}
+
+                                free(x);
+                        }
+                }
+
+                free(slot->node_vtable.interface);
+
+                if (slot->node_vtable.node) {
+                        LIST_REMOVE(vtables, slot->node_vtable.node->vtables, &slot->node_vtable);
+                        slot->bus->nodes_modified = true;
+
+                        bus_node_gc(slot->bus, slot->node_vtable.node);
+                }
+
+                break;
+        }
+        bus = slot->bus;
+
+        slot->type = _BUS_SLOT_DISCONNECTED;
+        slot->bus = NULL;
+        LIST_REMOVE(slots, bus->slots, slot);
+
+        if (!slot->floating)
+                sd_bus_unref(bus);
+}
+
+_public_ sd_bus_slot* sd_bus_slot_unref(sd_bus_slot *slot) {
+
+        if (!slot)
+                return NULL;
+
+        assert(slot->n_ref > 0);
+
+        if (slot->n_ref > 1) {
+                slot->n_ref --;
+                return NULL;
+        }
+
+        bus_slot_disconnect(slot);
+        free(slot);
+
+        return NULL;
+}
+
+_public_ sd_bus* sd_bus_slot_get_bus(sd_bus_slot *slot) {
+        assert_return(slot, NULL);
+
+        return slot->bus;
+}
+
+_public_ void *sd_bus_slot_get_userdata(sd_bus_slot *slot) {
+        assert_return(slot, NULL);
+
+        return slot->userdata;
+}
+
+_public_ void *sd_bus_slot_set_userdata(sd_bus_slot *slot, void *userdata) {
+        void *ret;
+
+        assert_return(slot, NULL);
+
+        ret = slot->userdata;
+        slot->userdata = userdata;
+
+        return ret;
+}
+
+_public_ sd_bus_message *sd_bus_slot_get_current_message(sd_bus_slot *slot) {
+        assert_return(slot, NULL);
+        assert_return(slot->type != _BUS_SLOT_DISCONNECTED, NULL);
+
+        if (slot->bus->current_slot != slot)
+                return NULL;
+
+        return slot->bus->current_message;
+}
diff --git a/src/libsystemd/sd-bus/bus-slot.h b/src/libsystemd/sd-bus/bus-slot.h
new file mode 100644 (file)
index 0000000..23a15e4
--- /dev/null
@@ -0,0 +1,29 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2014 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "sd-bus.h"
+#include "bus-internal.h"
+
+sd_bus_slot *bus_slot_allocate(sd_bus *bus, bool floating, BusSlotType type, size_t extra, void *userdata);
+
+void bus_slot_disconnect(sd_bus_slot *slot);
index 0f6a2ea..ffa2cf3 100644 (file)
@@ -21,6 +21,7 @@
 
 #include "sd-bus.h"
 #include "set.h"
+#include "bus-util.h"
 #include "bus-internal.h"
 #include "bus-track.h"
 
@@ -29,7 +30,7 @@ struct sd_bus_track {
         sd_bus *bus;
         sd_bus_track_handler_t handler;
         void *userdata;
-        Set *names;
+        Hashmap *names;
         LIST_FIELDS(sd_bus_track, queue);
         Iterator iterator;
         bool in_queue;
@@ -128,11 +129,11 @@ _public_ sd_bus_track* sd_bus_track_unref(sd_bus_track *track) {
                 return NULL;
         }
 
-        while ((n = set_first(track->names)))
+        while ((n = hashmap_first_key(track->names)))
                 sd_bus_track_remove_name(track, n);
 
         bus_track_remove_from_queue(track);
-        set_free(track->names);
+        hashmap_free(track->names);
         sd_bus_unref(track->bus);
         free(track);
 
@@ -157,6 +158,7 @@ static int on_name_owner_changed(sd_bus *bus, sd_bus_message *message, void *use
 }
 
 _public_ int sd_bus_track_add_name(sd_bus_track *track, const char *name) {
+        _cleanup_bus_slot_unref_ sd_bus_slot *slot = NULL;
         _cleanup_free_ char *n = NULL;
         const char *match;
         int r;
@@ -164,7 +166,7 @@ _public_ int sd_bus_track_add_name(sd_bus_track *track, const char *name) {
         assert_return(track, -EINVAL);
         assert_return(service_name_is_valid(name), -EINVAL);
 
-        r = set_ensure_allocated(&track->names, string_hash_func, string_compare_func);
+        r = hashmap_ensure_allocated(&track->names, string_hash_func, string_compare_func);
         if (r < 0)
                 return r;
 
@@ -172,30 +174,28 @@ _public_ int sd_bus_track_add_name(sd_bus_track *track, const char *name) {
         if (!n)
                 return -ENOMEM;
 
-        r = set_put(track->names, n);
+        /* First, subscribe to this name */
+        match = MATCH_FOR_NAME(n);
+        r = sd_bus_add_match(track->bus, &slot, match, on_name_owner_changed, track);
+        if (r < 0)
+                return r;
+
+        r = hashmap_put(track->names, n, slot);
         if (r == -EEXIST)
                 return 0;
         if (r < 0)
                 return r;
 
-        /* First, subscribe to this name */
-        match = MATCH_FOR_NAME(name);
-        r = sd_bus_add_match(track->bus, match, on_name_owner_changed, track);
-        if (r < 0) {
-                set_remove(track->names, n);
-                return r;
-        }
-
         /* Second, check if it is currently existing, or maybe
          * doesn't, or maybe disappeared already. */
-        r = sd_bus_get_owner(track->bus, name, 0, NULL);
+        r = sd_bus_get_owner(track->bus, n, 0, NULL);
         if (r < 0) {
-                set_remove(track->names, n);
-                sd_bus_remove_match(track->bus, match, on_name_owner_changed, track);
+                hashmap_remove(track->names, n);
                 return r;
         }
 
         n = NULL;
+        slot = NULL;
 
         bus_track_remove_from_queue(track);
         track->modified = true;
@@ -204,22 +204,19 @@ _public_ int sd_bus_track_add_name(sd_bus_track *track, const char *name) {
 }
 
 _public_ int sd_bus_track_remove_name(sd_bus_track *track, const char *name) {
-        const char *match;
-        _cleanup_free_ char *n = NULL;;
+        _cleanup_bus_slot_unref_ sd_bus_slot *slot = NULL;
+        _cleanup_free_ char *n = NULL;
 
         assert_return(name, -EINVAL);
 
         if (!track)
                 return 0;
 
-        n = set_remove(track->names, (char*) name);
-        if (!n)
+        slot = hashmap_remove2(track->names, (char*) name, (void**) &n);
+        if (!slot)
                 return 0;
 
-        match = MATCH_FOR_NAME(n);
-        sd_bus_remove_match(track->bus, match, on_name_owner_changed, track);
-
-        if (set_isempty(track->names))
+        if (hashmap_isempty(track->names))
                 bus_track_add_to_queue(track);
 
         track->modified = true;
@@ -231,34 +228,40 @@ _public_ unsigned sd_bus_track_count(sd_bus_track *track) {
         if (!track)
                 return 0;
 
-        return set_size(track->names);
+        return hashmap_size(track->names);
 }
 
 _public_ const char* sd_bus_track_contains(sd_bus_track *track, const char *name) {
         assert_return(track, NULL);
         assert_return(name, NULL);
 
-        return set_get(track->names, (void*) name);
+        return hashmap_get(track->names, (void*) name) ? name : NULL;
 }
 
 _public_ const char* sd_bus_track_first(sd_bus_track *track) {
+        const char *n = NULL;
+
         if (!track)
                 return NULL;
 
         track->modified = false;
         track->iterator = NULL;
 
-        return set_iterate(track->names, &track->iterator);
+        hashmap_iterate(track->names, &track->iterator, (const void**) &n);
+        return n;
 }
 
 _public_ const char* sd_bus_track_next(sd_bus_track *track) {
+        const char *n = NULL;
+
         if (!track)
                 return NULL;
 
         if (track->modified)
                 return NULL;
 
-        return set_iterate(track->names, &track->iterator);
+        hashmap_iterate(track->names, &track->iterator, (const void**) &n);
+        return n;
 }
 
 _public_ int sd_bus_track_add_sender(sd_bus_track *track, sd_bus_message *m) {
index 84b3fc5..b5b3c85 100644 (file)
@@ -77,7 +77,7 @@ int bus_async_unregister_and_exit(sd_event *e, sd_bus *bus, const char *name) {
         if (r < 0)
                 return -ENOMEM;
 
-        r = sd_bus_add_match(bus, match, name_owner_change_callback, e);
+        r = sd_bus_add_match(bus, NULL, match, name_owner_change_callback, e);
         if (r < 0)
                 return r;
 
@@ -251,17 +251,16 @@ typedef struct AsyncPolkitQuery {
         sd_bus_message *request, *reply;
         sd_bus_message_handler_t callback;
         void *userdata;
-        uint64_t serial;
+        sd_bus_slot *slot;
         Hashmap *registry;
 } AsyncPolkitQuery;
 
-static void async_polkit_query_free(sd_bus *b, AsyncPolkitQuery *q) {
+static void async_polkit_query_free(AsyncPolkitQuery *q) {
 
         if (!q)
                 return;
 
-        if (q->serial > 0 && b)
-                sd_bus_call_async_cancel(b, q->serial);
+        sd_bus_slot_unref(q->slot);
 
         if (q->registry && q->request)
                 hashmap_remove(q->registry, q->request);
@@ -281,8 +280,8 @@ static int async_polkit_callback(sd_bus *bus, sd_bus_message *reply, void *userd
         assert(reply);
         assert(q);
 
+        q->slot = sd_bus_slot_unref(q->slot);
         q->reply = sd_bus_message_ref(reply);
-        q->serial = 0;
 
         r = sd_bus_message_rewind(q->request, true);
         if (r < 0) {
@@ -294,7 +293,8 @@ static int async_polkit_callback(sd_bus *bus, sd_bus_message *reply, void *userd
         r = bus_maybe_reply_error(q->request, r, &error_buffer);
 
 finish:
-        async_polkit_query_free(bus, q);
+        async_polkit_query_free(q);
+
         return r;
 }
 
@@ -413,15 +413,15 @@ int bus_verify_polkit_async(
 
         r = hashmap_put(*registry, m, q);
         if (r < 0) {
-                async_polkit_query_free(bus, q);
+                async_polkit_query_free(q);
                 return r;
         }
 
         q->registry = *registry;
 
-        r = sd_bus_call_async(bus, pk, async_polkit_callback, q, 0, &q->serial);
+        r = sd_bus_call_async(bus, &q->slot, pk, async_polkit_callback, q, 0);
         if (r < 0) {
-                async_polkit_query_free(bus, q);
+                async_polkit_query_free(q);
                 return r;
         }
 
@@ -436,7 +436,7 @@ void bus_verify_polkit_async_registry_free(sd_bus *bus, Hashmap *registry) {
         AsyncPolkitQuery *q;
 
         while ((q = hashmap_steal_first(registry)))
-                async_polkit_query_free(bus, q);
+                async_polkit_query_free(q);
 
         hashmap_free(registry);
 #endif
index 8103555..1514fad 100644 (file)
@@ -139,12 +139,16 @@ typedef struct UnitInfo {
 int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u);
 
 DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus*, sd_bus_unref);
+DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus_slot*, sd_bus_slot_unref);
 DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus_message*, sd_bus_message_unref);
 DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus_creds*, sd_bus_creds_unref);
+DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus_track*, sd_bus_track_unref);
 
 #define _cleanup_bus_unref_ _cleanup_(sd_bus_unrefp)
+#define _cleanup_bus_slot_unref_ _cleanup_(sd_bus_slot_unrefp)
 #define _cleanup_bus_message_unref_ _cleanup_(sd_bus_message_unrefp)
 #define _cleanup_bus_creds_unref_ _cleanup_(sd_bus_creds_unrefp)
+#define _cleanup_bus_track_unref_ _cleanup_(sd_bus_slot_unrefp)
 #define _cleanup_bus_error_free_ _cleanup_(sd_bus_error_free)
 
 #define BUS_DEFINE_PROPERTY_GET_ENUM(function, name, type)              \
index 4e396f2..4545047 100644 (file)
@@ -240,7 +240,7 @@ static int monitor(sd_bus *bus, char *argv[]) {
                 if (!m)
                         return log_oom();
 
-                r = sd_bus_add_match(bus, m, NULL, NULL);
+                r = sd_bus_add_match(bus, NULL, m, NULL, NULL);
                 if (r < 0) {
                         log_error("Failed to add match: %s", strerror(-r));
                         return r;
@@ -250,7 +250,7 @@ static int monitor(sd_bus *bus, char *argv[]) {
         }
 
         STRV_FOREACH(i, arg_matches) {
-                r = sd_bus_add_match(bus, *i, NULL, NULL);
+                r = sd_bus_add_match(bus, NULL, *i, NULL, NULL);
                 if (r < 0) {
                         log_error("Failed to add match: %s", strerror(-r));
                         return r;
@@ -260,7 +260,7 @@ static int monitor(sd_bus *bus, char *argv[]) {
         }
 
         if (!added_something) {
-                r = sd_bus_add_match(bus, "", NULL, NULL);
+                r = sd_bus_add_match(bus, NULL, "", NULL, NULL);
                 if (r < 0) {
                         log_error("Failed to add match: %s", strerror(-r));
                         return r;
index dc54e21..ea80e9d 100644 (file)
@@ -52,6 +52,7 @@
 #include "bus-container.h"
 #include "bus-protocol.h"
 #include "bus-track.h"
+#include "bus-slot.h"
 
 static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec);
 static int attach_io_events(sd_bus *b);
@@ -71,43 +72,6 @@ static void bus_close_fds(sd_bus *b) {
         b->input_fd = b->output_fd = -1;
 }
 
-static void bus_node_destroy(sd_bus *b, struct node *n) {
-        struct node_callback *c;
-        struct node_vtable *v;
-        struct node_enumerator *e;
-
-        assert(b);
-
-        if (!n)
-                return;
-
-        while (n->child)
-                bus_node_destroy(b, n->child);
-
-        while ((c = n->callbacks)) {
-                LIST_REMOVE(callbacks, n->callbacks, c);
-                free(c);
-        }
-
-        while ((v = n->vtables)) {
-                LIST_REMOVE(vtables, n->vtables, v);
-                free(v->interface);
-                free(v);
-        }
-
-        while ((e = n->enumerators)) {
-                LIST_REMOVE(enumerators, n->enumerators, e);
-                free(e);
-        }
-
-        if (n->parent)
-                LIST_REMOVE(siblings, n->parent->child, n);
-
-        assert_se(hashmap_remove(b->nodes, n->path) == n);
-        free(n->path);
-        free(n);
-}
-
 static void bus_reset_queues(sd_bus *b) {
         assert(b);
 
@@ -133,15 +97,28 @@ static void bus_reset_queues(sd_bus *b) {
 }
 
 static void bus_free(sd_bus *b) {
-        struct filter_callback *f;
-        struct node *n;
+        sd_bus_slot *s;
 
         assert(b);
-
         assert(!b->track_queue);
 
+        b->state = BUS_CLOSED;
+
         sd_bus_detach_event(b);
 
+        while ((s = b->slots)) {
+                /* At this point only floating slots can still be
+                 * around, because the non-floating ones keep a
+                 * reference to the bus, and we thus couldn't be
+                 * destructing right now... We forcibly disconnect the
+                 * slots here, so that they still can be referenced by
+                 * apps, but are dead. */
+
+                assert(s->floating);
+                bus_slot_disconnect(s);
+                sd_bus_slot_unref(s);
+        }
+
         if (b->default_bus_ptr)
                 *b->default_bus_ptr = NULL;
 
@@ -171,19 +148,12 @@ static void bus_free(sd_bus *b) {
         hashmap_free_free(b->reply_callbacks);
         prioq_free(b->reply_callbacks_prioq);
 
-        while ((f = b->filter_callbacks)) {
-                LIST_REMOVE(callbacks, b->filter_callbacks, f);
-                free(f);
-        }
-
         bus_match_free(&b->match_callbacks);
 
         hashmap_free_free(b->vtable_methods);
         hashmap_free_free(b->vtable_properties);
 
-        while ((n = hashmap_first(b->nodes)))
-                bus_node_destroy(b, n);
-
+        assert(hashmap_isempty(b->nodes));
         hashmap_free(b->nodes);
 
         bus_kernel_flush_memfd(b);
@@ -426,7 +396,7 @@ static int bus_send_hello(sd_bus *bus) {
         if (r < 0)
                 return r;
 
-        return sd_bus_call_async(bus, m, hello_callback, NULL, 0, &bus->hello_cookie);
+        return sd_bus_call_async(bus, NULL, m, hello_callback, NULL, 0);
 }
 
 int bus_start_running(sd_bus *bus) {
@@ -1793,14 +1763,14 @@ static int timeout_compare(const void *a, const void *b) {
 
 _public_ int sd_bus_call_async(
                 sd_bus *bus,
+                sd_bus_slot **slot,
                 sd_bus_message *_m,
                 sd_bus_message_handler_t callback,
                 void *userdata,
-                uint64_t usec,
-                uint64_t *cookie) {
+                uint64_t usec) {
 
         _cleanup_bus_message_unref_ sd_bus_message *m = sd_bus_message_ref(_m);
-        struct reply_callback *c;
+        _cleanup_bus_slot_unref_ sd_bus_slot *s = NULL;
         int r;
 
         assert_return(bus, -EINVAL);
@@ -1830,55 +1800,37 @@ _public_ int sd_bus_call_async(
         if (r < 0)
                 return r;
 
-        c = new0(struct reply_callback, 1);
-        if (!c)
+        s = bus_slot_allocate(bus, !slot, BUS_REPLY_CALLBACK, sizeof(struct reply_callback), userdata);
+        if (!s)
                 return -ENOMEM;
 
-        c->callback = callback;
-        c->userdata = userdata;
-        c->cookie = BUS_MESSAGE_COOKIE(m);
-        c->timeout = calc_elapse(m->timeout);
+        s->reply_callback.callback = callback;
 
-        r = hashmap_put(bus->reply_callbacks, &c->cookie, c);
+        s->reply_callback.cookie = BUS_MESSAGE_COOKIE(m);
+        r = hashmap_put(bus->reply_callbacks, &s->reply_callback.cookie, &s->reply_callback);
         if (r < 0) {
-                free(c);
+                s->reply_callback.cookie = 0;
                 return r;
         }
 
-        if (c->timeout != 0) {
-                r = prioq_put(bus->reply_callbacks_prioq, c, &c->prioq_idx);
+        s->reply_callback.timeout = calc_elapse(m->timeout);
+        if (s->reply_callback.timeout != 0) {
+                r = prioq_put(bus->reply_callbacks_prioq, &s->reply_callback, &s->reply_callback.prioq_idx);
                 if (r < 0) {
-                        c->timeout = 0;
-                        sd_bus_call_async_cancel(bus, c->cookie);
+                        s->reply_callback.timeout = 0;
                         return r;
                 }
         }
 
-        r = sd_bus_send(bus, m, cookie);
-        if (r < 0) {
-                sd_bus_call_async_cancel(bus, c->cookie);
+        r = sd_bus_send(bus, m, &s->reply_callback.cookie);
+        if (r < 0)
                 return r;
-        }
-
-        return r;
-}
-
-_public_ int sd_bus_call_async_cancel(sd_bus *bus, uint64_t cookie) {
-        struct reply_callback *c;
 
-        assert_return(bus, -EINVAL);
-        assert_return(cookie != 0, -EINVAL);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
-
-        c = hashmap_remove(bus->reply_callbacks, &cookie);
-        if (!c)
-                return 0;
-
-        if (c->timeout != 0)
-                prioq_remove(bus->reply_callbacks_prioq, c, &c->prioq_idx);
+        if (slot)
+                *slot = s;
+        s = NULL;
 
-        free(c);
-        return 1;
+        return r;
 }
 
 int bus_ensure_running(sd_bus *bus) {
@@ -2125,6 +2077,11 @@ _public_ int sd_bus_get_timeout(sd_bus *bus, uint64_t *timeout_usec) {
                 return 0;
         }
 
+        if (c->timeout == 0) {
+                *timeout_usec = (uint64_t) -1;
+                return 0;
+        }
+
         *timeout_usec = c->timeout;
         return 1;
 }
@@ -2161,16 +2118,21 @@ static int process_timeout(sd_bus *bus) {
                 return r;
 
         assert_se(prioq_pop(bus->reply_callbacks_prioq) == c);
+        c->timeout = 0;
+
         hashmap_remove(bus->reply_callbacks, &c->cookie);
+        c->cookie = 0;
+
+        bus->current_message = m;
+        bus->current_slot = container_of(c, sd_bus_slot, reply_callback);
 
-        bus->current = m;
         bus->iteration_counter ++;
 
-        r = c->callback(bus, m, c->userdata, &error_buffer);
+        r = c->callback(bus, m, bus->current_slot->userdata, &error_buffer);
         r = bus_maybe_reply_error(m, r, &error_buffer);
-        free(c);
 
-        bus->current = NULL;
+        bus->current_message = NULL;
+        bus->current_slot = NULL;
 
         return r;
 }
@@ -2191,7 +2153,7 @@ static int process_hello(sd_bus *bus, sd_bus_message *m) {
             m->header->type != SD_BUS_MESSAGE_METHOD_ERROR)
                 return -EIO;
 
-        if (m->reply_cookie != bus->hello_cookie)
+        if (m->reply_cookie != 1)
                 return -EIO;
 
         return 0;
@@ -2200,7 +2162,8 @@ static int process_hello(sd_bus *bus, sd_bus_message *m) {
 static int process_reply(sd_bus *bus, sd_bus_message *m) {
         _cleanup_bus_message_unref_ sd_bus_message *synthetic_reply = NULL;
         _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
-        _cleanup_free_ struct reply_callback *c = NULL;
+        sd_bus_slot *slot;
+        struct reply_callback *c;
         int r;
 
         assert(bus);
@@ -2220,8 +2183,13 @@ static int process_reply(sd_bus *bus, sd_bus_message *m) {
         if (!c)
                 return 0;
 
-        if (c->timeout != 0)
+        c->cookie = 0;
+        slot = container_of(c, sd_bus_slot, reply_callback);
+
+        if (c->timeout != 0) {
                 prioq_remove(bus->reply_callbacks_prioq, c, &c->prioq_idx);
+                c->timeout = 0;
+        }
 
         if (m->n_fds > 0 && !(bus->hello_flags & KDBUS_HELLO_ACCEPT_FD)) {
 
@@ -2234,22 +2202,31 @@ static int process_reply(sd_bus *bus, sd_bus_message *m) {
                                 &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INCONSISTENT_MESSAGE, "Reply message contained file descriptor"),
                                 &synthetic_reply);
                 if (r < 0)
-                        return r;
+                        goto finish;
 
                 r = bus_seal_synthetic_message(bus, synthetic_reply);
                 if (r < 0)
-                        return r;
+                        goto finish;
 
                 m = synthetic_reply;
         } else {
                 r = sd_bus_message_rewind(m, true);
                 if (r < 0)
-                        return r;
+                        goto finish;
         }
 
-        r = c->callback(bus, m, c->userdata, &error_buffer);
+        bus->current_slot = slot;
+        r = c->callback(bus, m, bus->current_slot->userdata, &error_buffer);
+        bus->current_slot = NULL;
+
         r = bus_maybe_reply_error(m, r, &error_buffer);
 
+finish:
+        if (slot->floating) {
+                bus_slot_disconnect(slot);
+                sd_bus_slot_unref(slot);
+        }
+
         return r;
 }
 
@@ -2279,7 +2256,10 @@ static int process_filter(sd_bus *bus, sd_bus_message *m) {
                         if (r < 0)
                                 return r;
 
-                        r = l->callback(bus, m, l->userdata, &error_buffer);
+                        bus->current_slot = container_of(l, sd_bus_slot, filter_callback);
+                        r = l->callback(bus, m, bus->current_slot->userdata, &error_buffer);
+                        bus->current_slot = NULL;
+
                         r = bus_maybe_reply_error(m, r, &error_buffer);
                         if (r != 0)
                                 return r;
@@ -2395,7 +2375,7 @@ static int process_message(sd_bus *bus, sd_bus_message *m) {
         assert(bus);
         assert(m);
 
-        bus->current = m;
+        bus->current_message = m;
         bus->iteration_counter++;
 
         log_debug("Got message type=%s sender=%s destination=%s object=%s interface=%s member=%s cookie=%" PRIu64 " reply_cookie=%" PRIu64 " error=%s",
@@ -2436,7 +2416,7 @@ static int process_message(sd_bus *bus, sd_bus_message *m) {
         r = bus_process_object(bus, m);
 
 finish:
-        bus->current = NULL;
+        bus->current_message = NULL;
         return r;
 }
 
@@ -2539,17 +2519,23 @@ static int process_closing(sd_bus *bus, sd_bus_message **ret) {
                 if (r < 0)
                         return r;
 
-                if (c->timeout != 0)
+                if (c->timeout != 0) {
                         prioq_remove(bus->reply_callbacks_prioq, c, &c->prioq_idx);
+                        c->timeout = 0;
+                }
 
                 hashmap_remove(bus->reply_callbacks, &c->cookie);
+                c->cookie = 0;
+
+                bus->current_message = m;
+                bus->current_slot = container_of(c, sd_bus_slot, reply_callback);
 
-                bus->current = m;
                 bus->iteration_counter++;
 
-                r = c->callback(bus, m, c->userdata, &error_buffer);
+                r = c->callback(bus, m, bus->current_slot->userdata, &error_buffer);
                 r = bus_maybe_reply_error(m, r, &error_buffer);
-                free(c);
+
+                bus->current_slot = NULL;
 
                 goto finish;
         }
@@ -2572,7 +2558,7 @@ static int process_closing(sd_bus *bus, sd_bus_message **ret) {
 
         sd_bus_close(bus);
 
-        bus->current = m;
+        bus->current_message = m;
         bus->iteration_counter++;
 
         r = process_filter(bus, m);
@@ -2591,7 +2577,8 @@ static int process_closing(sd_bus *bus, sd_bus_message **ret) {
         r = 1;
 
 finish:
-        bus->current = NULL;
+        bus->current_message = NULL;
+
         return r;
 }
 
@@ -2608,7 +2595,8 @@ static int bus_process_internal(sd_bus *bus, bool hint_priority, int64_t priorit
         assert_return(!bus_pid_changed(bus), -ECHILD);
 
         /* We don't allow recursively invoking sd_bus_process(). */
-        assert_return(!bus->current, -EBUSY);
+        assert_return(!bus->current_message, -EBUSY);
+        assert(!bus->current_slot);
 
         switch (bus->state) {
 
@@ -2785,57 +2773,43 @@ _public_ int sd_bus_flush(sd_bus *bus) {
         }
 }
 
-_public_ int sd_bus_add_filter(sd_bus *bus,
-                               sd_bus_message_handler_t callback,
-                               void *userdata) {
+_public_ int sd_bus_add_filter(
+                sd_bus *bus,
+                sd_bus_slot **slot,
+                sd_bus_message_handler_t callback,
+                void *userdata) {
 
-        struct filter_callback *f;
+        sd_bus_slot *s;
 
         assert_return(bus, -EINVAL);
         assert_return(callback, -EINVAL);
         assert_return(!bus_pid_changed(bus), -ECHILD);
 
-        f = new0(struct filter_callback, 1);
-        if (!f)
+        s = bus_slot_allocate(bus, !slot, BUS_FILTER_CALLBACK, sizeof(struct filter_callback), userdata);
+        if (!s)
                 return -ENOMEM;
-        f->callback = callback;
-        f->userdata = userdata;
 
-        bus->filter_callbacks_modified = true;
-        LIST_PREPEND(callbacks, bus->filter_callbacks, f);
-        return 0;
-}
+        s->filter_callback.callback = callback;
 
-_public_ int sd_bus_remove_filter(sd_bus *bus,
-                                  sd_bus_message_handler_t callback,
-                                  void *userdata) {
-
-        struct filter_callback *f;
-
-        assert_return(bus, -EINVAL);
-        assert_return(callback, -EINVAL);
-        assert_return(!bus_pid_changed(bus), -ECHILD);
+        bus->filter_callbacks_modified = true;
+        LIST_PREPEND(callbacks, bus->filter_callbacks, &s->filter_callback);
 
-        LIST_FOREACH(callbacks, f, bus->filter_callbacks) {
-                if (f->callback == callback && f->userdata == userdata) {
-                        bus->filter_callbacks_modified = true;
-                        LIST_REMOVE(callbacks, bus->filter_callbacks, f);
-                        free(f);
-                        return 1;
-                }
-        }
+        if (slot)
+                *slot = s;
 
         return 0;
 }
 
-_public_ int sd_bus_add_match(sd_bus *bus,
-                              const char *match,
-                              sd_bus_message_handler_t callback,
-                              void *userdata) {
+_public_ int sd_bus_add_match(
+                sd_bus *bus,
+                sd_bus_slot **slot,
+                const char *match,
+                sd_bus_message_handler_t callback,
+                void *userdata) {
 
         struct bus_match_component *components = NULL;
         unsigned n_components = 0;
-        uint64_t cookie = 0;
+        sd_bus_slot *s;
         int r = 0;
 
         assert_return(bus, -EINVAL);
@@ -2846,35 +2820,60 @@ _public_ int sd_bus_add_match(sd_bus *bus,
         if (r < 0)
                 goto finish;
 
+        s = bus_slot_allocate(bus, !slot, BUS_MATCH_CALLBACK, sizeof(struct match_callback), userdata);
+        if (!s) {
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        s->match_callback.callback = callback;
+        s->match_callback.cookie = ++bus->match_cookie;
+
         if (bus->bus_client) {
-                cookie = ++bus->match_cookie;
 
-                r = bus_add_match_internal(bus, match, components, n_components, cookie);
+                if (!bus->is_kernel) {
+                        /* When this is not a kernel transport, we
+                         * store the original match string, so that we
+                         * can use it to remove the match again */
+
+                        s->match_callback.match_string = strdup(match);
+                        if (!s->match_callback.match_string) {
+                                r = -ENOMEM;
+                                goto finish;
+                        }
+                }
+
+                r = bus_add_match_internal(bus, s->match_callback.match_string, components, n_components, s->match_callback.cookie);
                 if (r < 0)
                         goto finish;
         }
 
         bus->match_callbacks_modified = true;
-        r = bus_match_add(&bus->match_callbacks, components, n_components, callback, userdata, cookie, NULL);
-        if (r < 0) {
-                if (bus->bus_client)
-                        bus_remove_match_internal(bus, match, cookie);
-        }
+        r = bus_match_add(&bus->match_callbacks, components, n_components, &s->match_callback);
+        if (r < 0)
+                goto finish;
+
+        if (slot)
+                *slot = s;
+        s = NULL;
 
 finish:
         bus_match_parse_free(components, n_components);
+        sd_bus_slot_unref(s);
+
         return r;
 }
 
-_public_ int sd_bus_remove_match(sd_bus *bus,
-                                 const char *match,
-                                 sd_bus_message_handler_t callback,
-                                 void *userdata) {
+int bus_remove_match_by_string(
+                sd_bus *bus,
+                const char *match,
+                sd_bus_message_handler_t callback,
+                void *userdata) {
 
         struct bus_match_component *components = NULL;
         unsigned n_components = 0;
-        int r = 0, q = 0;
-        uint64_t cookie = 0;
+        struct match_callback *c;
+        int r = 0;
 
         assert_return(bus, -EINVAL);
         assert_return(match, -EINVAL);
@@ -2882,17 +2881,18 @@ _public_ int sd_bus_remove_match(sd_bus *bus,
 
         r = bus_match_parse(match, &components, &n_components);
         if (r < 0)
-                return r;
+                goto finish;
 
-        bus->match_callbacks_modified = true;
-        r = bus_match_remove(&bus->match_callbacks, components, n_components, callback, userdata, &cookie);
+        r = bus_match_find(&bus->match_callbacks, components, n_components, NULL, NULL, &c);
+        if (r <= 0)
+                goto finish;
 
-        if (bus->bus_client)
-                q = bus_remove_match_internal(bus, match, cookie);
+        sd_bus_slot_unref(container_of(c, sd_bus_slot, match_callback));
 
+finish:
         bus_match_parse_free(components, n_components);
 
-        return r < 0 ? r : q;
+        return r;
 }
 
 bool bus_pid_changed(sd_bus *bus) {
@@ -3116,10 +3116,16 @@ _public_ sd_event* sd_bus_get_event(sd_bus *bus) {
         return bus->event;
 }
 
-_public_ sd_bus_message* sd_bus_get_current(sd_bus *bus) {
+_public_ sd_bus_message* sd_bus_get_current_message(sd_bus *bus) {
+        assert_return(bus, NULL);
+
+        return bus->current_message;
+}
+
+_public_ sd_bus_slot* sd_bus_get_current_slot(sd_bus *bus) {
         assert_return(bus, NULL);
 
-        return bus->current;
+        return bus->current_slot;
 }
 
 static int bus_default(int (*bus_open)(sd_bus **), sd_bus **default_bus, sd_bus **ret) {
index c0abc7a..c9eb698 100644 (file)
@@ -100,19 +100,19 @@ static int server_init(sd_bus **_bus) {
                 goto fail;
         }
 
-        r = sd_bus_add_fallback(bus, "/foo/bar", object_callback, NULL);
+        r = sd_bus_add_fallback(bus, NULL, "/foo/bar", object_callback, NULL);
         if (r < 0) {
                 log_error("Failed to add object: %s", strerror(-r));
                 goto fail;
         }
 
-        r = sd_bus_add_match(bus, "type='signal',interface='foo.bar',member='Notify'", match_callback, NULL);
+        r = sd_bus_add_match(bus, NULL, "type='signal',interface='foo.bar',member='Notify'", match_callback, NULL);
         if (r < 0) {
                 log_error("Failed to add match: %s", strerror(-r));
                 goto fail;
         }
 
-        r = sd_bus_add_match(bus, "type='signal',interface='org.freedesktop.DBus',member='NameOwnerChanged'", match_callback, NULL);
+        r = sd_bus_add_match(bus, NULL, "type='signal',interface='org.freedesktop.DBus',member='NameOwnerChanged'", match_callback, NULL);
         if (r < 0) {
                 log_error("Failed to add match: %s", strerror(-r));
                 goto fail;
@@ -490,7 +490,7 @@ static void* client2(void*p) {
                 goto finish;
         }
 
-        r = sd_bus_call_async(bus, m, quit_callback, &quit, 200 * USEC_PER_MSEC, NULL);
+        r = sd_bus_call_async(bus, NULL, m, quit_callback, &quit, 200 * USEC_PER_MSEC);
         if (r < 0) {
                 log_info("Failed to issue method call: %s", bus_error_message(&error, -r));
                 goto finish;
index 0ecad18..5ee6eea 100644 (file)
@@ -72,7 +72,7 @@ static void test_one(
         assert_se(r >= 0);
 
         log_debug("match");
-        r = sd_bus_add_match(b, match, NULL, NULL);
+        r = sd_bus_add_match(b, NULL, match, NULL, NULL);
         assert_se(r >= 0);
 
         log_debug("signal");
index 34d000f..7bb8b0a 100644 (file)
@@ -101,7 +101,7 @@ int main(int argc, char *argv[]) {
         assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_SERVICE_UNKNOWN));
         assert_se(r == -EHOSTUNREACH);
 
-        r = sd_bus_add_match(b, "interface='waldo.com',member='Piep'", NULL, NULL);
+        r = sd_bus_add_match(b, NULL, "interface='waldo.com',member='Piep'", NULL, NULL);
         assert_se(r >= 0);
 
         r = sd_bus_emit_signal(a, "/foo/bar/waldo", "waldo.com", "Piep", "sss", "I am a string", "/this/is/a/path", "and.this.a.domain.name");
index c561be2..a62de50 100644 (file)
@@ -28,6 +28,7 @@
 #include "bus-match.h"
 #include "bus-message.h"
 #include "bus-util.h"
+#include "bus-slot.h"
 
 static bool mask[32];
 
@@ -56,31 +57,23 @@ static bool mask_contains(unsigned a[], unsigned n) {
         return true;
 }
 
-static int match_add(struct bus_match_node *root, const char *match, int value) {
+static int match_add(sd_bus_slot *slots, struct bus_match_node *root, const char *match, int value) {
         struct bus_match_component *components = NULL;
         unsigned n_components = 0;
+        sd_bus_slot *s;
         int r;
 
-        r = bus_match_parse(match, &components, &n_components);
-        if (r < 0)
-                return r;
-
-        r = bus_match_add(root, components, n_components, filter, INT_TO_PTR(value), 0, NULL);
-        bus_match_parse_free(components, n_components);
-
-        return r;
-}
-
-static int match_remove(struct bus_match_node *root, const char *match, int value) {
-        struct bus_match_component *components = NULL;
-        unsigned n_components = 0;
-        int r;
+        s = slots + value;
+        zero(*s);
 
         r = bus_match_parse(match, &components, &n_components);
         if (r < 0)
                 return r;
 
-        r = bus_match_remove(root, components, n_components, filter, INT_TO_PTR(value), 0);
+        s->userdata = INT_TO_PTR(value);
+        s->match_callback.callback = filter;
+
+        r = bus_match_add(root, components, n_components, &s->match_callback);
         bus_match_parse_free(components, n_components);
 
         return r;
@@ -90,24 +83,25 @@ int main(int argc, char *argv[]) {
         struct bus_match_node root;
         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
         enum bus_match_node_type i;
+        sd_bus_slot slots[15];
 
         zero(root);
         root.type = BUS_MATCH_ROOT;
 
-        assert_se(match_add(&root, "arg2='wal\\'do',sender='foo',type='signal',interface='bar.x',", 1) >= 0);
-        assert_se(match_add(&root, "arg2='wal\\'do2',sender='foo',type='signal',interface='bar.x',", 2) >= 0);
-        assert_se(match_add(&root, "arg3='test',sender='foo',type='signal',interface='bar.x',", 3) >= 0);
-        assert_se(match_add(&root, "arg3='test',sender='foo',type='method_call',interface='bar.x',", 4) >= 0);
-        assert_se(match_add(&root, "", 5) >= 0);
-        assert_se(match_add(&root, "interface='quux.x'", 6) >= 0);
-        assert_se(match_add(&root, "interface='bar.x'", 7) >= 0);
-        assert_se(match_add(&root, "member='waldo',path='/foo/bar'", 8) >= 0);
-        assert_se(match_add(&root, "path='/foo/bar'", 9) >= 0);
-        assert_se(match_add(&root, "path_namespace='/foo'", 10) >= 0);
-        assert_se(match_add(&root, "path_namespace='/foo/quux'", 11) >= 0);
-        assert_se(match_add(&root, "arg1='two'", 12) >= 0);
-        assert_se(match_add(&root, "member='waldo',arg2path='/prefix/'", 13) >= 0);
-        assert_se(match_add(&root, "member=waldo,path='/foo/bar',arg3namespace='prefix'", 14) >= 0);
+        assert_se(match_add(slots, &root, "arg2='wal\\'do',sender='foo',type='signal',interface='bar.x',", 1) >= 0);
+        assert_se(match_add(slots, &root, "arg2='wal\\'do2',sender='foo',type='signal',interface='bar.x',", 2) >= 0);
+        assert_se(match_add(slots, &root, "arg3='test',sender='foo',type='signal',interface='bar.x',", 3) >= 0);
+        assert_se(match_add(slots, &root, "arg3='test',sender='foo',type='method_call',interface='bar.x',", 4) >= 0);
+        assert_se(match_add(slots, &root, "", 5) >= 0);
+        assert_se(match_add(slots, &root, "interface='quux.x'", 6) >= 0);
+        assert_se(match_add(slots, &root, "interface='bar.x'", 7) >= 0);
+        assert_se(match_add(slots, &root, "member='waldo',path='/foo/bar'", 8) >= 0);
+        assert_se(match_add(slots, &root, "path='/foo/bar'", 9) >= 0);
+        assert_se(match_add(slots, &root, "path_namespace='/foo'", 10) >= 0);
+        assert_se(match_add(slots, &root, "path_namespace='/foo/quux'", 11) >= 0);
+        assert_se(match_add(slots, &root, "arg1='two'", 12) >= 0);
+        assert_se(match_add(slots, &root, "member='waldo',arg2path='/prefix/'", 13) >= 0);
+        assert_se(match_add(slots, &root, "member=waldo,path='/foo/bar',arg3namespace='prefix'", 14) >= 0);
 
         bus_match_dump(&root, 0);
 
@@ -119,9 +113,8 @@ int main(int argc, char *argv[]) {
         assert_se(bus_match_run(NULL, &root, m) == 0);
         assert_se(mask_contains((unsigned[]) { 9, 8, 7, 5, 10, 12, 13, 14 }, 8));
 
-        assert_se(match_remove(&root, "member='waldo',path='/foo/bar'", 8) > 0);
-        assert_se(match_remove(&root, "arg2path='/prefix/',member='waldo'", 13) > 0);
-        assert_se(match_remove(&root, "interface='bar.xx'", 7) == 0);
+        assert_se(bus_match_remove(&root, &slots[8].match_callback) >= 0);
+        assert_se(bus_match_remove(&root, &slots[13].match_callback) >= 0);
 
         bus_match_dump(&root, 0);
 
index e2423c7..e7a445f 100644 (file)
@@ -200,7 +200,7 @@ static const sd_bus_vtable vtable2[] = {
         SD_BUS_VTABLE_END
 };
 
-static int enumerator_callback(sd_bus *b, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
+static int enumerator_callback(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
 
         if (object_path_startswith("/value", path))
                 assert_se(*nodes = strv_new("/value/a", "/value/b", "/value/c", NULL));
@@ -222,11 +222,11 @@ static void *server(void *p) {
         assert_se(sd_bus_set_fd(bus, c->fds[0], c->fds[0]) >= 0);
         assert_se(sd_bus_set_server(bus, 1, id) >= 0);
 
-        assert_se(sd_bus_add_object_vtable(bus, "/foo", "org.freedesktop.systemd.test", vtable, c) >= 0);
-        assert_se(sd_bus_add_object_vtable(bus, "/foo", "org.freedesktop.systemd.test2", vtable, c) >= 0);
-        assert_se(sd_bus_add_fallback_vtable(bus, "/value", "org.freedesktop.systemd.ValueTest", vtable2, NULL, UINT_TO_PTR(20)) >= 0);
-        assert_se(sd_bus_add_node_enumerator(bus, "/value", enumerator_callback, NULL) >= 0);
-        assert_se(sd_bus_add_object_manager(bus, "/value") >= 0);
+        assert_se(sd_bus_add_object_vtable(bus, NULL, "/foo", "org.freedesktop.systemd.test", vtable, c) >= 0);
+        assert_se(sd_bus_add_object_vtable(bus, NULL, "/foo", "org.freedesktop.systemd.test2", vtable, c) >= 0);
+        assert_se(sd_bus_add_fallback_vtable(bus, NULL, "/value", "org.freedesktop.systemd.ValueTest", vtable2, NULL, UINT_TO_PTR(20)) >= 0);
+        assert_se(sd_bus_add_node_enumerator(bus, NULL, "/value", enumerator_callback, NULL) >= 0);
+        assert_se(sd_bus_add_object_manager(bus, NULL, "/value") >= 0);
 
         assert_se(sd_bus_start(bus) >= 0);
 
index de6e3b2..e3061c8 100644 (file)
@@ -1088,7 +1088,7 @@ static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) {
                 return r;
         }
 
-        r = sd_bus_add_object_vtable(bus, "/org/freedesktop/locale1", "org.freedesktop.locale1", locale_vtable, c);
+        r = sd_bus_add_object_vtable(bus, NULL, "/org/freedesktop/locale1", "org.freedesktop.locale1", locale_vtable, c);
         if (r < 0) {
                 log_error("Failed to register object: %s", strerror(-r));
                 return r;
index 82323d6..1a2f09c 100644 (file)
@@ -329,7 +329,7 @@ int seat_object_find(sd_bus *bus, const char *path, const char *interface, void
                 Session *session;
                 pid_t pid;
 
-                message = sd_bus_get_current(bus);
+                message = sd_bus_get_current_message(bus);
                 if (!message)
                         return 0;
 
index ffdc558..7d81500 100644 (file)
@@ -493,7 +493,7 @@ int session_object_find(sd_bus *bus, const char *path, const char *interface, vo
                 sd_bus_message *message;
                 pid_t pid;
 
-                message = sd_bus_get_current(bus);
+                message = sd_bus_get_current_message(bus);
                 if (!message)
                         return 0;
 
index b5d27e7..4f1a079 100644 (file)
@@ -250,7 +250,7 @@ int user_object_find(sd_bus *bus, const char *path, const char *interface, void
                 sd_bus_message *message;
                 pid_t pid;
 
-                message = sd_bus_get_current(bus);
+                message = sd_bus_get_current_message(bus);
                 if (!message)
                         return 0;
 
index 86ce7df..686506c 100644 (file)
@@ -586,49 +586,50 @@ static int manager_connect_bus(Manager *m) {
                 return r;
         }
 
-        r = sd_bus_add_object_vtable(m->bus, "/org/freedesktop/login1", "org.freedesktop.login1.Manager", manager_vtable, m);
+        r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/login1", "org.freedesktop.login1.Manager", manager_vtable, m);
         if (r < 0) {
                 log_error("Failed to add manager object vtable: %s", strerror(-r));
                 return r;
         }
 
-        r = sd_bus_add_fallback_vtable(m->bus, "/org/freedesktop/login1/seat", "org.freedesktop.login1.Seat", seat_vtable, seat_object_find, m);
+        r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/login1/seat", "org.freedesktop.login1.Seat", seat_vtable, seat_object_find, m);
         if (r < 0) {
                 log_error("Failed to add seat object vtable: %s", strerror(-r));
                 return r;
         }
 
-        r = sd_bus_add_node_enumerator(m->bus, "/org/freedesktop/login1/seat", seat_node_enumerator, m);
+        r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/login1/seat", seat_node_enumerator, m);
         if (r < 0) {
                 log_error("Failed to add seat enumerator: %s", strerror(-r));
                 return r;
         }
 
-        r = sd_bus_add_fallback_vtable(m->bus, "/org/freedesktop/login1/session", "org.freedesktop.login1.Session", session_vtable, session_object_find, m);
+        r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/login1/session", "org.freedesktop.login1.Session", session_vtable, session_object_find, m);
         if (r < 0) {
                 log_error("Failed to add session object vtable: %s", strerror(-r));
                 return r;
         }
 
-        r = sd_bus_add_node_enumerator(m->bus, "/org/freedesktop/login1/session", session_node_enumerator, m);
+        r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/login1/session", session_node_enumerator, m);
         if (r < 0) {
                 log_error("Failed to add session enumerator: %s", strerror(-r));
                 return r;
         }
 
-        r = sd_bus_add_fallback_vtable(m->bus, "/org/freedesktop/login1/user", "org.freedesktop.login1.User", user_vtable, user_object_find, m);
+        r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/login1/user", "org.freedesktop.login1.User", user_vtable, user_object_find, m);
         if (r < 0) {
                 log_error("Failed to add user object vtable: %s", strerror(-r));
                 return r;
         }
 
-        r = sd_bus_add_node_enumerator(m->bus, "/org/freedesktop/login1/user", user_node_enumerator, m);
+        r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/login1/user", user_node_enumerator, m);
         if (r < 0) {
                 log_error("Failed to add user enumerator: %s", strerror(-r));
                 return r;
         }
 
         r = sd_bus_add_match(m->bus,
+                             NULL,
                              "type='signal',"
                              "sender='org.freedesktop.DBus',"
                              "interface='org.freedesktop.DBus',"
@@ -641,6 +642,7 @@ static int manager_connect_bus(Manager *m) {
         }
 
         r = sd_bus_add_match(m->bus,
+                             NULL,
                              "type='signal',"
                              "sender='org.freedesktop.systemd1',"
                              "interface='org.freedesktop.systemd1.Manager',"
@@ -653,6 +655,7 @@ static int manager_connect_bus(Manager *m) {
         }
 
         r = sd_bus_add_match(m->bus,
+                             NULL,
                              "type='signal',"
                              "sender='org.freedesktop.systemd1',"
                              "interface='org.freedesktop.systemd1.Manager',"
@@ -665,6 +668,7 @@ static int manager_connect_bus(Manager *m) {
         }
 
         r = sd_bus_add_match(m->bus,
+                             NULL,
                              "type='signal',"
                              "sender='org.freedesktop.systemd1',"
                              "interface='org.freedesktop.DBus.Properties',"
@@ -676,6 +680,7 @@ static int manager_connect_bus(Manager *m) {
         }
 
         r = sd_bus_add_match(m->bus,
+                             NULL,
                              "type='signal',"
                              "sender='org.freedesktop.systemd1',"
                              "interface='org.freedesktop.systemd1.Manager',"
index 920c995..83ef82d 100644 (file)
@@ -160,7 +160,7 @@ int machine_object_find(sd_bus *bus, const char *path, const char *interface, vo
                 sd_bus_message *message;
                 pid_t pid;
 
-                message = sd_bus_get_current(bus);
+                message = sd_bus_get_current_message(bus);
                 if (!message)
                         return 0;
 
index 20e6f7c..45768d2 100644 (file)
@@ -141,25 +141,26 @@ static int manager_connect_bus(Manager *m) {
                 return r;
         }
 
-        r = sd_bus_add_object_vtable(m->bus, "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", manager_vtable, m);
+        r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", manager_vtable, m);
         if (r < 0) {
                 log_error("Failed to add manager object vtable: %s", strerror(-r));
                 return r;
         }
 
-        r = sd_bus_add_fallback_vtable(m->bus, "/org/freedesktop/machine1/machine", "org.freedesktop.machine1.Machine", machine_vtable, machine_object_find, m);
+        r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/machine1/machine", "org.freedesktop.machine1.Machine", machine_vtable, machine_object_find, m);
         if (r < 0) {
                 log_error("Failed to add machine object vtable: %s", strerror(-r));
                 return r;
         }
 
-        r = sd_bus_add_node_enumerator(m->bus, "/org/freedesktop/machine1/machine", machine_node_enumerator, m);
+        r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/machine1/machine", machine_node_enumerator, m);
         if (r < 0) {
                 log_error("Failed to add machine enumerator: %s", strerror(-r));
                 return r;
         }
 
         r = sd_bus_add_match(m->bus,
+                             NULL,
                              "type='signal',"
                              "sender='org.freedesktop.systemd1',"
                              "interface='org.freedesktop.systemd1.Manager',"
@@ -173,6 +174,7 @@ static int manager_connect_bus(Manager *m) {
         }
 
         r = sd_bus_add_match(m->bus,
+                             NULL,
                              "type='signal',"
                              "sender='org.freedesktop.systemd1',"
                              "interface='org.freedesktop.systemd1.Manager',"
@@ -186,6 +188,7 @@ static int manager_connect_bus(Manager *m) {
         }
 
         r = sd_bus_add_match(m->bus,
+                             NULL,
                              "type='signal',"
                              "sender='org.freedesktop.systemd1',"
                              "interface='org.freedesktop.DBus.Properties',"
@@ -198,6 +201,7 @@ static int manager_connect_bus(Manager *m) {
         }
 
         r = sd_bus_add_match(m->bus,
+                             NULL,
                              "type='signal',"
                              "sender='org.freedesktop.systemd1',"
                              "interface='org.freedesktop.systemd1.Manager',"
index 77c505f..37a572d 100644 (file)
@@ -684,7 +684,7 @@ static int link_set_hostname(Link *link, const char *hostname) {
         if (r < 0)
                 return r;
 
-        r = sd_bus_call_async(link->manager->bus, m, set_hostname_handler, link, 0, NULL);
+        r = sd_bus_call_async(link->manager->bus, NULL, m, set_hostname_handler, link, 0);
         if (r < 0)
                 log_error_link(link, "Could not set transient hostname: %s", strerror(-r));
 
index e1e4640..91d8032 100644 (file)
@@ -2305,6 +2305,7 @@ static int enable_wait_for_jobs(sd_bus *bus) {
 
         r = sd_bus_add_match(
                         bus,
+                        NULL,
                         "type='signal',"
                         "sender='org.freedesktop.systemd1',"
                         "interface='org.freedesktop.systemd1.Manager',"
@@ -2364,13 +2365,14 @@ static int check_wait_response(WaitData *d) {
 }
 
 static int wait_for_jobs(sd_bus *bus, Set *s) {
+        _cleanup_bus_slot_unref_ sd_bus_slot *slot = NULL;
         WaitData d = { .set = s };
         int r = 0, q;
 
         assert(bus);
         assert(s);
 
-        q = sd_bus_add_filter(bus, wait_filter, &d);
+        q = sd_bus_add_filter(bus, &slot, wait_filter, &d);
         if (q < 0)
                 return log_oom();
 
@@ -2398,10 +2400,6 @@ static int wait_for_jobs(sd_bus *bus, Set *s) {
                 d.result = NULL;
         }
 
-        q = sd_bus_remove_filter(bus, wait_filter, &d);
-        if (q < 0 && r == 0)
-                r = q;
-
         return r;
 }
 
index c6787ca..79566d2 100644 (file)
@@ -37,6 +37,7 @@ _SD_BEGIN_DECLARATIONS;
 
 typedef struct sd_bus sd_bus;
 typedef struct sd_bus_message sd_bus_message;
+typedef struct sd_bus_slot sd_bus_slot;
 typedef struct sd_bus_creds sd_bus_creds;
 typedef struct sd_bus_track sd_bus_track;
 
@@ -138,8 +139,7 @@ int sd_bus_get_tid(sd_bus *bus, pid_t *tid);
 int sd_bus_send(sd_bus *bus, sd_bus_message *m, uint64_t *cookie);
 int sd_bus_send_to(sd_bus *bus, sd_bus_message *m, const char *destination, uint64_t *cookie);
 int sd_bus_call(sd_bus *bus, sd_bus_message *m, uint64_t usec, sd_bus_error *ret_error, sd_bus_message **reply);
-int sd_bus_call_async(sd_bus *bus, sd_bus_message *m, sd_bus_message_handler_t callback, void *userdata, uint64_t usec, uint64_t *cookie);
-int sd_bus_call_async_cancel(sd_bus *bus, uint64_t cookie);
+int sd_bus_call_async(sd_bus *bus, sd_bus_slot **slot, sd_bus_message *m, sd_bus_message_handler_t callback, void *userdata, uint64_t usec);
 
 int sd_bus_get_fd(sd_bus *bus);
 int sd_bus_get_events(sd_bus *bus);
@@ -148,35 +148,33 @@ int sd_bus_process(sd_bus *bus, sd_bus_message **r);
 int sd_bus_process_priority(sd_bus *bus, int64_t max_priority, sd_bus_message **r);
 int sd_bus_wait(sd_bus *bus, uint64_t timeout_usec);
 int sd_bus_flush(sd_bus *bus);
-sd_bus_message* sd_bus_get_current(sd_bus *bus);
+sd_bus_message* sd_bus_get_current_message(sd_bus *bus);
+sd_bus_slot* sd_bus_get_current_slot(sd_bus *bus);
 
 int sd_bus_attach_event(sd_bus *bus, sd_event *e, int priority);
 int sd_bus_detach_event(sd_bus *bus);
 sd_event *sd_bus_get_event(sd_bus *bus);
 
-int sd_bus_add_filter(sd_bus *bus, sd_bus_message_handler_t callback, void *userdata);
-int sd_bus_remove_filter(sd_bus *bus, sd_bus_message_handler_t callback, void *userdata);
+int sd_bus_add_filter(sd_bus *bus, sd_bus_slot **slot, sd_bus_message_handler_t callback, void *userdata);
+int sd_bus_add_match(sd_bus *bus, sd_bus_slot **slot, const char *match, sd_bus_message_handler_t callback, void *userdata);
+int sd_bus_add_object(sd_bus *bus, sd_bus_slot **slot, const char *path, sd_bus_message_handler_t callback, void *userdata);
+int sd_bus_add_fallback(sd_bus *bus, sd_bus_slot **slot, const char *prefix, sd_bus_message_handler_t callback, void *userdata);
+int sd_bus_add_object_vtable(sd_bus *bus, sd_bus_slot **slot, const char *path, const char *interface, const sd_bus_vtable *vtable, void *userdata);
+int sd_bus_add_fallback_vtable(sd_bus *bus, sd_bus_slot **slot, const char *prefix, const char *interface, const sd_bus_vtable *vtable, sd_bus_object_find_t find, void *userdata);
+int sd_bus_add_node_enumerator(sd_bus *bus, sd_bus_slot **slot, const char *path, sd_bus_node_enumerator_t callback, void *userdata);
+int sd_bus_add_object_manager(sd_bus *bus, sd_bus_slot **slot, const char *path);
 
-int sd_bus_add_match(sd_bus *bus, const char *match, sd_bus_message_handler_t callback, void *userdata);
-int sd_bus_remove_match(sd_bus *bus, const char *match, sd_bus_message_handler_t callback, void *userdata);
+/* Slot object */
 
-int sd_bus_add_object(sd_bus *bus, const char *path, sd_bus_message_handler_t callback, void *userdata);
-int sd_bus_remove_object(sd_bus *bus, const char *path, sd_bus_message_handler_t callback, void *userdata);
+sd_bus_slot* sd_bus_slot_ref(sd_bus_slot *slot);
+sd_bus_slot* sd_bus_slot_unref(sd_bus_slot *slot);
 
-int sd_bus_add_fallback(sd_bus *bus, const char *prefix, sd_bus_message_handler_t callback, void *userdata);
-int sd_bus_remove_fallback(sd_bus *bus, const char *prefix, sd_bus_message_handler_t callback, void *userdata);
+sd_bus* sd_bus_slot_get_bus(sd_bus_slot *slot);
 
-int sd_bus_add_object_vtable(sd_bus *bus, const char *path, const char *interface, const sd_bus_vtable *vtable, void *userdata);
-int sd_bus_remove_object_vtable(sd_bus *bus, const char *path, const char *interface, const sd_bus_vtable *vtable, void *userdata);
+void *sd_bus_slot_get_userdata(sd_bus_slot *slot);
+void *sd_bus_slot_set_userdata(sd_bus_slot *slot, void *userdata);
 
-int sd_bus_add_fallback_vtable(sd_bus *bus, const char *path, const char *interface, const sd_bus_vtable *vtable, sd_bus_object_find_t find, void *userdata);
-int sd_bus_remove_fallback_vtable(sd_bus *bus, const char *path, const char *interface, const sd_bus_vtable *vtable, sd_bus_object_find_t find, void *userdata);
-
-int sd_bus_add_node_enumerator(sd_bus *bus, const char *path, sd_bus_node_enumerator_t callback, void *userdata);
-int sd_bus_remove_node_enumerator(sd_bus *bus, const char *path, sd_bus_node_enumerator_t callback, void *userdata);
-
-int sd_bus_add_object_manager(sd_bus *bus, const char *path);
-int sd_bus_remove_object_manager(sd_bus *bus, const char *path);
+sd_bus_message* sd_bus_slot_get_current_message(sd_bus_slot *slot);
 
 /* Message object */
 
index 3895e32..1b09380 100644 (file)
@@ -784,7 +784,7 @@ static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) {
                 return r;
         }
 
-        r = sd_bus_add_object_vtable(bus, "/org/freedesktop/timedate1", "org.freedesktop.timedate1", timedate_vtable, c);
+        r = sd_bus_add_object_vtable(bus, NULL, "/org/freedesktop/timedate1", "org.freedesktop.timedate1", timedate_vtable, c);
         if (r < 0) {
                 log_error("Failed to register object: %s", strerror(-r));
                 return r;