]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-event: optionally, if an event source fails, exit the event loop
authorLennart Poettering <lennart@poettering.net>
Thu, 1 Oct 2020 20:17:31 +0000 (22:17 +0200)
committerLennart Poettering <lennart@poettering.net>
Wed, 7 Oct 2020 07:38:41 +0000 (09:38 +0200)
Currently, if an event source callback returns an error, we'll disable
the event source and continue. This adds a per-event source flag that if
turned on goes further: the event loop is also exited, propagating the
error code.

This is inspired by some patterns repeatedly seen in #15206.

The idea is that event sources that server the "primary" function of a
program are marked like this, so that if they fail the failure is
instantly propagated and terminates the program.

src/libsystemd/libsystemd.sym
src/libsystemd/sd-event/event-source.h
src/libsystemd/sd-event/sd-event.c
src/systemd/sd-event.h

index c6dfcd679121ac85207a20d4adb13619a4c727fb..6e7f2eee53b209e5c1b58fd9d0695337cfa64deb 100644 (file)
@@ -726,6 +726,8 @@ LIBSYSTEMD_247 {
 global:
         sd_event_add_time_relative;
         sd_event_source_set_time_relative;
+        sd_event_source_get_exit_on_failure;
+        sd_event_source_set_exit_on_failure;
 
         sd_bus_error_has_names_sentinel;
 
index 08eb9b6a611e268c08c64654fcd215085058c798..a8a30d825ebee317f6dcefa42948cd81003bcac5 100644 (file)
@@ -60,6 +60,7 @@ struct sd_event_source {
         bool pending:1;
         bool dispatching:1;
         bool floating:1;
+        bool exit_on_failure:1;
 
         int64_t priority;
         unsigned pending_index;
index 7dd43f2ddc56cbfe154e595976474ac827c497e3..e891f62bb7ae5adc278f4e2d7de37677e483b9a1 100644 (file)
@@ -3183,16 +3183,21 @@ static int process_inotify(sd_event *e) {
 }
 
 static int source_dispatch(sd_event_source *s) {
+        _cleanup_(sd_event_unrefp) sd_event *saved_event = NULL;
         EventSourceType saved_type;
         int r = 0;
 
         assert(s);
         assert(s->pending || s->type == SOURCE_EXIT);
 
-        /* Save the event source type, here, so that we still know it after the event callback which might invalidate
-         * the event. */
+        /* Save the event source type, here, so that we still know it after the event callback which might
+         * invalidate the event. */
         saved_type = s->type;
 
+        /* Similar, store a reference to the event loop object, so that we can still access it after the
+         * callback might have invalidated/disconnected the event source. */
+        saved_event = sd_event_ref(s->event);
+
         if (!IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) {
                 r = source_set_pending(s, false);
                 if (r < 0)
@@ -3299,9 +3304,15 @@ static int source_dispatch(sd_event_source *s) {
 
         s->dispatching = false;
 
-        if (r < 0)
-                log_debug_errno(r, "Event source %s (type %s) returned error, disabling: %m",
-                                strna(s->description), event_source_type_to_string(saved_type));
+        if (r < 0) {
+                log_debug_errno(r, "Event source %s (type %s) returned error, %s: %m",
+                                strna(s->description),
+                                event_source_type_to_string(saved_type),
+                                s->exit_on_failure ? "exiting" : "disabling");
+
+                if (s->exit_on_failure)
+                        (void) sd_event_exit(saved_event, r);
+        }
 
         if (s->n_ref == 0)
                 source_free(s);
@@ -3334,9 +3345,15 @@ static int event_prepare(sd_event *e) {
                 r = s->prepare(s, s->userdata);
                 s->dispatching = false;
 
-                if (r < 0)
-                        log_debug_errno(r, "Prepare callback of event source %s (type %s) returned error, disabling: %m",
-                                        strna(s->description), event_source_type_to_string(s->type));
+                if (r < 0) {
+                        log_debug_errno(r, "Prepare callback of event source %s (type %s) returned error, %s: %m",
+                                        strna(s->description),
+                                        event_source_type_to_string(s->type),
+                                        s->exit_on_failure ? "exiting" : "disabling");
+
+                        if (s->exit_on_failure)
+                                (void) sd_event_exit(e, r);
+                }
 
                 if (s->n_ref == 0)
                         source_free(s);
@@ -3974,3 +3991,21 @@ _public_ int sd_event_source_set_floating(sd_event_source *s, int b) {
 
         return 1;
 }
+
+_public_ int sd_event_source_get_exit_on_failure(sd_event_source *s) {
+        assert_return(s, -EINVAL);
+        assert_return(s->type != SOURCE_EXIT, -EDOM);
+
+        return s->exit_on_failure;
+}
+
+_public_ int sd_event_source_set_exit_on_failure(sd_event_source *s, int b) {
+        assert_return(s, -EINVAL);
+        assert_return(s->type != SOURCE_EXIT, -EDOM);
+
+        if (s->exit_on_failure == !!b)
+                return 0;
+
+        s->exit_on_failure = b;
+        return 1;
+}
index dc96bfa68176aa05f2c62cae93016358e8b46d8f..3a53c3d27da1419cbf282e787e05d5c6bf03bcb9 100644 (file)
@@ -160,6 +160,8 @@ int sd_event_source_set_destroy_callback(sd_event_source *s, sd_event_destroy_t
 int sd_event_source_get_destroy_callback(sd_event_source *s, sd_event_destroy_t *ret);
 int sd_event_source_get_floating(sd_event_source *s);
 int sd_event_source_set_floating(sd_event_source *s, int b);
+int sd_event_source_get_exit_on_failure(sd_event_source *s);
+int sd_event_source_set_exit_on_failure(sd_event_source *s, int b);
 
 /* Define helpers so that __attribute__((cleanup(sd_event_unrefp))) and similar may be used. */
 _SD_DEFINE_POINTER_CLEANUP_FUNC(sd_event, sd_event_unref);