summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2018-11-01 10:37:51 +0900
committerYu Watanabe <watanabe.yu+github@gmail.com>2018-11-07 00:25:13 +0900
commiteca195ec23fb4ed3ece26b55f85c5eefa662e967 (patch)
treea2d8dfa04721b850aa40bebdbfadc7701c1c72e7
parentda14313418f1bbbdf52bd9435e6a183b1f59779a (diff)
downloadsystemd-eca195ec23fb4ed3ece26b55f85c5eefa662e967.tar.gz
systemd-eca195ec23fb4ed3ece26b55f85c5eefa662e967.tar.bz2
systemd-eca195ec23fb4ed3ece26b55f85c5eefa662e967.zip
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.
-rw-r--r--src/udev/udevd.c81
1 files changed, 79 insertions, 2 deletions
diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index 728b45343d..cff0afdd3d 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;
}