chiark / gitweb /
sd-bus: when the server-side disconnects, make sure to dispatch all tracking objects...
authorLennart Poettering <lennart@poettering.net>
Mon, 22 Aug 2016 14:11:54 +0000 (16:11 +0200)
committerSven Eden <yamakuzure@gmx.net>
Wed, 5 Jul 2017 06:50:52 +0000 (08:50 +0200)
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.

src/libelogind/sd-bus/bus-internal.h
src/libelogind/sd-bus/bus-track.c
src/libelogind/sd-bus/bus-track.h
src/libelogind/sd-bus/sd-bus.c

index 4f08ec1..90a8eae 100644 (file)
@@ -320,6 +320,7 @@ struct sd_bus {
         sd_bus_track *track_queue;
 
         LIST_HEAD(sd_bus_slot, slots);
+        LIST_HEAD(sd_bus_track, tracks);
 };
 
 #define BUS_DEFAULT_TIMEOUT ((usec_t) (25 * USEC_PER_SEC))
index 6fbf912..77a63a9 100644 (file)
@@ -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);
@@ -420,6 +432,34 @@ void bus_track_dispatch(sd_bus_track *track) {
 }
 
 #if 0 /// UNNEEDED by elogind
+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);
 
index 7d93a72..26bd05f 100644 (file)
@@ -20,3 +20,4 @@
 ***/
 
 void bus_track_dispatch(sd_bus_track *track);
+void bus_track_close(sd_bus_track *track);
index b4a5c55..0b8d2ff 100644 (file)
@@ -109,6 +109,7 @@ static void bus_free(sd_bus *b) {
 
         assert(b);
         assert(!b->track_queue);
+        assert(!b->tracks);
 
         b->state = BUS_CLOSED;
 
@@ -2730,6 +2731,12 @@ static int process_closing(sd_bus *bus, sd_bus_message **ret) {
         if (c)
                 return process_closing_reply_callback(bus, c);
 
+        /* Then, fake-drop all remaining bus tracking references */
+        if (bus->tracks) {
+                bus_track_close(bus->tracks);
+                return 1;
+        }
+
         /* Then, synthesize a Disconnected message */
         r = sd_bus_message_new_signal(
                         bus,