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.
struct sd_bus_track {
unsigned n_ref;
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;
sd_bus *bus;
sd_bus_track_handler_t handler;
void *userdata;
static void bus_track_add_to_queue(sd_bus_track *track) {
assert(track);
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 (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;
if (!track->handler)
return;
- if (hashmap_isempty(track->names))
- bus_track_add_to_queue(track);
+ bus_track_add_to_queue(track);
track->modified = true;
return 1;
track->modified = true;
return 1;
/* First, subscribe to this name */
match = MATCH_FOR_NAME(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);
r = sd_bus_add_match(track->bus, &n->slot, match, on_name_owner_changed, track);
+ track->n_adding--;
+ if (r < 0) {
+ bus_track_add_to_queue(track);
r = hashmap_put(track->names, n->name, n);
r = hashmap_put(track->names, n->name, n);
+ if (r < 0) {
+ bus_track_add_to_queue(track);
/* Second, check if it is currently existing, or maybe doesn't, or maybe disappeared already. */
/* 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);
r = sd_bus_get_name_creds(track->bus, name, 0, NULL);
if (r < 0) {
hashmap_remove(track->names, name);
if (r < 0) {
hashmap_remove(track->names, name);
+ bus_track_add_to_queue(track);