From: Daan De Meyer Date: Thu, 6 Nov 2025 09:20:49 +0000 (+0100) Subject: sd-event: Mark post sources as pending after dispatching X-Git-Tag: v259-rc1~59^2~7 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=4c8b6d636c92e84f4b40db5656db58f71f397a1d;p=thirdparty%2Fsystemd.git sd-event: Mark post sources as pending after dispatching More post event sources might get added during dispatching, we want to make sure those become pending as well if we're dispatching a non-post event source. --- diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c index d8cd1ba7dfe..120e67cc318 100644 --- a/src/libsystemd/sd-event/sd-event.c +++ b/src/libsystemd/sd-event/sd-event.c @@ -4083,6 +4083,22 @@ static int source_memory_pressure_initiate_dispatch(sd_event_source *s) { return 0; /* go on, dispatch to user callback */ } +static int mark_post_sources_pending(sd_event *e) { + sd_event_source *z; + int r; + + SET_FOREACH(z, e->post_sources) { + if (event_source_is_offline(z)) + continue; + + r = source_set_pending(z, true); + if (r < 0) + return r; + } + + return 0; +} + static int source_dispatch(sd_event_source *s) { EventSourceType saved_type; sd_event *saved_event; @@ -4117,18 +4133,10 @@ static int source_dispatch(sd_event_source *s) { } if (s->type != SOURCE_POST) { - sd_event_source *z; - /* If we execute a non-post source, let's mark all post sources as pending. */ - - SET_FOREACH(z, s->event->post_sources) { - if (event_source_is_offline(z)) - continue; - - r = source_set_pending(z, true); - if (r < 0) - return r; - } + r = mark_post_sources_pending(s->event); + if (r < 0) + return r; } if (s->type == SOURCE_MEMORY_PRESSURE) { @@ -4237,6 +4245,14 @@ static int source_dispatch(sd_event_source *s) { s->dispatching = false; + if (saved_type != SOURCE_POST) { + /* More post sources might have been added while executing the callback, let's make sure + * those are marked pending as well. */ + r = mark_post_sources_pending(saved_event); + if (r < 0) + return r; + } + finish: if (r < 0) { log_debug_errno(r, "Event source %s (type %s) returned error, %s: %m", diff --git a/src/libsystemd/sd-event/test-event.c b/src/libsystemd/sd-event/test-event.c index 77cf7af541a..31931aea193 100644 --- a/src/libsystemd/sd-event/test-event.c +++ b/src/libsystemd/sd-event/test-event.c @@ -946,4 +946,43 @@ TEST(leave_ratelimit) { ASSERT_TRUE(manually_left_ratelimit); } +static int defer_post_handler(sd_event_source *s, void *userdata) { + bool *dispatched_post = ASSERT_PTR(userdata); + + *dispatched_post = true; + + return 0; +} + +static int defer_adds_post_handler(sd_event_source *s, void *userdata) { + sd_event *e = sd_event_source_get_event(s); + + /* Add a post event source from within the defer handler */ + ASSERT_OK(sd_event_add_post(e, NULL, defer_post_handler, userdata)); + + return 0; +} + +TEST(defer_add_post) { + _cleanup_(sd_event_unrefp) sd_event *e = NULL; + bool dispatched_post = false; + + ASSERT_OK(sd_event_default(&e)); + + /* Add a oneshot defer event source that will add a post event source */ + ASSERT_OK(sd_event_add_defer(e, NULL, defer_adds_post_handler, &dispatched_post)); + + /* Run one iteration - this should dispatch the defer handler */ + ASSERT_OK_POSITIVE(sd_event_run(e, UINT64_MAX)); + + /* The post handler should have been added but not yet dispatched */ + ASSERT_FALSE(dispatched_post); + + /* Run another iteration - this should dispatch the post handler */ + ASSERT_OK_POSITIVE(sd_event_run(e, 0)); + + /* Now the post handler should have been dispatched */ + ASSERT_TRUE(dispatched_post); +} + DEFINE_TEST_MAIN(LOG_DEBUG);