From: Yu Watanabe Date: Sat, 5 Apr 2025 17:04:06 +0000 (+0900) Subject: udev: do not wait for event queue being empty on exit X-Git-Tag: v258-rc1~871^2~1 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=45e8c283d87614cddc7ff23371b3e2701bd386cd;p=thirdparty%2Fsystemd.git udev: do not wait for event queue being empty on exit When the manager process is requested to terminate, if a worker process try to lock a block device and failed, then the worker returns a TRY_AGAIN notification and the event is requeued. Hence, the event queue may have pending events even after manager_exit() is called. In such situation, sd_event_exit() will never called, and udevd will stuck. This makes, after termination is requested, it only checks whether there are any events currently being processed. --- diff --git a/src/udev/udev-manager.c b/src/udev/udev-manager.c index b1faeedab79..375bcd55e8d 100644 --- a/src/udev/udev-manager.c +++ b/src/udev/udev-manager.c @@ -588,8 +588,9 @@ static int event_queue_start(Manager *manager) { int r; assert(manager); + assert(!manager->exit); - if (!manager->events || manager->exit || manager->stop_exec_queue) + if (!manager->events || manager->stop_exec_queue) return 0; r = event_source_disable(manager->kill_workers_event); @@ -921,9 +922,29 @@ static int manager_unlink_queue_file(Manager *manager) { return 0; } +static int on_post_exit(Manager *manager) { + assert(manager); + assert(manager->exit); + + LIST_FOREACH(event, event, manager->events) + if (event->state == EVENT_RUNNING) + return 0; /* There still exist events being processed. */ + + (void) manager_unlink_queue_file(manager); + + if (!hashmap_isempty(manager->workers)) + return 0; /* There still exist running workers. */ + + udev_watch_dump(); + return sd_event_exit(manager->event, 0); +} + static int on_post(sd_event_source *s, void *userdata) { Manager *manager = ASSERT_PTR(userdata); + if (manager->exit) + return on_post_exit(manager); + if (manager->events) { /* Try to process pending events if idle workers exist. Why is this necessary? * When a worker finished an event and became idle, even if there was a pending event, @@ -940,11 +961,6 @@ static int on_post(sd_event_source *s, void *userdata) { if (!hashmap_isempty(manager->workers)) return 0; /* There still exist idle workers. */ - if (manager->exit) { - udev_watch_dump(); - return sd_event_exit(manager->event, 0); - } - if (manager->cgroup && set_isempty(manager->synthesize_change_child_event_sources)) /* cleanup possible left-over processes in our cgroup */ (void) cg_kill(manager->cgroup, SIGKILL, CGROUP_IGNORE_SELF, /* set=*/ NULL, /* kill_log= */ NULL, /* userdata= */ NULL);