From 19befb2d5fc087f96e40ddc432b2cc9385666209 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 15 May 2014 01:15:30 +0200 Subject: sd-bus: introduce sd_bus_slot objects encapsulating callbacks or vtables attached to a bus connection 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). --- src/libsystemd/libsystemd.sym.m4 | 18 +- src/libsystemd/sd-bus/bus-control.h | 1 + src/libsystemd/sd-bus/bus-internal.h | 64 ++++- src/libsystemd/sd-bus/bus-match.c | 110 +++++--- src/libsystemd/sd-bus/bus-match.h | 11 +- src/libsystemd/sd-bus/bus-objects.c | 392 ++++++++------------------ src/libsystemd/sd-bus/bus-objects.h | 1 + src/libsystemd/sd-bus/bus-slot.c | 244 ++++++++++++++++ src/libsystemd/sd-bus/bus-slot.h | 29 ++ src/libsystemd/sd-bus/bus-track.c | 59 ++-- src/libsystemd/sd-bus/bus-util.c | 22 +- src/libsystemd/sd-bus/bus-util.h | 4 + src/libsystemd/sd-bus/busctl.c | 6 +- src/libsystemd/sd-bus/sd-bus.c | 330 +++++++++++----------- src/libsystemd/sd-bus/test-bus-chat.c | 8 +- src/libsystemd/sd-bus/test-bus-kernel-bloom.c | 2 +- src/libsystemd/sd-bus/test-bus-kernel.c | 2 +- src/libsystemd/sd-bus/test-bus-match.c | 59 ++-- src/libsystemd/sd-bus/test-bus-objects.c | 12 +- 19 files changed, 787 insertions(+), 587 deletions(-) create mode 100644 src/libsystemd/sd-bus/bus-slot.c create mode 100644 src/libsystemd/sd-bus/bus-slot.h (limited to 'src/libsystemd') diff --git a/src/libsystemd/libsystemd.sym.m4 b/src/libsystemd/libsystemd.sym.m4 index 14d9dcf9e9..7545ae4dc1 100644 --- a/src/libsystemd/libsystemd.sym.m4 +++ b/src/libsystemd/libsystemd.sym.m4 @@ -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; diff --git a/src/libsystemd/sd-bus/bus-control.h b/src/libsystemd/sd-bus/bus-control.h index 420e091b2e..aa290edac7 100644 --- a/src/libsystemd/sd-bus/bus-control.h +++ b/src/libsystemd/sd-bus/bus-control.h @@ -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); diff --git a/src/libsystemd/sd-bus/bus-internal.h b/src/libsystemd/sd-bus/bus-internal.h index 3dceb8a5da..042d352261 100644 --- a/src/libsystemd/sd-bus/bus-internal.h +++ b/src/libsystemd/sd-bus/bus-internal.h @@ -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); diff --git a/src/libsystemd/sd-bus/bus-match.c b/src/libsystemd/sd-bus/bus-match.c index c54ca8d71d..b868159b5c 100644 --- a/src/libsystemd/sd-bus/bus-match.c +++ b/src/libsystemd/sd-bus/bus-match.c @@ -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'); diff --git a/src/libsystemd/sd-bus/bus-match.h b/src/libsystemd/sd-bus/bus-match.h index 056082b908..af5f65d073 100644 --- a/src/libsystemd/sd-bus/bus-match.h +++ b/src/libsystemd/sd-bus/bus-match.h @@ -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); diff --git a/src/libsystemd/sd-bus/bus-objects.c b/src/libsystemd/sd-bus/bus-objects.c index 8b12e89164..f160e2343d 100644 --- a/src/libsystemd/sd-bus/bus-objects.c +++ b/src/libsystemd/sd-bus/bus-objects.c @@ -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; } diff --git a/src/libsystemd/sd-bus/bus-objects.h b/src/libsystemd/sd-bus/bus-objects.h index 420edd9478..4373fae89c 100644 --- a/src/libsystemd/sd-bus/bus-objects.h +++ b/src/libsystemd/sd-bus/bus-objects.h @@ -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 index 0000000000..8e38992ec4 --- /dev/null +++ b/src/libsystemd/sd-bus/bus-slot.c @@ -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 . +***/ + +#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 index 0000000000..23a15e4d02 --- /dev/null +++ b/src/libsystemd/sd-bus/bus-slot.h @@ -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 . +***/ + +#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); diff --git a/src/libsystemd/sd-bus/bus-track.c b/src/libsystemd/sd-bus/bus-track.c index 0f6a2eafbd..ffa2cf3d75 100644 --- a/src/libsystemd/sd-bus/bus-track.c +++ b/src/libsystemd/sd-bus/bus-track.c @@ -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) { diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c index 84b3fc5af5..b5b3c857b8 100644 --- a/src/libsystemd/sd-bus/bus-util.c +++ b/src/libsystemd/sd-bus/bus-util.c @@ -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 diff --git a/src/libsystemd/sd-bus/bus-util.h b/src/libsystemd/sd-bus/bus-util.h index 8103555fe8..1514fad81f 100644 --- a/src/libsystemd/sd-bus/bus-util.h +++ b/src/libsystemd/sd-bus/bus-util.h @@ -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) \ diff --git a/src/libsystemd/sd-bus/busctl.c b/src/libsystemd/sd-bus/busctl.c index 4e396f20c1..4545047011 100644 --- a/src/libsystemd/sd-bus/busctl.c +++ b/src/libsystemd/sd-bus/busctl.c @@ -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; diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c index dc54e211a4..ea80e9d19b 100644 --- a/src/libsystemd/sd-bus/sd-bus.c +++ b/src/libsystemd/sd-bus/sd-bus.c @@ -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) { diff --git a/src/libsystemd/sd-bus/test-bus-chat.c b/src/libsystemd/sd-bus/test-bus-chat.c index c0abc7a697..c9eb69843d 100644 --- a/src/libsystemd/sd-bus/test-bus-chat.c +++ b/src/libsystemd/sd-bus/test-bus-chat.c @@ -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; diff --git a/src/libsystemd/sd-bus/test-bus-kernel-bloom.c b/src/libsystemd/sd-bus/test-bus-kernel-bloom.c index 0ecad18f45..5ee6eea0e8 100644 --- a/src/libsystemd/sd-bus/test-bus-kernel-bloom.c +++ b/src/libsystemd/sd-bus/test-bus-kernel-bloom.c @@ -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"); diff --git a/src/libsystemd/sd-bus/test-bus-kernel.c b/src/libsystemd/sd-bus/test-bus-kernel.c index 34d000f1c6..7bb8b0a540 100644 --- a/src/libsystemd/sd-bus/test-bus-kernel.c +++ b/src/libsystemd/sd-bus/test-bus-kernel.c @@ -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"); diff --git a/src/libsystemd/sd-bus/test-bus-match.c b/src/libsystemd/sd-bus/test-bus-match.c index c561be2a65..a62de502f9 100644 --- a/src/libsystemd/sd-bus/test-bus-match.c +++ b/src/libsystemd/sd-bus/test-bus-match.c @@ -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); diff --git a/src/libsystemd/sd-bus/test-bus-objects.c b/src/libsystemd/sd-bus/test-bus-objects.c index e2423c7f67..e7a445f3cb 100644 --- a/src/libsystemd/sd-bus/test-bus-objects.c +++ b/src/libsystemd/sd-bus/test-bus-objects.c @@ -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); -- cgit v1.2.3-54-g00ecf