Zbigniew Jędrzejewski-Szmek 62fe94
From c45a5a74465a39280b855f9d720b2ab4779a47fa Mon Sep 17 00:00:00 2001
Zbigniew Jędrzejewski-Szmek 62fe94
From: Tom Gundersen <teg@jklm.no>
Zbigniew Jędrzejewski-Szmek 62fe94
Date: Fri, 15 Aug 2014 18:49:29 +0200
Zbigniew Jędrzejewski-Szmek 62fe94
Subject: [PATCH] sd-event: split run into prepare/wait/dispatch
Zbigniew Jędrzejewski-Szmek 62fe94
Zbigniew Jędrzejewski-Szmek 62fe94
This will allow sd-event to be integrated into an external event loop, which
Zbigniew Jędrzejewski-Szmek 62fe94
in turn will allow (say) glib-based applications to use our various libraries,
Zbigniew Jędrzejewski-Szmek 62fe94
without manually integrating each of them (bus, rtnl, dhcp, ...).
Zbigniew Jędrzejewski-Szmek 62fe94
Zbigniew Jędrzejewski-Szmek 62fe94
The external event-loop should integrate sd-event int he following way:
Zbigniew Jędrzejewski-Szmek 62fe94
Zbigniew Jędrzejewski-Szmek 62fe94
Every iteration must start with a call to sd_event_prepare(), which will
Zbigniew Jędrzejewski-Szmek 62fe94
return 0 if no event sources are ready to be processed, a positive value if
Zbigniew Jędrzejewski-Szmek 62fe94
they are and a negative value on error. sd_event_prepare() may only be called
Zbigniew Jędrzejewski-Szmek 62fe94
following sd_event_dispatch(); a call to sd_event_wait() indicating that no
Zbigniew Jędrzejewski-Szmek 62fe94
sources are ready to be dispatched; or a failed call to sd_event_dispatch() or
Zbigniew Jędrzejewski-Szmek 62fe94
sd_event_wait().
Zbigniew Jędrzejewski-Szmek 62fe94
Zbigniew Jędrzejewski-Szmek 62fe94
A successful call to sd_event_prepare() indicating that no event sources are
Zbigniew Jędrzejewski-Szmek 62fe94
ready to be dispatched must be followed by a call to sd_event_wait(),
Zbigniew Jędrzejewski-Szmek 62fe94
which will return 0 if it timed out without event sources being ready to
Zbigniew Jędrzejewski-Szmek 62fe94
be processed, a negative value on error and a positive value otherwise.
Zbigniew Jędrzejewski-Szmek 62fe94
sd_event_wait() may only be called following a successful call to
Zbigniew Jędrzejewski-Szmek 62fe94
sd_event_prepare() indicating that no event sources are ready to be dispatched.
Zbigniew Jędrzejewski-Szmek 62fe94
Zbigniew Jędrzejewski-Szmek 62fe94
If sd_event_wait() indicates that some events sources are ready to be
Zbigniew Jędrzejewski-Szmek 62fe94
dispatched, it must be followed by a call to sd_event_dispatch(). This
Zbigniew Jędrzejewski-Szmek 62fe94
is the only time sd_event_dispatch() may be called.
Zbigniew Jędrzejewski-Szmek 62fe94
---
Zbigniew Jędrzejewski-Szmek 62fe94
 src/libsystemd/sd-event/sd-event.c | 122 +++++++++++++++++++++++++++++--------
Zbigniew Jędrzejewski-Szmek 62fe94
 src/systemd/sd-event.h             |   5 ++
Zbigniew Jędrzejewski-Szmek 62fe94
 2 files changed, 102 insertions(+), 25 deletions(-)
