From eaa22dd2515e82ba7de62259dab06fbd156284ca Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 22 Aug 2016 16:11:54 +0200 Subject: [PATCH] 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. --- src/libelogind/sd-bus/bus-internal.h | 1 + src/libelogind/sd-bus/bus-track.c | 44 ++++++++++++++++++++++++++-- src/libelogind/sd-bus/bus-track.h | 1 + src/libelogind/sd-bus/sd-bus.c | 7 +++++ 4 files changed, 51 insertions(+), 2 deletions(-) diff --git a/src/libelogind/sd-bus/bus-internal.h b/src/libelogind/sd-bus/bus-internal.h index 4f08ec19b..90a8eaec7 100644 --- a/src/libelogind/sd-bus/bus-internal.h +++ b/src/libelogind/sd-bus/bus-internal.h @@ -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)) diff --git a/src/libelogind/sd-bus/bus-track.c b/src/libelogind/sd-bus/bus-track.c index 6fbf91251..77a63a978 100644 --- a/src/libelogind/sd-bus/bus-track.c +++ b/src/libelogind/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); @@ -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); diff --git a/src/libelogind/sd-bus/bus-track.h b/src/libelogind/sd-bus/bus-track.h index 7d93a727d..26bd05f5c 100644 --- a/src/libelogind/sd-bus/bus-track.h +++ b/src/libelogind/sd-bus/bus-track.h @@ -20,3 +20,4 @@ ***/ void bus_track_dispatch(sd_bus_track *track); +void bus_track_close(sd_bus_track *track); diff --git a/src/libelogind/sd-bus/sd-bus.c b/src/libelogind/sd-bus/sd-bus.c index b4a5c554c..0b8d2fffd 100644 --- a/src/libelogind/sd-bus/sd-bus.c +++ b/src/libelogind/sd-bus/sd-bus.c @@ -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, -- 2.30.2