chiark / gitweb /
util: replace close_nointr_nofail() by a more useful safe_close()
[elogind.git] / src / libsystemd / sd-event / sd-event.c
index cda92e260454c4f6575ca3786f079f55fa4ab000..3bda7f31adf8c97ec7b1d77705a2ad2710244f0e 100644 (file)
@@ -32,6 +32,7 @@
 #include "util.h"
 #include "time-util.h"
 #include "missing.h"
+#include "set.h"
 
 #include "sd-event.h"
 
@@ -45,6 +46,7 @@ typedef enum EventSourceType {
         SOURCE_SIGNAL,
         SOURCE_CHILD,
         SOURCE_DEFER,
+        SOURCE_POST,
         SOURCE_EXIT,
         SOURCE_WATCHDOG
 } EventSourceType;
@@ -95,6 +97,9 @@ struct sd_event_source {
                 struct {
                         sd_event_handler_t callback;
                 } defer;
+                struct {
+                        sd_event_handler_t callback;
+                } post;
                 struct {
                         sd_event_handler_t callback;
                         unsigned prioq_index;
@@ -134,6 +139,8 @@ struct sd_event {
         Hashmap *child_sources;
         unsigned n_enabled_child_sources;
 
+        Set *post_sources;
+
         Prioq *exit;
 
         pid_t original_pid;
@@ -324,20 +331,11 @@ static void event_free(sd_event *e) {
         if (e->default_event_ptr)
                 *(e->default_event_ptr) = NULL;
 
-        if (e->epoll_fd >= 0)
-                close_nointr_nofail(e->epoll_fd);
-
-        if (e->signal_fd >= 0)
-                close_nointr_nofail(e->signal_fd);
-
-        if (e->realtime_fd >= 0)
-                close_nointr_nofail(e->realtime_fd);
-
-        if (e->monotonic_fd >= 0)
-                close_nointr_nofail(e->monotonic_fd);
-
-        if (e->watchdog_fd >= 0)
-                close_nointr_nofail(e->watchdog_fd);
+        safe_close(e->epoll_fd);
+        safe_close(e->signal_fd);
+        safe_close(e->realtime_fd);
+        safe_close(e->monotonic_fd);
+        safe_close(e->watchdog_fd);
 
         prioq_free(e->pending);
         prioq_free(e->prepare);
@@ -350,6 +348,7 @@ static void event_free(sd_event *e) {
         free(e->signal_sources);
 
         hashmap_free(e->child_sources);
+        set_free(e->post_sources);
         free(e);
 }
 
@@ -524,6 +523,10 @@ static void source_free(sd_event_source *s) {
                         /* nothing */
                         break;
 
+                case SOURCE_POST:
+                        set_remove(s->event->post_sources, s);
+                        break;
+
                 case SOURCE_EXIT:
                         prioq_remove(s->event->exit, s, &s->exit.prioq_index);
                         break;
@@ -599,11 +602,11 @@ static sd_event_source *source_new(sd_event *e, EventSourceType type) {
 
 _public_ int sd_event_add_io(
                 sd_event *e,
+                sd_event_source **ret,
                 int fd,
                 uint32_t events,
                 sd_event_io_handler_t callback,
-                void *userdata,
-                sd_event_source **ret) {
+                void *userdata) {
 
         sd_event_source *s;
         int r;
@@ -661,7 +664,7 @@ static int event_setup_timer_fd(
 
         r = epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, fd, &ev);
         if (r < 0) {
-                close_nointr_nofail(fd);
+                safe_close(fd);
                 return -errno;
         }
 
@@ -683,6 +686,7 @@ static int event_setup_timer_fd(
 
 static int event_add_time_internal(
                 sd_event *e,
+                sd_event_source **ret,
                 EventSourceType type,
                 int *timer_fd,
                 clockid_t id,
@@ -691,8 +695,7 @@ static int event_add_time_internal(
                 uint64_t usec,
                 uint64_t accuracy,
                 sd_event_time_handler_t callback,
-                void *userdata,
-                sd_event_source **ret) {
+                void *userdata) {
 
         sd_event_source *s;
         int r;
@@ -755,23 +758,23 @@ fail:
 }
 
 _public_ int sd_event_add_monotonic(sd_event *e,
+                                    sd_event_source **ret,
                                     uint64_t usec,
                                     uint64_t accuracy,
                                     sd_event_time_handler_t callback,
-                                    void *userdata,
-                                    sd_event_source **ret) {
+                                    void *userdata) {
 
-        return event_add_time_internal(e, SOURCE_MONOTONIC, &e->monotonic_fd, CLOCK_MONOTONIC, &e->monotonic_earliest, &e->monotonic_latest, usec, accuracy, callback, userdata, ret);
+        return event_add_time_internal(e, ret, SOURCE_MONOTONIC, &e->monotonic_fd, CLOCK_MONOTONIC, &e->monotonic_earliest, &e->monotonic_latest, usec, accuracy, callback, userdata);
 }
 
 _public_ int sd_event_add_realtime(sd_event *e,
+                                   sd_event_source **ret,
                                    uint64_t usec,
                                    uint64_t accuracy,
                                    sd_event_time_handler_t callback,
-                                   void *userdata,
-                                   sd_event_source **ret) {
+                                   void *userdata) {
 
-        return event_add_time_internal(e, SOURCE_REALTIME, &e->realtime_fd, CLOCK_REALTIME, &e->realtime_earliest, &e->monotonic_latest, usec, accuracy, callback, userdata, ret);
+        return event_add_time_internal(e, ret, SOURCE_REALTIME, &e->realtime_fd, CLOCK_REALTIME, &e->realtime_earliest, &e->realtime_latest, usec, accuracy, callback, userdata);
 }
 
 static int event_update_signal_fd(sd_event *e) {
@@ -797,9 +800,7 @@ static int event_update_signal_fd(sd_event *e) {
 
         r = epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, e->signal_fd, &ev);
         if (r < 0) {
-                close_nointr_nofail(e->signal_fd);
-                e->signal_fd = -1;
-
+                e->signal_fd = safe_close(e->signal_fd);
                 return -errno;
         }
 
@@ -808,10 +809,10 @@ static int event_update_signal_fd(sd_event *e) {
 
 _public_ int sd_event_add_signal(
                 sd_event *e,
+                sd_event_source **ret,
                 int sig,
                 sd_event_signal_handler_t callback,
-                void *userdata,
-                sd_event_source **ret) {
+                void *userdata) {
 
         sd_event_source *s;
         sigset_t ss;
@@ -865,11 +866,11 @@ _public_ int sd_event_add_signal(
 
 _public_ int sd_event_add_child(
                 sd_event *e,
+                sd_event_source **ret,
                 pid_t pid,
                 int options,
                 sd_event_child_handler_t callback,
-                void *userdata,
-                sd_event_source **ret) {
+                void *userdata) {
 
         sd_event_source *s;
         int r;
@@ -926,9 +927,9 @@ _public_ int sd_event_add_child(
 
 _public_ int sd_event_add_defer(
                 sd_event *e,
+                sd_event_source **ret,
                 sd_event_handler_t callback,
-                void *userdata,
-                sd_event_source **ret) {
+                void *userdata) {
 
         sd_event_source *s;
         int r;
@@ -957,11 +958,48 @@ _public_ int sd_event_add_defer(
         return 0;
 }
 
+_public_ int sd_event_add_post(
+                sd_event *e,
+                sd_event_source **ret,
+                sd_event_handler_t callback,
+                void *userdata) {
+
+        sd_event_source *s;
+        int r;
+
+        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);
+
+        r = set_ensure_allocated(&e->post_sources, trivial_hash_func, trivial_compare_func);
+        if (r < 0)
+                return r;
+
+        s = source_new(e, SOURCE_POST);
+        if (!s)
+                return -ENOMEM;
+
+        s->post.callback = callback;
+        s->userdata = userdata;
+        s->enabled = SD_EVENT_ON;
+
+        r = set_put(e->post_sources, s);
+        if (r < 0) {
+                source_free(s);
+                return r;
+        }
+
+        *ret = s;
+        return 0;
+}
+
 _public_ int sd_event_add_exit(
                 sd_event *e,
+                sd_event_source **ret,
                 sd_event_handler_t callback,
-                void *userdata,
-                sd_event_source **ret) {
+                void *userdata) {
 
         sd_event_source *s;
         int r;
@@ -1246,6 +1284,7 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) {
                         break;
 
                 case SOURCE_DEFER:
+                case SOURCE_POST:
                         s->enabled = m;
                         break;
 
@@ -1304,6 +1343,7 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) {
                         break;
 
                 case SOURCE_DEFER:
+                case SOURCE_POST:
                         s->enabled = m;
                         break;
 
@@ -1763,8 +1803,6 @@ static int process_signal(sd_event *e, uint32_t events) {
                 if (r < 0)
                         return r;
         }
-
-        return 0;
 }
 
 static int source_dispatch(sd_event_source *s) {
@@ -1779,6 +1817,23 @@ static int source_dispatch(sd_event_source *s) {
                         return r;
         }
 
+        if (s->type != SOURCE_POST) {
+                sd_event_source *z;
+                Iterator i;
+
+                /* If we execute a non-post source, let's mark all
+                 * post sources as pending */
+
+                SET_FOREACH(z, s->event->post_sources, i) {
+                        if (z->enabled == SD_EVENT_OFF)
+                                continue;
+
+                        r = source_set_pending(z, true);
+                        if (r < 0)
+                                return r;
+                }
+        }
+
         if (s->enabled == SD_EVENT_ONESHOT) {
                 r = sd_event_source_set_enabled(s, SD_EVENT_OFF);
                 if (r < 0)
@@ -1825,6 +1880,10 @@ static int source_dispatch(sd_event_source *s) {
                 r = s->defer.callback(s, s->userdata);
                 break;
 
+        case SOURCE_POST:
+                r = s->post.callback(s, s->userdata);
+                break;
+
         case SOURCE_EXIT:
                 r = s->exit.callback(s, s->userdata);
                 break;
@@ -2202,8 +2261,7 @@ _public_ int sd_event_set_watchdog(sd_event *e, int b) {
         } else {
                 if (e->watchdog_fd >= 0) {
                         epoll_ctl(e->epoll_fd, EPOLL_CTL_DEL, e->watchdog_fd, NULL);
-                        close_nointr_nofail(e->watchdog_fd);
-                        e->watchdog_fd = -1;
+                        e->watchdog_fd = safe_close(e->watchdog_fd);
                 }
         }
 
@@ -2211,8 +2269,7 @@ _public_ int sd_event_set_watchdog(sd_event *e, int b) {
         return e->watchdog;
 
 fail:
-        close_nointr_nofail(e->watchdog_fd);
-        e->watchdog_fd = -1;
+        e->watchdog_fd = safe_close(e->watchdog_fd);
         return r;
 }