Zbigniew Jędrzejewski-Szmek 62fe94
Zbigniew Jędrzejewski-Szmek 62fe94
diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c
Zbigniew Jędrzejewski-Szmek 62fe94
index e062997a80..a71962c24c 100644
Zbigniew Jędrzejewski-Szmek 62fe94
--- a/src/libsystemd/sd-event/sd-event.c
Zbigniew Jędrzejewski-Szmek 62fe94
+++ b/src/libsystemd/sd-event/sd-event.c
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -2210,12 +2210,8 @@ static int process_watchdog(sd_event *e) {
Zbigniew Jędrzejewski-Szmek 62fe94
         return arm_watchdog(e);
Zbigniew Jędrzejewski-Szmek 62fe94
 }
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
-_public_ int sd_event_run(sd_event *e, uint64_t timeout) {
Zbigniew Jędrzejewski-Szmek 62fe94
-        struct epoll_event *ev_queue;
Zbigniew Jędrzejewski-Szmek 62fe94
-        unsigned ev_queue_max;
Zbigniew Jędrzejewski-Szmek 62fe94
-        sd_event_source *p;
Zbigniew Jędrzejewski-Szmek 62fe94
-        int r, i, m;
Zbigniew Jędrzejewski-Szmek 62fe94
-        bool timedout;
Zbigniew Jędrzejewski-Szmek 62fe94
+_public_ int sd_event_prepare(sd_event *e) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        int r;
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
         assert_return(e, -EINVAL);
Zbigniew Jędrzejewski-Szmek 62fe94
         assert_return(!event_pid_changed(e), -ECHILD);
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -2223,38 +2219,60 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) {
Zbigniew Jędrzejewski-Szmek 62fe94
         assert_return(e->state == SD_EVENT_PASSIVE, -EBUSY);
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
         if (e->exit_requested)
Zbigniew Jędrzejewski-Szmek 62fe94
-                return dispatch_exit(e);
Zbigniew Jędrzejewski-Szmek 62fe94
+                goto pending;
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
-        sd_event_ref(e);
Zbigniew Jędrzejewski-Szmek 62fe94
         e->iteration++;
Zbigniew Jędrzejewski-Szmek 62fe94
-        e->state = SD_EVENT_RUNNING;
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
         r = event_prepare(e);
Zbigniew Jędrzejewski-Szmek 62fe94
         if (r < 0)
Zbigniew Jędrzejewski-Szmek 62fe94
-                goto finish;
Zbigniew Jędrzejewski-Szmek 62fe94
+                return r;
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
         r = event_arm_timer(e, &e->realtime);
Zbigniew Jędrzejewski-Szmek 62fe94
         if (r < 0)
Zbigniew Jędrzejewski-Szmek 62fe94
-                goto finish;
Zbigniew Jędrzejewski-Szmek 62fe94
+                return r;
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
         r = event_arm_timer(e, &e->boottime);
Zbigniew Jędrzejewski-Szmek 62fe94
         if (r < 0)
Zbigniew Jędrzejewski-Szmek 62fe94
-                goto finish;
Zbigniew Jędrzejewski-Szmek 62fe94
+                return r;
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
         r = event_arm_timer(e, &e->monotonic);
Zbigniew Jędrzejewski-Szmek 62fe94
         if (r < 0)
Zbigniew Jędrzejewski-Szmek 62fe94
-                goto finish;
Zbigniew Jędrzejewski-Szmek 62fe94
+                return r;
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
         r = event_arm_timer(e, &e->realtime_alarm);
Zbigniew Jędrzejewski-Szmek 62fe94
         if (r < 0)
Zbigniew Jędrzejewski-Szmek 62fe94
-                goto finish;
Zbigniew Jędrzejewski-Szmek 62fe94
+                return r;
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
         r = event_arm_timer(e, &e->boottime_alarm);
Zbigniew Jędrzejewski-Szmek 62fe94
         if (r < 0)
Zbigniew Jędrzejewski-Szmek 62fe94
-                goto finish;
Zbigniew Jędrzejewski-Szmek 62fe94
+                return r;
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
         if (event_next_pending(e) || e->need_process_child)
Zbigniew Jędrzejewski-Szmek 62fe94
-                timeout = 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+                goto pending;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        e->state = SD_EVENT_PREPARED;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        return 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+pending:
Zbigniew Jędrzejewski-Szmek 62fe94
+        e->state = SD_EVENT_PREPARED;
Zbigniew Jędrzejewski-Szmek 62fe94
+        return sd_event_wait(e, 0);
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+_public_ int sd_event_wait(sd_event *e, uint64_t timeout) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        struct epoll_event *ev_queue;
Zbigniew Jędrzejewski-Szmek 62fe94
+        unsigned ev_queue_max;
Zbigniew Jędrzejewski-Szmek 62fe94
+        int r, m, i;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(e, -EINVAL);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(!event_pid_changed(e), -ECHILD);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(e->state == SD_EVENT_PREPARED, -EBUSY);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (e->exit_requested) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                e->state = SD_EVENT_PENDING;
Zbigniew Jędrzejewski-Szmek 62fe94
+                return 1;
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
         ev_queue_max = CLAMP(e->n_sources, 1U, EPOLL_QUEUE_MAX);
Zbigniew Jędrzejewski-Szmek 62fe94
         ev_queue = newa(struct epoll_event, ev_queue_max);
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -2262,12 +2280,16 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) {
Zbigniew Jędrzejewski-Szmek 62fe94
         m = epoll_wait(e->epoll_fd, ev_queue, ev_queue_max,
Zbigniew Jędrzejewski-Szmek 62fe94
                        timeout == (uint64_t) -1 ? -1 : (int) ((timeout + USEC_PER_MSEC - 1) / USEC_PER_MSEC));
Zbigniew Jędrzejewski-Szmek 62fe94
         if (m < 0) {
Zbigniew Jędrzejewski-Szmek 62fe94
-                r = errno == EAGAIN || errno == EINTR ? 1 : -errno;
Zbigniew Jędrzejewski-Szmek 62fe94
+                if (errno == EINTR) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                        e->state = SD_EVENT_PENDING;
Zbigniew Jędrzejewski-Szmek 62fe94
+                        return 1;
Zbigniew Jędrzejewski-Szmek 62fe94
+                }
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+                r = -errno;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
                 goto finish;
Zbigniew Jędrzejewski-Szmek 62fe94
         }
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
-        timedout = m == 0;
Zbigniew Jędrzejewski-Szmek 62fe94
-
Zbigniew Jędrzejewski-Szmek 62fe94
         dual_timestamp_get(&e->timestamp);
