[systemd-commits] 3 commits - src/libsystemd

Lennart Poettering lennart at kemper.freedesktop.org
Thu May 15 08:13:40 PDT 2014


 src/libsystemd/sd-bus/bus-internal.h     |    6 
 src/libsystemd/sd-bus/bus-match.c        |    7 -
 src/libsystemd/sd-bus/bus-objects.c      |   37 +++--
 src/libsystemd/sd-bus/bus-slot.c         |   15 +-
 src/libsystemd/sd-bus/sd-bus.c           |   76 ++++++-----
 src/libsystemd/sd-event/sd-event.c       |  206 ++++++++++++++++++-------------
 src/libsystemd/sd-event/test-event.c     |    4 
 src/libsystemd/sd-resolve/sd-resolve.c   |   90 +++++++++----
 src/libsystemd/sd-resolve/test-resolve.c |    3 
 9 files changed, 281 insertions(+), 163 deletions(-)

New commits:
commit 1b64f8382956cdd9a2afc50a7ab638529acb912e
Author: Lennart Poettering <lennart at poettering.net>
Date:   Thu May 15 17:08:24 2014 +0200

    sd-bus: always keep slot reference while dispatching callback
    
    Also, make sure we automatically destroy reply callbacks that are
    floating.

diff --git a/src/libsystemd/sd-bus/bus-match.c b/src/libsystemd/sd-bus/bus-match.c
index b868159..3391b1a 100644
--- a/src/libsystemd/sd-bus/bus-match.c
+++ b/src/libsystemd/sd-bus/bus-match.c
@@ -290,16 +290,15 @@ int bus_match_run(
 
                 /* Run the callback. And then invoke siblings. */
                 if (node->leaf.callback) {
-                        sd_bus_slot *slot;
-
                         _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
+                        sd_bus_slot *slot;
 
                         slot = container_of(node->leaf.callback, sd_bus_slot, match_callback);
                         if (bus)
-                                bus->current_slot = slot;
+                                bus->current_slot = sd_bus_slot_ref(slot);
                         r = node->leaf.callback->callback(bus, m, slot->userdata, &error_buffer);
                         if (bus)
-                                bus->current_slot = NULL;
+                                bus->current_slot = sd_bus_slot_unref(slot);
 
                         r = bus_maybe_reply_error(m, r, &error_buffer);
                         if (r != 0)
diff --git a/src/libsystemd/sd-bus/bus-objects.c b/src/libsystemd/sd-bus/bus-objects.c
index f160e23..51d4a62 100644
--- a/src/libsystemd/sd-bus/bus-objects.c
+++ b/src/libsystemd/sd-bus/bus-objects.c
@@ -50,9 +50,9 @@ static int node_vtable_get_userdata(
         s = container_of(c, sd_bus_slot, node_vtable);
         u = s->userdata;
         if (c->find) {
-                bus->current_slot = s;
+                bus->current_slot = sd_bus_slot_ref(s);
                 r = c->find(bus, path, c->interface, u, &u, error);
-                bus->current_slot = NULL;
+                bus->current_slot = sd_bus_slot_unref(s);
 
                 if (r < 0)
                         return r;
@@ -115,13 +115,16 @@ static int add_enumerated_to_set(
 
         LIST_FOREACH(enumerators, c, first) {
                 char **children = NULL, **k;
+                sd_bus_slot *slot;
 
                 if (bus->nodes_modified)
                         return 0;
 
-                bus->current_slot = container_of(c, sd_bus_slot, node_enumerator);
-                r = c->callback(bus, prefix, bus->current_slot->userdata, &children, error);
-                bus->current_slot = NULL;
+                slot = container_of(c, sd_bus_slot, node_enumerator);
+
+                bus->current_slot = sd_bus_slot_ref(slot);
+                r = c->callback(bus, prefix, slot->userdata, &children, error);
+                bus->current_slot = sd_bus_slot_unref(slot);
 
                 if (r < 0)
                         return r;
@@ -248,6 +251,7 @@ static int node_callbacks_run(
 
         LIST_FOREACH(callbacks, c, first) {
                 _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
+                sd_bus_slot *slot;
 
                 if (bus->nodes_modified)
                         return 0;
@@ -266,9 +270,11 @@ static int node_callbacks_run(
                 if (r < 0)
                         return r;
 
-                bus->current_slot = container_of(c, sd_bus_slot, node_callback);
-                r = c->callback(bus, m, bus->current_slot->userdata, &error_buffer);
-                bus->current_slot = NULL;
+                slot = container_of(c, sd_bus_slot, node_callback);
+
+                bus->current_slot = sd_bus_slot_ref(slot);
+                r = c->callback(bus, m, slot->userdata, &error_buffer);
+                bus->current_slot = sd_bus_slot_unref(slot);
 
                 r = bus_maybe_reply_error(m, r, &error_buffer);
                 if (r != 0)
@@ -394,10 +400,13 @@ static int method_callbacks_run(
         m->enforced_reply_signature = strempty(c->vtable->x.method.result);
 
         if (c->vtable->x.method.handler) {
+                sd_bus_slot *slot;
+
+                slot = container_of(c->parent, sd_bus_slot, node_vtable);
 
-                bus->current_slot = container_of(c->parent, sd_bus_slot, node_vtable);
+                bus->current_slot = sd_bus_slot_ref(slot);
                 r = c->vtable->x.method.handler(bus, m, u, &error);
-                bus->current_slot = NULL;
+                bus->current_slot = sd_bus_slot_unref(slot);
 
                 return bus_maybe_reply_error(m, r, &error);
         }
@@ -434,9 +443,9 @@ static int invoke_property_get(
 
         if (v->x.property.get) {
 
-                bus->current_slot = slot;
+                bus->current_slot = sd_bus_slot_ref(slot);
                 r = v->x.property.get(bus, path, interface, property, reply, userdata, error);
-                bus->current_slot = NULL;
+                bus->current_slot = sd_bus_slot_unref(slot);
 
                 if (r < 0)
                         return r;
@@ -496,9 +505,9 @@ static int invoke_property_set(
 
         if (v->x.property.set) {
 
-                bus->current_slot = slot;
+                bus->current_slot = sd_bus_slot_ref(slot);
                 r = v->x.property.set(bus, path, interface, property, value, userdata, error);
-                bus->current_slot = NULL;
+                bus->current_slot = sd_bus_slot_unref(slot);
 
                 if (r < 0)
                         return r;
diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c
index de947bf..ec2843f 100644
--- a/src/libsystemd/sd-bus/sd-bus.c
+++ b/src/libsystemd/sd-bus/sd-bus.c
@@ -2090,6 +2090,7 @@ static int process_timeout(sd_bus *bus) {
         _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
         _cleanup_bus_message_unref_ sd_bus_message* m = NULL;
         struct reply_callback *c;
+        sd_bus_slot *slot;
         usec_t n;
         int r;
 
@@ -2123,18 +2124,22 @@ static int process_timeout(sd_bus *bus) {
         hashmap_remove(bus->reply_callbacks, &c->cookie);
         c->cookie = 0;
 
-        bus->current_message = m;
-        bus->current_slot = container_of(c, sd_bus_slot, reply_callback);
+        slot = container_of(c, sd_bus_slot, reply_callback);
 
         bus->iteration_counter ++;
 
-        r = c->callback(bus, m, bus->current_slot->userdata, &error_buffer);
-        r = bus_maybe_reply_error(m, r, &error_buffer);
-
+        bus->current_message = m;
+        bus->current_slot = sd_bus_slot_ref(slot);
+        r = c->callback(bus, m, slot->userdata, &error_buffer);
+        bus->current_slot = sd_bus_slot_unref(slot);
         bus->current_message = NULL;
-        bus->current_slot = NULL;
 
-        return r;
+        if (slot->floating) {
+                bus_slot_disconnect(slot);
+                sd_bus_slot_unref(slot);
+        }
+
+        return bus_maybe_reply_error(m, r, &error_buffer);
 }
 
 static int process_hello(sd_bus *bus, sd_bus_message *m) {
@@ -2162,8 +2167,8 @@ static int process_hello(sd_bus *bus, sd_bus_message *m) {
 static int process_reply(sd_bus *bus, sd_bus_message *m) {
         _cleanup_bus_message_unref_ sd_bus_message *synthetic_reply = NULL;
         _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
-        sd_bus_slot *slot;
         struct reply_callback *c;
+        sd_bus_slot *slot;
         int r;
 
         assert(bus);
@@ -2184,12 +2189,8 @@ static int process_reply(sd_bus *bus, sd_bus_message *m) {
                 return 0;
 
         c->cookie = 0;
-        slot = container_of(c, sd_bus_slot, reply_callback);
 
-        if (c->timeout != 0) {
-                prioq_remove(bus->reply_callbacks_prioq, c, &c->prioq_idx);
-                c->timeout = 0;
-        }
+        slot = container_of(c, sd_bus_slot, reply_callback);
 
         if (m->n_fds > 0 && !(bus->hello_flags & KDBUS_HELLO_ACCEPT_FD)) {
 
@@ -2202,32 +2203,34 @@ static int process_reply(sd_bus *bus, sd_bus_message *m) {
                                 &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INCONSISTENT_MESSAGE, "Reply message contained file descriptor"),
                                 &synthetic_reply);
                 if (r < 0)
-                        goto finish;
+                        return r;
 
                 r = bus_seal_synthetic_message(bus, synthetic_reply);
                 if (r < 0)
-                        goto finish;
+                        return r;
 
                 m = synthetic_reply;
         } else {
                 r = sd_bus_message_rewind(m, true);
                 if (r < 0)
-                        goto finish;
+                        return r;
         }
 
-        bus->current_slot = slot;
-        r = c->callback(bus, m, bus->current_slot->userdata, &error_buffer);
-        bus->current_slot = NULL;
+        if (c->timeout != 0) {
+                prioq_remove(bus->reply_callbacks_prioq, c, &c->prioq_idx);
+                c->timeout = 0;
+        }
 
-        r = bus_maybe_reply_error(m, r, &error_buffer);
+        bus->current_slot = sd_bus_slot_ref(slot);
+        r = c->callback(bus, m, slot->userdata, &error_buffer);
+        bus->current_slot = sd_bus_slot_unref(slot);
 
-finish:
         if (slot->floating) {
                 bus_slot_disconnect(slot);
                 sd_bus_slot_unref(slot);
         }
 
-        return r;
+        return bus_maybe_reply_error(m, r, &error_buffer);
 }
 
 static int process_filter(sd_bus *bus, sd_bus_message *m) {
@@ -2242,6 +2245,7 @@ static int process_filter(sd_bus *bus, sd_bus_message *m) {
                 bus->filter_callbacks_modified = false;
 
                 LIST_FOREACH(callbacks, l, bus->filter_callbacks) {
+                        sd_bus_slot *slot;
 
                         if (bus->filter_callbacks_modified)
                                 break;
@@ -2256,9 +2260,11 @@ static int process_filter(sd_bus *bus, sd_bus_message *m) {
                         if (r < 0)
                                 return r;
 
-                        bus->current_slot = container_of(l, sd_bus_slot, filter_callback);
-                        r = l->callback(bus, m, bus->current_slot->userdata, &error_buffer);
-                        bus->current_slot = NULL;
+                        slot = container_of(l, sd_bus_slot, filter_callback);
+
+                        bus->current_slot = sd_bus_slot_ref(slot);
+                        r = l->callback(bus, m, slot->userdata, &error_buffer);
+                        bus->current_slot = sd_bus_slot_unref(slot);
 
                         r = bus_maybe_reply_error(m, r, &error_buffer);
                         if (r != 0)
@@ -2505,6 +2511,7 @@ static int process_closing(sd_bus *bus, sd_bus_message **ret) {
         c = hashmap_first(bus->reply_callbacks);
         if (c) {
                 _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
+                sd_bus_slot *slot;
 
                 /* First, fail all outstanding method calls */
                 r = bus_message_new_synthetic_error(
@@ -2527,17 +2534,22 @@ static int process_closing(sd_bus *bus, sd_bus_message **ret) {
                 hashmap_remove(bus->reply_callbacks, &c->cookie);
                 c->cookie = 0;
 
-                bus->current_message = m;
-                bus->current_slot = container_of(c, sd_bus_slot, reply_callback);
+                slot = container_of(c, sd_bus_slot, reply_callback);
 
                 bus->iteration_counter++;
 
-                r = c->callback(bus, m, bus->current_slot->userdata, &error_buffer);
-                r = bus_maybe_reply_error(m, r, &error_buffer);
-
-                bus->current_slot = NULL;
+                bus->current_message = m;
+                bus->current_slot = sd_bus_slot_ref(slot);
+                r = c->callback(bus, m, slot->userdata, &error_buffer);
+                bus->current_slot = sd_bus_slot_unref(slot);
+                bus->current_message = NULL;
+
+                if (slot->floating) {
+                        bus_slot_disconnect(slot);
+                        sd_bus_slot_unref(slot);
+                }
 
-                goto finish;
+                return bus_maybe_reply_error(m, r, &error_buffer);
         }
 
         /* Then, synthesize a Disconnected message */

commit 4a134c4903dbf6ef6c6ad55780643a5dd816d349
Author: Lennart Poettering <lennart at poettering.net>
Date:   Thu May 15 16:34:38 2014 +0200

    sd-resolve: add "floating" resolve queries
    
    Same story as for sd-bus and sd-event: allow passing NULL to store query
    in in which case the query is freed automatically.

diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c
index 06af962..c48fa37 100644
--- a/src/libsystemd/sd-event/sd-event.c
+++ b/src/libsystemd/sd-event/sd-event.c
@@ -718,9 +718,9 @@ static sd_event_source *source_new(sd_event *e, bool floating, EventSourceType t
 
         s->n_ref = 1;
         s->event = e;
+        s->floating = floating;
         s->type = type;
         s->pending_index = s->prepare_index = PRIOQ_IDX_NULL;
-        s->floating = floating;
 
         if (!floating)
                 sd_event_ref(e);
diff --git a/src/libsystemd/sd-resolve/sd-resolve.c b/src/libsystemd/sd-resolve/sd-resolve.c
index 3f699ce..09ab6f0 100644
--- a/src/libsystemd/sd-resolve/sd-resolve.c
+++ b/src/libsystemd/sd-resolve/sd-resolve.c
@@ -86,7 +86,7 @@ struct sd_resolve {
         unsigned n_valid_workers;
 
         unsigned current_id, current_index;
-        sd_resolve_query* queries[QUERIES_MAX];
+        sd_resolve_query* query_array[QUERIES_MAX];
         unsigned n_queries, n_done;
 
         sd_event_source *event_source;
@@ -96,6 +96,8 @@ struct sd_resolve {
 
         sd_resolve **default_resolve_ptr;
         pid_t tid;
+
+        LIST_HEAD(sd_resolve_query, queries);
 };
 
 struct sd_resolve_query {
@@ -105,6 +107,7 @@ struct sd_resolve_query {
 
         QueryType type:4;
         bool done:1;
+        bool floating:1;
         unsigned id;
 
         int ret;
@@ -121,6 +124,8 @@ struct sd_resolve_query {
         };
 
         void *userdata;
+
+        LIST_FIELDS(sd_resolve_query, queries);
 };
 
 typedef struct RHeader {
@@ -200,6 +205,8 @@ static int getaddrinfo_done(sd_resolve_query* q);
 static int getnameinfo_done(sd_resolve_query *q);
 static int res_query_done(sd_resolve_query* q);
 
+static void resolve_query_disconnect(sd_resolve_query *q);
+
 #define RESOLVE_DONT_DESTROY(resolve) \
         _cleanup_resolve_unref_ _unused_ sd_resolve *_dont_destroy_##resolve = sd_resolve_ref(resolve)
 
@@ -630,10 +637,17 @@ _public_ int sd_resolve_get_tid(sd_resolve *resolve, pid_t *tid) {
 
 static void resolve_free(sd_resolve *resolve) {
         PROTECT_ERRNO;
+        sd_resolve_query *q;
         unsigned i;
 
         assert(resolve);
 
+        while ((q = resolve->queries)) {
+                assert(q->floating);
+                resolve_query_disconnect(q);
+                sd_resolve_query_unref(q);
+        }
+
         if (resolve->default_resolve_ptr)
                 *(resolve->default_resolve_ptr) = NULL;
 
@@ -719,7 +733,7 @@ static sd_resolve_query *lookup_query(sd_resolve *resolve, unsigned id) {
 
         assert(resolve);
 
-        q = resolve->queries[id % QUERIES_MAX];
+        q = resolve->query_array[id % QUERIES_MAX];
         if (q)
                 if (q->id == id)
                         return q;
@@ -760,6 +774,11 @@ static int complete_query(sd_resolve *resolve, sd_resolve_query *q) {
 
         resolve->current = sd_resolve_query_unref(q);
 
+        if (q->floating) {
+                resolve_query_disconnect(q);
+                sd_bus_slot_unref(q);
+        }
+
         return r;
 }
 
@@ -989,7 +1008,7 @@ _public_ int sd_resolve_wait(sd_resolve *resolve, uint64_t timeout_usec) {
         return sd_resolve_process(resolve);
 }
 
-static int alloc_query(sd_resolve *resolve, sd_resolve_query **_q) {
+static int alloc_query(sd_resolve *resolve, bool floating, sd_resolve_query **_q) {
         sd_resolve_query *q;
         int r;
 
@@ -1003,21 +1022,26 @@ static int alloc_query(sd_resolve *resolve, sd_resolve_query **_q) {
         if (r < 0)
                 return r;
 
-        while (resolve->queries[resolve->current_index]) {
+        while (resolve->query_array[resolve->current_index]) {
                 resolve->current_index++;
                 resolve->current_id++;
 
                 resolve->current_index %= QUERIES_MAX;
         }
 
-        q = resolve->queries[resolve->current_index] = new0(sd_resolve_query, 1);
+        q = resolve->query_array[resolve->current_index] = new0(sd_resolve_query, 1);
         if (!q)
                 return -ENOMEM;
 
         q->n_ref = 1;
-        q->resolve = sd_resolve_ref(resolve);
+        q->resolve = resolve;
+        q->floating = floating;
         q->id = resolve->current_id;
 
+        if (!floating)
+                sd_resolve_ref(resolve);
+
+        LIST_PREPEND(queries, resolve->queries, q);
         resolve->n_queries++;
 
         *_q = q;
@@ -1038,12 +1062,11 @@ _public_ int sd_resolve_getaddrinfo(
         int r;
 
         assert_return(resolve, -EINVAL);
-        assert_return(_q, -EINVAL);
         assert_return(node || service, -EINVAL);
         assert_return(callback, -EINVAL);
         assert_return(!resolve_pid_changed(resolve), -ECHILD);
 
-        r = alloc_query(resolve, &q);
+        r = alloc_query(resolve, !_q, &q);
         if (r < 0)
                 return r;
 
@@ -1078,7 +1101,9 @@ _public_ int sd_resolve_getaddrinfo(
                 return -errno;
         }
 
-        *_q = q;
+        if (_q)
+                *_q = q;
+
         return 0;
 }
 
@@ -1109,7 +1134,6 @@ _public_ int sd_resolve_getnameinfo(
         int r;
 
         assert_return(resolve, -EINVAL);
-        assert_return(_q, -EINVAL);
         assert_return(sa, -EINVAL);
         assert_return(salen >= sizeof(struct sockaddr), -EINVAL);
         assert_return(salen <= sizeof(union sockaddr_union), -EINVAL);
@@ -1117,7 +1141,7 @@ _public_ int sd_resolve_getnameinfo(
         assert_return(callback, -EINVAL);
         assert_return(!resolve_pid_changed(resolve), -ECHILD);
 
-        r = alloc_query(resolve, &q);
+        r = alloc_query(resolve, !_q, &q);
         if (r < 0)
                 return r;
 
@@ -1145,7 +1169,9 @@ _public_ int sd_resolve_getnameinfo(
                 return -errno;
         }
 
-        *_q = q;
+        if (_q)
+                *_q = q;
+
         return 0;
 }
 
@@ -1176,12 +1202,11 @@ static int resolve_res(
         int r;
 
         assert_return(resolve, -EINVAL);
-        assert_return(_q, -EINVAL);
         assert_return(dname, -EINVAL);
         assert_return(callback, -EINVAL);
         assert_return(!resolve_pid_changed(resolve), -ECHILD);
 
-        r = alloc_query(resolve, &q);
+        r = alloc_query(resolve, !_q, &q);
         if (r < 0)
                 return r;
 
@@ -1208,7 +1233,9 @@ static int resolve_res(
                 return -errno;
         }
 
-        *_q = q;
+        if (_q)
+                *_q = q;
+
         return 0;
 }
 
@@ -1251,23 +1278,38 @@ static void resolve_freeaddrinfo(struct addrinfo *ai) {
         }
 }
 
-static void resolve_query_free(sd_resolve_query *q) {
+static void resolve_query_disconnect(sd_resolve_query *q) {
+        sd_resolve *resolve;
         unsigned i;
 
         assert(q);
-        assert(q->resolve);
-        assert(q->resolve->n_queries > 0);
+
+        if (!q->resolve)
+                return;
+
+        resolve = q->resolve;
+        assert(resolve->n_queries > 0);
 
         if (q->done) {
-                assert(q->resolve->n_done > 0);
-                q->resolve->n_done--;
+                assert(resolve->n_done > 0);
+                resolve->n_done--;
         }
 
         i = q->id % QUERIES_MAX;
-        assert(q->resolve->queries[i] == q);
-        q->resolve->queries[i] = NULL;
-        q->resolve->n_queries--;
-        sd_resolve_unref(q->resolve);
+        assert(resolve->query_array[i] == q);
+        resolve->query_array[i] = NULL;
+        LIST_REMOVE(queries, resolve->queries, q);
+        resolve->n_queries--;
+
+        q->resolve = NULL;
+        if (!q->floating)
+                sd_resolve_unref(resolve);
+}
+
+static void resolve_query_free(sd_resolve_query *q) {
+        assert(q);
+
+        resolve_query_disconnect(q);
 
         resolve_freeaddrinfo(q->addrinfo);
         free(q->host);
diff --git a/src/libsystemd/sd-resolve/test-resolve.c b/src/libsystemd/sd-resolve/test-resolve.c
index 3717286..c6c3bfb 100644
--- a/src/libsystemd/sd-resolve/test-resolve.c
+++ b/src/libsystemd/sd-resolve/test-resolve.c
@@ -140,6 +140,9 @@ int main(int argc, char *argv[]) {
 
         assert_se(sd_resolve_default(&resolve) >= 0);
 
+        /* Test a floating resolver query */
+        sd_resolve_getaddrinfo(resolve, NULL, "redhat.com", "http", NULL, getaddrinfo_handler, NULL);
+
         /* Make a name -> address query */
         r = sd_resolve_getaddrinfo(resolve, &q1, argc >= 2 ? argv[1] : "www.heise.de", NULL, &hints, getaddrinfo_handler, NULL);
         if (r < 0)

commit a71fe8b8aee1cb78c4d8c56eeb234743f64e4b4d
Author: Lennart Poettering <lennart at poettering.net>
Date:   Thu May 15 01:55:18 2014 +0200

    sd-event: introduce concept of "floating" event sources
    
    These are the counterpart of "floating" bus slots, i.e. event sources
    that are bound to the lifetime of the event object itself, and thus
    don't require an explicit reference to be kept.

diff --git a/src/libsystemd/sd-bus/bus-internal.h b/src/libsystemd/sd-bus/bus-internal.h
index 042d352..d1183d6 100644
--- a/src/libsystemd/sd-bus/bus-internal.h
+++ b/src/libsystemd/sd-bus/bus-internal.h
@@ -126,7 +126,6 @@ struct vtable_member {
 };
 
 typedef enum BusSlotType {
-        _BUS_SLOT_DISCONNECTED,
         BUS_REPLY_CALLBACK,
         BUS_FILTER_CALLBACK,
         BUS_MATCH_CALLBACK,
@@ -134,14 +133,15 @@ typedef enum BusSlotType {
         BUS_NODE_ENUMERATOR,
         BUS_NODE_VTABLE,
         BUS_NODE_OBJECT_MANAGER,
+        _BUS_SLOT_INVALID = -1,
 } BusSlotType;
 
 struct sd_bus_slot {
         unsigned n_ref;
         sd_bus *bus;
         void *userdata;
-        BusSlotType type;
-        bool floating;
+        BusSlotType type:5;
+        bool floating:1;
 
         LIST_FIELDS(sd_bus_slot, slots);
 
diff --git a/src/libsystemd/sd-bus/bus-slot.c b/src/libsystemd/sd-bus/bus-slot.c
index 8e38992..5e92751 100644
--- a/src/libsystemd/sd-bus/bus-slot.c
+++ b/src/libsystemd/sd-bus/bus-slot.c
@@ -67,12 +67,11 @@ void bus_slot_disconnect(sd_bus_slot *slot) {
 
         assert(slot);
 
-        switch (slot->type) {
-
-        case _BUS_SLOT_DISCONNECTED:
-                /* Already disconnected... */
+        if (!slot->bus)
                 return;
 
+        switch (slot->type) {
+
         case BUS_REPLY_CALLBACK:
 
                 if (slot->reply_callback.cookie != 0)
@@ -181,10 +180,14 @@ void bus_slot_disconnect(sd_bus_slot *slot) {
                 }
 
                 break;
+
+        default:
+                assert_not_reached("Wut? Unknown slot type?");
         }
+
         bus = slot->bus;
 
-        slot->type = _BUS_SLOT_DISCONNECTED;
+        slot->type = _BUS_SLOT_INVALID;
         slot->bus = NULL;
         LIST_REMOVE(slots, bus->slots, slot);
 
@@ -235,7 +238,7 @@ _public_ void *sd_bus_slot_set_userdata(sd_bus_slot *slot, void *userdata) {
 
 _public_ sd_bus_message *sd_bus_slot_get_current_message(sd_bus_slot *slot) {
         assert_return(slot, NULL);
-        assert_return(slot->type != _BUS_SLOT_DISCONNECTED, NULL);
+        assert_return(slot->type >= 0, NULL);
 
         if (slot->bus->current_slot != slot)
                 return NULL;
diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c
index 4797087..06af962 100644
--- a/src/libsystemd/sd-event/sd-event.c
+++ b/src/libsystemd/sd-event/sd-event.c
@@ -33,6 +33,7 @@
 #include "time-util.h"
 #include "missing.h"
 #include "set.h"
+#include "list.h"
 
 #include "sd-event.h"
 
@@ -51,7 +52,7 @@ typedef enum EventSourceType {
         SOURCE_POST,
         SOURCE_EXIT,
         SOURCE_WATCHDOG,
-        _SOUFCE_EVENT_SOURCE_TYPE_MAX,
+        _SOURCE_EVENT_SOURCE_TYPE_MAX,
         _SOURCE_EVENT_SOURCE_TYPE_INVALID = -1
 } EventSourceType;
 
@@ -68,6 +69,7 @@ struct sd_event_source {
         int enabled:3;
         bool pending:1;
         bool dispatching:1;
+        bool floating:1;
 
         int64_t priority;
         unsigned pending_index;
@@ -75,6 +77,8 @@ struct sd_event_source {
         unsigned pending_iteration;
         unsigned prepare_iteration;
 
+        LIST_FIELDS(sd_event_source, sources);
+
         union {
                 struct {
                         sd_event_io_handler_t callback;
@@ -177,8 +181,12 @@ struct sd_event {
         usec_t watchdog_last, watchdog_period;
 
         unsigned n_sources;
+
+        LIST_HEAD(sd_event_source, sources);
 };
 
+static void source_disconnect(sd_event_source *s);
+
 static int pending_prioq_compare(const void *a, const void *b) {
         const sd_event_source *x = a, *y = b;
 
@@ -349,7 +357,16 @@ static void free_clock_data(struct clock_data *d) {
 }
 
 static void event_free(sd_event *e) {
+        sd_event_source *s;
+
         assert(e);
+
+        while ((s = e->sources)) {
+                assert(s->floating);
+                source_disconnect(s);
+                sd_event_source_unref(s);
+        }
+
         assert(e->n_sources == 0);
 
         if (e->default_event_ptr)
@@ -557,86 +574,101 @@ static struct clock_data* event_get_clock_data(sd_event *e, EventSourceType t) {
         }
 }
 
-static void source_free(sd_event_source *s) {
+static void source_disconnect(sd_event_source *s) {
+        sd_event *event;
+
         assert(s);
 
-        if (s->event) {
-                assert(s->event->n_sources > 0);
+        if (!s->event)
+                return;
 
-                switch (s->type) {
+        assert(s->event->n_sources > 0);
 
-                case SOURCE_IO:
-                        if (s->io.fd >= 0)
-                                source_io_unregister(s);
+        switch (s->type) {
 
-                        break;
+        case SOURCE_IO:
+                if (s->io.fd >= 0)
+                        source_io_unregister(s);
 
-                case SOURCE_TIME_REALTIME:
-                case SOURCE_TIME_MONOTONIC:
-                case SOURCE_TIME_REALTIME_ALARM:
-                case SOURCE_TIME_BOOTTIME_ALARM: {
-                        struct clock_data *d;
+                break;
 
-                        d = event_get_clock_data(s->event, s->type);
-                        assert(d);
+        case SOURCE_TIME_REALTIME:
+        case SOURCE_TIME_MONOTONIC:
+        case SOURCE_TIME_REALTIME_ALARM:
+        case SOURCE_TIME_BOOTTIME_ALARM: {
+                struct clock_data *d;
 
-                        prioq_remove(d->earliest, s, &s->time.earliest_index);
-                        prioq_remove(d->latest, s, &s->time.latest_index);
-                        break;
+                d = event_get_clock_data(s->event, s->type);
+                assert(d);
+
+                prioq_remove(d->earliest, s, &s->time.earliest_index);
+                prioq_remove(d->latest, s, &s->time.latest_index);
+                break;
+        }
+
+        case SOURCE_SIGNAL:
+                if (s->signal.sig > 0) {
+                        if (s->signal.sig != SIGCHLD || s->event->n_enabled_child_sources == 0)
+                                assert_se(sigdelset(&s->event->sigset, s->signal.sig) == 0);
+
+                        if (s->event->signal_sources)
+                                s->event->signal_sources[s->signal.sig] = NULL;
                 }
 
-                case SOURCE_SIGNAL:
-                        if (s->signal.sig > 0) {
-                                if (s->signal.sig != SIGCHLD || s->event->n_enabled_child_sources == 0)
-                                        assert_se(sigdelset(&s->event->sigset, s->signal.sig) == 0);
+                break;
 
-                                if (s->event->signal_sources)
-                                        s->event->signal_sources[s->signal.sig] = NULL;
+        case SOURCE_CHILD:
+                if (s->child.pid > 0) {
+                        if (s->enabled != SD_EVENT_OFF) {
+                                assert(s->event->n_enabled_child_sources > 0);
+                                s->event->n_enabled_child_sources--;
                         }
 
-                        break;
+                        if (!s->event->signal_sources || !s->event->signal_sources[SIGCHLD])
+                                assert_se(sigdelset(&s->event->sigset, SIGCHLD) == 0);
 
-                case SOURCE_CHILD:
-                        if (s->child.pid > 0) {
-                                if (s->enabled != SD_EVENT_OFF) {
-                                        assert(s->event->n_enabled_child_sources > 0);
-                                        s->event->n_enabled_child_sources--;
-                                }
+                        hashmap_remove(s->event->child_sources, INT_TO_PTR(s->child.pid));
+                }
 
-                                if (!s->event->signal_sources || !s->event->signal_sources[SIGCHLD])
-                                        assert_se(sigdelset(&s->event->sigset, SIGCHLD) == 0);
+                break;
 
-                                hashmap_remove(s->event->child_sources, INT_TO_PTR(s->child.pid));
-                        }
+        case SOURCE_DEFER:
+                /* nothing */
+                break;
 
-                        break;
+        case SOURCE_POST:
+                set_remove(s->event->post_sources, s);
+                break;
 
-                case SOURCE_DEFER:
-                        /* nothing */
-                        break;
+        case SOURCE_EXIT:
+                prioq_remove(s->event->exit, s, &s->exit.prioq_index);
+                break;
 
-                case SOURCE_POST:
-                        set_remove(s->event->post_sources, s);
-                        break;
+        default:
+                assert_not_reached("Wut? I shouldn't exist.");
+        }
 
-                case SOURCE_EXIT:
-                        prioq_remove(s->event->exit, s, &s->exit.prioq_index);
-                        break;
+        if (s->pending)
+                prioq_remove(s->event->pending, s, &s->pending_index);
 
-                default:
-                        assert_not_reached("Wut? I shouldn't exist.");
-                }
+        if (s->prepare)
+                prioq_remove(s->event->prepare, s, &s->prepare_index);
 
-                if (s->pending)
-                        prioq_remove(s->event->pending, s, &s->pending_index);
+        event = s->event;
 
-                if (s->prepare)
-                        prioq_remove(s->event->prepare, s, &s->prepare_index);
+        s->type = _SOURCE_EVENT_SOURCE_TYPE_INVALID;
+        s->event = NULL;
+        LIST_REMOVE(sources, event->sources, s);
+        event->n_sources--;
 
-                s->event->n_sources--;
-                sd_event_unref(s->event);
-        }
+        if (!s->floating)
+                sd_event_unref(event);
+}
+
+static void source_free(sd_event_source *s) {
+        assert(s);
 
+        source_disconnect(s);
         free(s);
 }
 
@@ -675,7 +707,7 @@ static int source_set_pending(sd_event_source *s, bool b) {
         return 0;
 }
 
-static sd_event_source *source_new(sd_event *e, EventSourceType type) {
+static sd_event_source *source_new(sd_event *e, bool floating, EventSourceType type) {
         sd_event_source *s;
 
         assert(e);
@@ -685,10 +717,15 @@ static sd_event_source *source_new(sd_event *e, EventSourceType type) {
                 return NULL;
 
         s->n_ref = 1;
-        s->event = sd_event_ref(e);
+        s->event = e;
         s->type = type;
         s->pending_index = s->prepare_index = PRIOQ_IDX_NULL;
+        s->floating = floating;
+
+        if (!floating)
+                sd_event_ref(e);
 
+        LIST_PREPEND(sources, e->sources, s);
         e->n_sources ++;
 
         return s;
@@ -709,11 +746,10 @@ _public_ int sd_event_add_io(
         assert_return(fd >= 0, -EINVAL);
         assert_return(!(events & ~(EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLPRI|EPOLLERR|EPOLLHUP|EPOLLET)), -EINVAL);
         assert_return(callback, -EINVAL);
-        assert_return(ret, -EINVAL);
         assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
         assert_return(!event_pid_changed(e), -ECHILD);
 
-        s = source_new(e, SOURCE_IO);
+        s = source_new(e, !ret, SOURCE_IO);
         if (!s)
                 return -ENOMEM;
 
@@ -729,7 +765,9 @@ _public_ int sd_event_add_io(
                 return -errno;
         }
 
-        *ret = s;
+        if (ret)
+                *ret = s;
+
         return 0;
 }
 
@@ -798,7 +836,6 @@ _public_ int sd_event_add_time(
         int r;
 
         assert_return(e, -EINVAL);
-        assert_return(ret, -EINVAL);
         assert_return(usec != (uint64_t) -1, -EINVAL);
         assert_return(accuracy != (uint64_t) -1, -EINVAL);
         assert_return(callback, -EINVAL);
@@ -829,7 +866,7 @@ _public_ int sd_event_add_time(
                         return r;
         }
 
-        s = source_new(e, type);
+        s = source_new(e, !ret, type);
         if (!s)
                 return -ENOMEM;
 
@@ -848,7 +885,9 @@ _public_ int sd_event_add_time(
         if (r < 0)
                 goto fail;
 
-        *ret = s;
+        if (ret)
+                *ret = s;
+
         return 0;
 
 fail:
@@ -906,7 +945,6 @@ _public_ int sd_event_add_signal(
         assert_return(e, -EINVAL);
         assert_return(sig > 0, -EINVAL);
         assert_return(sig < _NSIG, -EINVAL);
-        assert_return(ret, -EINVAL);
         assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
         assert_return(!event_pid_changed(e), -ECHILD);
 
@@ -927,7 +965,7 @@ _public_ int sd_event_add_signal(
         } else if (e->signal_sources[sig])
                 return -EBUSY;
 
-        s = source_new(e, SOURCE_SIGNAL);
+        s = source_new(e, !ret, SOURCE_SIGNAL);
         if (!s)
                 return -ENOMEM;
 
@@ -947,7 +985,9 @@ _public_ int sd_event_add_signal(
                 }
         }
 
-        *ret = s;
+        if (ret)
+                *ret = s;
+
         return 0;
 }
 
@@ -967,7 +1007,6 @@ _public_ int sd_event_add_child(
         assert_return(!(options & ~(WEXITED|WSTOPPED|WCONTINUED)), -EINVAL);
         assert_return(options != 0, -EINVAL);
         assert_return(callback, -EINVAL);
-        assert_return(ret, -EINVAL);
         assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
         assert_return(!event_pid_changed(e), -ECHILD);
 
@@ -978,7 +1017,7 @@ _public_ int sd_event_add_child(
         if (hashmap_contains(e->child_sources, INT_TO_PTR(pid)))
                 return -EBUSY;
 
-        s = source_new(e, SOURCE_CHILD);
+        s = source_new(e, !ret, SOURCE_CHILD);
         if (!s)
                 return -ENOMEM;
 
@@ -1008,7 +1047,9 @@ _public_ int sd_event_add_child(
 
         e->need_process_child = true;
 
-        *ret = s;
+        if (ret)
+                *ret = s;
+
         return 0;
 }
 
@@ -1023,11 +1064,10 @@ _public_ int sd_event_add_defer(
 
         assert_return(e, -EINVAL);
         assert_return(callback, -EINVAL);
-        assert_return(ret, -EINVAL);
         assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
         assert_return(!event_pid_changed(e), -ECHILD);
 
-        s = source_new(e, SOURCE_DEFER);
+        s = source_new(e, !ret, SOURCE_DEFER);
         if (!s)
                 return -ENOMEM;
 
@@ -1041,7 +1081,9 @@ _public_ int sd_event_add_defer(
                 return r;
         }
 
-        *ret = s;
+        if (ret)
+                *ret = s;
+
         return 0;
 }
 
@@ -1056,7 +1098,6 @@ _public_ int sd_event_add_post(
 
         assert_return(e, -EINVAL);
         assert_return(callback, -EINVAL);
-        assert_return(ret, -EINVAL);
         assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
         assert_return(!event_pid_changed(e), -ECHILD);
 
@@ -1064,7 +1105,7 @@ _public_ int sd_event_add_post(
         if (r < 0)
                 return r;
 
-        s = source_new(e, SOURCE_POST);
+        s = source_new(e, !ret, SOURCE_POST);
         if (!s)
                 return -ENOMEM;
 
@@ -1078,7 +1119,9 @@ _public_ int sd_event_add_post(
                 return r;
         }
 
-        *ret = s;
+        if (ret)
+                *ret = s;
+
         return 0;
 }
 
@@ -1093,7 +1136,6 @@ _public_ int sd_event_add_exit(
 
         assert_return(e, -EINVAL);
         assert_return(callback, -EINVAL);
-        assert_return(ret, -EINVAL);
         assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
         assert_return(!event_pid_changed(e), -ECHILD);
 
@@ -1103,7 +1145,7 @@ _public_ int sd_event_add_exit(
                         return -ENOMEM;
         }
 
-        s = source_new(e, SOURCE_EXIT);
+        s = source_new(e, !ret, SOURCE_EXIT);
         if (!s)
                 return -ENOMEM;
 
@@ -1118,7 +1160,9 @@ _public_ int sd_event_add_exit(
                 return r;
         }
 
-        *ret = s;
+        if (ret)
+                *ret = s;
+
         return 0;
 }
 
@@ -1151,6 +1195,8 @@ _public_ sd_event_source* sd_event_source_unref(sd_event_source *s) {
                 if (s->dispatching) {
                         if (s->type == SOURCE_IO)
                                 source_io_unregister(s);
+
+                        source_disconnect(s);
                 } else
                         source_free(s);
         }
@@ -1995,7 +2041,7 @@ static int source_dispatch(sd_event_source *s) {
                 break;
 
         case SOURCE_WATCHDOG:
-        case _SOUFCE_EVENT_SOURCE_TYPE_MAX:
+        case _SOURCE_EVENT_SOURCE_TYPE_MAX:
         case _SOURCE_EVENT_SOURCE_TYPE_INVALID:
                 assert_not_reached("Wut? I shouldn't exist.");
         }
diff --git a/src/libsystemd/sd-event/test-event.c b/src/libsystemd/sd-event/test-event.c
index 3342ec6..ffefb14 100644
--- a/src/libsystemd/sd-event/test-event.c
+++ b/src/libsystemd/sd-event/test-event.c
@@ -206,6 +206,10 @@ int main(int argc, char *argv[]) {
         assert_se(sd_event_source_set_enabled(z, SD_EVENT_ONESHOT) >= 0);
         assert_se(sd_event_source_set_prepare(z, prepare_handler) >= 0);
 
+        /* Test for floating event sources */
+        assert_se(sigprocmask_many(SIG_BLOCK, SIGRTMIN+1, -1) == 0);
+        assert_se(sd_event_add_signal(e, NULL, SIGRTMIN+1, NULL, NULL) >= 0);
+
         assert_se(write(a[1], &ch, 1) >= 0);
         assert_se(write(b[1], &ch, 1) >= 0);
 



More information about the systemd-commits mailing list