From eca195ec23fb4ed3ece26b55f85c5eefa662e967 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 1 Nov 2018 10:37:51 +0900 Subject: [PATCH] udevd: wait 3 seconds before killing worker processes During boot process, many worker processes are forked and killed. To decrease cycles of forking and killing worker, let's wait 3 seconds before killing workers. If new uevent or inotify event comes within the delay, the killing porcess will be cancelled. --- src/udev/udevd.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 79 insertions(+), 2 deletions(-) diff --git a/src/udev/udevd.c b/src/udev/udevd.c index 728b453..cff0afd 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -86,6 +86,7 @@ typedef struct Manager { sd_event_source *ctrl_event; sd_event_source *uevent_event; sd_event_source *inotify_event; + sd_event_source *kill_workers_event; usec_t last_usec; @@ -284,6 +285,7 @@ static void manager_free(Manager *manager) { sd_event_source_unref(manager->ctrl_event); sd_event_source_unref(manager->uevent_event); sd_event_source_unref(manager->inotify_event); + sd_event_source_unref(manager->kill_workers_event); sd_event_unref(manager->event); manager_workers_free(manager); @@ -364,6 +366,7 @@ static void worker_spawn(Manager *manager, struct event *event) { manager->ctrl_event = sd_event_source_unref(manager->ctrl_event); manager->uevent_event = sd_event_source_unref(manager->uevent_event); manager->inotify_event = sd_event_source_unref(manager->inotify_event); + manager->kill_workers_event = sd_event_source_unref(manager->kill_workers_event); manager->event = sd_event_unref(manager->event); @@ -767,6 +770,73 @@ static void manager_reload(Manager *manager) { "STATUS=Processing with %u children at max", arg_children_max); } +static int on_kill_workers_event(sd_event_source *s, uint64_t usec, void *userdata) { + Manager *manager = userdata; + + assert(manager); + + log_debug("Cleanup idle workers"); + manager_kill_workers(manager); + + return 1; +} + +static int manager_enable_kill_workers_event(Manager *manager) { + int enabled, r; + + assert(manager); + + if (!manager->kill_workers_event) + goto create_new; + + r = sd_event_source_get_enabled(manager->kill_workers_event, &enabled); + if (r < 0) { + log_debug_errno(r, "Failed to query whether event source for killing idle workers is enabled or not, trying to create new event source: %m"); + manager->kill_workers_event = sd_event_source_unref(manager->kill_workers_event); + goto create_new; + } + + if (enabled == SD_EVENT_ONESHOT) + return 0; + + r = sd_event_source_set_time(manager->kill_workers_event, now(CLOCK_MONOTONIC) + 3 * USEC_PER_SEC); + if (r < 0) { + log_debug_errno(r, "Failed to set time to event source for killing idle workers, trying to create new event source: %m"); + manager->kill_workers_event = sd_event_source_unref(manager->kill_workers_event); + goto create_new; + } + + r = sd_event_source_set_enabled(manager->kill_workers_event, SD_EVENT_ONESHOT); + if (r < 0) { + log_debug_errno(r, "Failed to enable event source for killing idle workers, trying to create new event source: %m"); + manager->kill_workers_event = sd_event_source_unref(manager->kill_workers_event); + goto create_new; + } + + return 0; + +create_new: + r = sd_event_add_time(manager->event, &manager->kill_workers_event, CLOCK_MONOTONIC, + now(CLOCK_MONOTONIC) + 3 * USEC_PER_SEC, USEC_PER_SEC, on_kill_workers_event, manager); + if (r < 0) + return log_warning_errno(r, "Failed to create timer event for killing idle workers: %m"); + + return 0; +} + +static int manager_disable_kill_workers_event(Manager *manager) { + int r; + + if (!manager->kill_workers_event) + return 0; + + r = sd_event_source_set_enabled(manager->kill_workers_event, SD_EVENT_OFF); + if (r < 0) + return log_warning_errno(r, "Failed to disable event source for cleaning up idle workers, ignoring: %m"); + + return 0; +} + static void event_queue_start(Manager *manager) { struct event *event; usec_t usec; @@ -788,6 +858,8 @@ static void event_queue_start(Manager *manager) { manager->last_usec = usec; } + (void) manager_disable_kill_workers_event(manager); + udev_builtin_init(); if (!manager->rules) { @@ -1159,6 +1231,8 @@ static int on_inotify(sd_event_source *s, int fd, uint32_t revents, void *userda assert(manager); + (void) manager_disable_kill_workers_event(manager); + l = read(fd, &buffer, sizeof(buffer)); if (l < 0) { if (IN_SET(errno, EAGAIN, EINTR)) @@ -1258,6 +1332,10 @@ static int on_sigchld(sd_event_source *s, const struct signalfd_siginfo *si, voi /* we can start new workers, try to schedule events */ event_queue_start(manager); + /* Disable unnecessary cleanup event */ + if (hashmap_isempty(manager->workers) && manager->kill_workers_event) + (void) sd_event_source_set_enabled(manager->kill_workers_event, SD_EVENT_OFF); + return 1; } @@ -1273,8 +1351,7 @@ static int on_post(sd_event_source *s, void *userdata) { if (!hashmap_isempty(manager->workers)) { /* There are idle workers */ - log_debug("Cleanup idle workers"); - manager_kill_workers(manager); + (void) manager_enable_kill_workers_event(manager); return 1; } -- 2.7.4