Zbigniew Jędrzejewski-Szmek 62fe94
         e->timestamp_boottime = now(CLOCK_BOOTTIME);
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -2324,21 +2346,71 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) {
Zbigniew Jędrzejewski-Szmek 62fe94
                         goto finish;
Zbigniew Jędrzejewski-Szmek 62fe94
         }
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
-        p = event_next_pending(e);
Zbigniew Jędrzejewski-Szmek 62fe94
-        if (!p) {
Zbigniew Jędrzejewski-Szmek 62fe94
-                r = !timedout;
Zbigniew Jędrzejewski-Szmek 62fe94
-                goto finish;
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (event_next_pending(e)) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                e->state = SD_EVENT_PENDING;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+                return 1;
Zbigniew Jędrzejewski-Szmek 62fe94
         }
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
-        r = source_dispatch(p);
Zbigniew Jędrzejewski-Szmek 62fe94
+        r = 0;
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
 finish:
Zbigniew Jędrzejewski-Szmek 62fe94
         e->state = SD_EVENT_PASSIVE;
Zbigniew Jędrzejewski-Szmek 62fe94
-        sd_event_unref(e);
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
         return r;
Zbigniew Jędrzejewski-Szmek 62fe94
 }
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
+_public_ int sd_event_dispatch(sd_event *e) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        sd_event_source *p;
Zbigniew Jędrzejewski-Szmek 62fe94
+        int r;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(e, -EINVAL);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(!event_pid_changed(e), -ECHILD);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(e->state == SD_EVENT_PENDING, -EBUSY);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (e->exit_requested)
Zbigniew Jędrzejewski-Szmek 62fe94
+                return dispatch_exit(e);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        p = event_next_pending(e);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (p) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                sd_event_ref(e);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+                e->state = SD_EVENT_RUNNING;
Zbigniew Jędrzejewski-Szmek 62fe94
+                r = source_dispatch(p);
Zbigniew Jędrzejewski-Szmek 62fe94
+                e->state = SD_EVENT_PASSIVE;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+                sd_event_unref(e);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+                return r;
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        e->state = SD_EVENT_PASSIVE;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        return 1;
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+_public_ int sd_event_run(sd_event *e, uint64_t timeout) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        int r;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(e, -EINVAL);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(!event_pid_changed(e), -ECHILD);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_return(e->state == SD_EVENT_PASSIVE, -EBUSY);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        r = sd_event_prepare(e);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (r > 0)
Zbigniew Jędrzejewski-Szmek 62fe94
+                return sd_event_dispatch(e);
Zbigniew Jędrzejewski-Szmek 62fe94
+        else if (r < 0)
Zbigniew Jędrzejewski-Szmek 62fe94
+                return r;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        r = sd_event_wait(e, timeout);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (r > 0)
Zbigniew Jędrzejewski-Szmek 62fe94
+                return sd_event_dispatch(e);
Zbigniew Jędrzejewski-Szmek 62fe94
+        else
Zbigniew Jędrzejewski-Szmek 62fe94
+                return r;
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
 _public_ int sd_event_loop(sd_event *e) {
Zbigniew Jędrzejewski-Szmek 62fe94
         int r;
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
diff --git a/src/systemd/sd-event.h b/src/systemd/sd-event.h
Zbigniew Jędrzejewski-Szmek 62fe94
index d96852a763..8e013b33f6 100644
Zbigniew Jędrzejewski-Szmek 62fe94
--- a/src/systemd/sd-event.h
Zbigniew Jędrzejewski-Szmek 62fe94
+++ b/src/systemd/sd-event.h
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -52,6 +52,8 @@ enum {
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
 enum {
Zbigniew Jędrzejewski-Szmek 62fe94
         SD_EVENT_PASSIVE,
Zbigniew Jędrzejewski-Szmek 62fe94
+        SD_EVENT_PREPARED,
Zbigniew Jędrzejewski-Szmek 62fe94
+        SD_EVENT_PENDING,
Zbigniew Jędrzejewski-Szmek 62fe94
         SD_EVENT_RUNNING,
Zbigniew Jędrzejewski-Szmek 62fe94
         SD_EVENT_EXITING,
Zbigniew Jędrzejewski-Szmek 62fe94
         SD_EVENT_FINISHED
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -84,6 +86,9 @@ int sd_event_add_defer(sd_event *e, sd_event_source **s, sd_event_handler_t call
Zbigniew Jędrzejewski-Szmek 62fe94
 int sd_event_add_post(sd_event *e, sd_event_source **s, sd_event_handler_t callback, void *userdata);
Zbigniew Jędrzejewski-Szmek 62fe94
 int sd_event_add_exit(sd_event *e, sd_event_source **s, sd_event_handler_t callback, void *userdata);
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
+int sd_event_prepare(sd_event *e);
Zbigniew Jędrzejewski-Szmek 62fe94
+int sd_event_wait(sd_event *e, uint64_t timeout);
Zbigniew Jędrzejewski-Szmek 62fe94
+int sd_event_dispatch(sd_event *e);
Zbigniew Jędrzejewski-Szmek 62fe94
 int sd_event_run(sd_event *e, uint64_t timeout);
Zbigniew Jędrzejewski-Szmek 62fe94
 int sd_event_loop(sd_event *e);
Zbigniew Jędrzejewski-Szmek 62fe94
 int sd_event_exit(sd_event *e, int code);