diff options
Diffstat (limited to 'src/systemd/src/libsystemd/sd-event/sd-event.c')
-rw-r--r-- | src/systemd/src/libsystemd/sd-event/sd-event.c | 99 |
1 files changed, 85 insertions, 14 deletions
diff --git a/src/systemd/src/libsystemd/sd-event/sd-event.c b/src/systemd/src/libsystemd/sd-event/sd-event.c index 7dd43f2ddc..d3df2e1309 100644 --- a/src/systemd/src/libsystemd/sd-event/sd-event.c +++ b/src/systemd/src/libsystemd/sd-event/sd-event.c @@ -972,6 +972,12 @@ static sd_event_source *source_new(sd_event *e, bool floating, EventSourceType t return s; } +static int io_exit_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + assert(s); + + return sd_event_exit(sd_event_source_get_event(s), PTR_TO_INT(userdata)); +} + _public_ int sd_event_add_io( sd_event *e, sd_event_source **ret, @@ -987,10 +993,12 @@ _public_ int sd_event_add_io( assert_return(e = event_resolve(e), -ENOPKG); assert_return(fd >= 0, -EBADF); assert_return(!(events & ~(EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLPRI|EPOLLERR|EPOLLHUP|EPOLLET)), -EINVAL); - assert_return(callback, -EINVAL); assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(!event_pid_changed(e), -ECHILD); + if (!callback) + callback = io_exit_callback; + s = source_new(e, !ret, SOURCE_IO); if (!s) return -ENOMEM; @@ -1235,6 +1243,12 @@ _public_ int sd_event_add_signal( return 0; } +static int child_exit_callback(sd_event_source *s, const siginfo_t *si, void *userdata) { + assert(s); + + return sd_event_exit(sd_event_source_get_event(s), PTR_TO_INT(userdata)); +} + static bool shall_use_pidfd(void) { /* Mostly relevant for debugging, i.e. this is used in test-event.c to test the event loop once with and once without pidfd */ return getenv_bool_secure("SYSTEMD_PIDFD") != 0; @@ -1256,10 +1270,12 @@ _public_ int sd_event_add_child( assert_return(pid > 1, -EINVAL); assert_return(!(options & ~(WEXITED|WSTOPPED|WCONTINUED)), -EINVAL); assert_return(options != 0, -EINVAL); - assert_return(callback, -EINVAL); assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(!event_pid_changed(e), -ECHILD); + if (!callback) + callback = child_exit_callback; + if (e->n_enabled_child_sources == 0) { /* Caller must block SIGCHLD before using us to watch children, even if pidfd is available, * for compatibility with pre-pidfd and because we don't want the reap the child processes @@ -1357,10 +1373,12 @@ _public_ int sd_event_add_child_pidfd( assert_return(pidfd >= 0, -EBADF); assert_return(!(options & ~(WEXITED|WSTOPPED|WCONTINUED)), -EINVAL); assert_return(options != 0, -EINVAL); - assert_return(callback, -EINVAL); assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(!event_pid_changed(e), -ECHILD); + if (!callback) + callback = child_exit_callback; + if (e->n_enabled_child_sources == 0) { r = signal_is_blocked(SIGCHLD); if (r < 0) @@ -1426,6 +1444,12 @@ _public_ int sd_event_add_child_pidfd( return 0; } +static int generic_exit_callback(sd_event_source *s, void *userdata) { + assert(s); + + return sd_event_exit(sd_event_source_get_event(s), PTR_TO_INT(userdata)); +} + _public_ int sd_event_add_defer( sd_event *e, sd_event_source **ret, @@ -1437,10 +1461,12 @@ _public_ int sd_event_add_defer( assert_return(e, -EINVAL); assert_return(e = event_resolve(e), -ENOPKG); - assert_return(callback, -EINVAL); assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(!event_pid_changed(e), -ECHILD); + if (!callback) + callback = generic_exit_callback; + s = source_new(e, !ret, SOURCE_DEFER); if (!s) return -ENOMEM; @@ -1471,10 +1497,12 @@ _public_ int sd_event_add_post( assert_return(e, -EINVAL); assert_return(e = event_resolve(e), -ENOPKG); - assert_return(callback, -EINVAL); assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(!event_pid_changed(e), -ECHILD); + if (!callback) + callback = generic_exit_callback; + s = source_new(e, !ret, SOURCE_POST); if (!s) return -ENOMEM; @@ -1826,6 +1854,12 @@ static int inode_data_realize_watch(sd_event *e, struct inode_data *d) { return 1; } +static int inotify_exit_callback(sd_event_source *s, const struct inotify_event *event, void *userdata) { + assert(s); + + return sd_event_exit(sd_event_source_get_event(s), PTR_TO_INT(userdata)); +} + _public_ int sd_event_add_inotify( sd_event *e, sd_event_source **ret, @@ -1844,10 +1878,12 @@ _public_ int sd_event_add_inotify( assert_return(e, -EINVAL); assert_return(e = event_resolve(e), -ENOPKG); assert_return(path, -EINVAL); - assert_return(callback, -EINVAL); assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(!event_pid_changed(e), -ECHILD); + if (!callback) + callback = inotify_exit_callback; + /* Refuse IN_MASK_ADD since we coalesce watches on the same inode, and hence really don't want to merge * masks. Or in other words, this whole code exists only to manage IN_MASK_ADD type operations for you, hence * the user can't use them for us. */ @@ -3183,16 +3219,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 +3340,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 +3381,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 +4027,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; +} |