summaryrefslogtreecommitdiff
path: root/src/libsystemd/sd-bus/bus-track.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2016-08-22 16:11:54 +0200
committerLennart Poettering <lennart@poettering.net>2016-08-22 17:31:36 +0200
commit232f367766b35fa248476d0ded49781a06a80ae1 (patch)
treed0556cdcc1dce2b4e6636d55625397527c64e3ed /src/libsystemd/sd-bus/bus-track.c
parent8b6e65ac32627e371ee61f7d086ed33bc47e4b4c (diff)
sd-bus: when the server-side disconnects, make sure to dispatch all tracking objects immediately
If the server side kicks us from the bus, from our view no names are on the bus anymore, hence let's make sure to dispatch all tracking objects immediately.
Diffstat (limited to 'src/libsystemd/sd-bus/bus-track.c')
-rw-r--r--src/libsystemd/sd-bus/bus-track.c44
1 files changed, 42 insertions, 2 deletions
diff --git a/src/libsystemd/sd-bus/bus-track.c b/src/libsystemd/sd-bus/bus-track.c
index 90e0c7ae01..00e93a215f 100644
--- a/src/libsystemd/sd-bus/bus-track.c
+++ b/src/libsystemd/sd-bus/bus-track.c
@@ -39,9 +39,12 @@ struct sd_bus_track {
Hashmap *names;
LIST_FIELDS(sd_bus_track, queue);
Iterator iterator;
- bool in_queue:1;
+ bool in_list:1; /* In bus->tracks? */
+ bool in_queue:1; /* In bus->track_queue? */
bool modified:1;
bool recursive:1;
+
+ LIST_FIELDS(sd_bus_track, tracks);
};
#define MATCH_PREFIX \
@@ -101,6 +104,10 @@ static void bus_track_add_to_queue(sd_bus_track *track) {
if (!track->handler)
return;
+ /* Already closed? */
+ if (!track->in_list)
+ return;
+
LIST_PREPEND(queue, track->bus->track_queue, track);
track->in_queue = true;
}
@@ -156,6 +163,9 @@ _public_ int sd_bus_track_new(
t->userdata = userdata;
t->bus = sd_bus_ref(bus);
+ LIST_PREPEND(tracks, bus->tracks, t);
+ t->in_list = true;
+
bus_track_add_to_queue(t);
*track = t;
@@ -190,6 +200,9 @@ _public_ sd_bus_track* sd_bus_track_unref(sd_bus_track *track) {
while ((i = hashmap_steal_first(track->names)))
track_item_free(i);
+ if (track->in_list)
+ LIST_REMOVE(tracks, track->bus->tracks, track);
+
bus_track_remove_from_queue(track);
hashmap_free(track->names);
sd_bus_unref(track->bus);
@@ -403,7 +416,6 @@ void bus_track_dispatch(sd_bus_track *track) {
int r;
assert(track);
- assert(track->in_queue);
assert(track->handler);
bus_track_remove_from_queue(track);
@@ -419,6 +431,34 @@ void bus_track_dispatch(sd_bus_track *track) {
sd_bus_track_unref(track);
}
+void bus_track_close(sd_bus_track *track) {
+ struct track_item *i;
+
+ assert(track);
+
+ /* Called whenever our bus connected is closed. If so, and our track object is non-empty, dispatch it
+ * immediately, as we are closing now, but first flush out all names. */
+
+ if (!track->in_list)
+ return; /* We already closed this one, don't close it again. */
+
+ /* Remember that this one is closed now */
+ LIST_REMOVE(tracks, track->bus->tracks, track);
+ track->in_list = false;
+
+ /* If there's no name in this one anyway, we don't have to dispatch */
+ if (hashmap_isempty(track->names))
+ return;
+
+ /* Let's flush out all names */
+ while ((i = hashmap_steal_first(track->names)))
+ track_item_free(i);
+
+ /* Invoke handler */
+ if (track->handler)
+ bus_track_dispatch(track);
+}
+
_public_ void *sd_bus_track_get_userdata(sd_bus_track *track) {
assert_return(track, NULL);