chiark / gitweb /
sd-event: introduce concept of "floating" event sources
authorLennart Poettering <lennart@poettering.net>
Wed, 14 May 2014 23:55:18 +0000 (01:55 +0200)
committerLennart Poettering <lennart@poettering.net>
Thu, 15 May 2014 15:13:04 +0000 (17:13 +0200)
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.

src/libsystemd/sd-bus/bus-internal.h
src/libsystemd/sd-bus/bus-slot.c
src/libsystemd/sd-event/sd-event.c
src/libsystemd/sd-event/test-event.c

index 042d3522615977e48283d599cb3b2275be2de5ba..d1183d69c430c42f744dce43c2c59e2272a65183 100644 (file)
@@ -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);
 
index 8e38992ec4abc512e6c0a57bd4dc9591dbcf23ab..5e927511d5decc78039c620b516c338151998fc2 100644 (file)
@@ -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;
index 47970879da162c28d841ffecdcb4449c86f96088..06af962dfb8f4a945c8b49bb6f3cd9b5d0161296 100644 (file)
@@ -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.");
         }
index 3342ec696841ed1b801d001b3d0be9e9159b26b5..ffefb14b742ff368dbc79503f88d68b976658eef 100644 (file)
@@ -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);