summaryrefslogtreecommitdiff
path: root/src/libsystemd
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2016-08-22 16:09:15 +0200
committerLennart Poettering <lennart@poettering.net>2016-08-22 16:14:21 +0200
commit8b6e65ac32627e371ee61f7d086ed33bc47e4b4c (patch)
treec5d3392ab75bbac256386cf1deefa743a4cab2b3 /src/libsystemd
parent217fcc7eb3b558e65538cbb42f47b2cb89f2850a (diff)
sd-bus: ensure we don't dispatch track objects while we are adding names to them
In order to add a name to a bus tracking object we need to do some bus operations: we need to check if the name already exists and add match for it. Both are synchronous bus calls. While processing those we need to make sure that the tracking object is not dispatched yet, as it might still be empty, but is not going to be empty for very long. hence, block dispatching by removing the object from the dispatch queue while adding it, and readding it on error.
Diffstat (limited to 'src/libsystemd')
-rw-r--r--src/libsystemd/sd-bus/bus-track.c34
1 files changed, 30 insertions, 4 deletions
diff --git a/src/libsystemd/sd-bus/bus-track.c b/src/libsystemd/sd-bus/bus-track.c
index 6ece2244c2..90e0c7ae01 100644
--- a/src/libsystemd/sd-bus/bus-track.c
+++ b/src/libsystemd/sd-bus/bus-track.c
@@ -32,6 +32,7 @@ struct track_item {
struct sd_bus_track {
unsigned n_ref;
+ unsigned n_adding; /* are we in the process of adding a new name? */
sd_bus *bus;
sd_bus_track_handler_t handler;
void *userdata;
@@ -80,9 +81,23 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(struct track_item*, track_item_free);
static void bus_track_add_to_queue(sd_bus_track *track) {
assert(track);
+ /* Adds the bus track object to the queue of objects we should dispatch next, subject to a number of
+ * conditions. */
+
+ /* Already in the queue? */
if (track->in_queue)
return;
+ /* if we are currently in the process of adding a new name, then let's not enqueue this just yet, let's wait
+ * until the addition is complete. */
+ if (track->n_adding > 0)
+ return;
+
+ /* still referenced? */
+ if (hashmap_size(track->names) > 0)
+ return;
+
+ /* Nothing to call? */
if (!track->handler)
return;
@@ -112,8 +127,7 @@ static int bus_track_remove_name_fully(sd_bus_track *track, const char *name) {
track_item_free(i);
- if (hashmap_isempty(track->names))
- bus_track_add_to_queue(track);
+ bus_track_add_to_queue(track);
track->modified = true;
return 1;
@@ -237,18 +251,30 @@ _public_ int sd_bus_track_add_name(sd_bus_track *track, const char *name) {
/* First, subscribe to this name */
match = MATCH_FOR_NAME(name);
+
+ bus_track_remove_from_queue(track); /* don't dispatch this while we work in it */
+
+ track->n_adding++; /* make sure we aren't dispatched while we synchronously add this match */
r = sd_bus_add_match(track->bus, &n->slot, match, on_name_owner_changed, track);
- if (r < 0)
+ track->n_adding--;
+ if (r < 0) {
+ bus_track_add_to_queue(track);
return r;
+ }
r = hashmap_put(track->names, n->name, n);
- if (r < 0)
+ if (r < 0) {
+ bus_track_add_to_queue(track);
return r;
+ }
/* Second, check if it is currently existing, or maybe doesn't, or maybe disappeared already. */
+ track->n_adding++; /* again, make sure this isn't dispatch while we are working in it */
r = sd_bus_get_name_creds(track->bus, name, 0, NULL);
+ track->n_adding--;
if (r < 0) {
hashmap_remove(track->names, name);
+ bus_track_add_to_queue(track);
return r;
}