[systemd-commits] 9 commits - src/test src/udev units/systemd-udevd.service.in

Tom Gundersen tomegun at kemper.freedesktop.org
Fri May 29 09:53:06 PDT 2015


 src/test/test-udev.c           |    7 
 src/udev/udev-event.c          |  190 ++++++++-------
 src/udev/udev.h                |    2 
 src/udev/udevadm-test.c        |    8 
 src/udev/udevd.c               |  499 ++++++++++++++++++++---------------------
 units/systemd-udevd.service.in |    1 
 6 files changed, 362 insertions(+), 345 deletions(-)

New commits:
commit 62f908b53c0e4598c962c88ad44fb31d64155b2e
Author: Tom Gundersen <teg at jklm.no>
Date:   Fri May 29 18:41:26 2015 +0200

    udevd: hook up watchdog support
    
    We are already sending watchdog notification, this tells PID1 to actually listen for
    them and restart udevd in case it gets stuck.

diff --git a/units/systemd-udevd.service.in b/units/systemd-udevd.service.in
index 32f04d9..e7216d6 100644
--- a/units/systemd-udevd.service.in
+++ b/units/systemd-udevd.service.in
@@ -23,3 +23,4 @@ RestartSec=0
 ExecStart=@rootlibexecdir@/systemd-udevd
 MountFlags=slave
 KillMode=mixed
+WatchdogSec=1min

commit b79aacbff61e77c5fa579e30f7c6fc7f2d67e9e4
Author: Tom Gundersen <teg at jklm.no>
Date:   Fri May 29 18:38:44 2015 +0200

    udevd: notify - expose a bit more of the internal state
    
    This notifies PID1 about config being flushed, about shutdown starting and shutdown finalizing.

diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index 81ba665..fae8f78 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -730,6 +730,10 @@ static void manager_exit(Manager *manager) {
 
         manager->exit = true;
 
+        sd_notify(false,
+                  "STOPPING=1\n"
+                  "STATUS=Starting shutdown...");
+
         /* close sources of new events and discard buffered events */
         manager->ctrl = udev_ctrl_unref(manager->ctrl);
         manager->ctrl_event = sd_event_source_unref(manager->ctrl_event);
@@ -759,9 +763,17 @@ static void manager_reload(Manager *manager) {
 
         assert(manager);
 
+        sd_notify(false,
+                  "RELOADING=1\n"
+                  "STATUS=Flushing configuration...");
+
         manager_kill_workers(manager);
         manager->rules = udev_rules_unref(manager->rules);
         udev_builtin_exit(manager->udev);
+
+        sd_notify(false,
+                  "READY=1\n"
+                  "STATUS=Processing...");
 }
 
 static void event_queue_start(Manager *manager) {
@@ -1703,6 +1715,10 @@ int main(int argc, char *argv[]) {
         sd_event_get_exit_code(manager->event, &r);
 
 exit:
+        sd_notify(false,
+                  "STOPPING=1\n"
+                  "STATUS=Shutting down...");
+
         if (manager)
                 udev_ctrl_cleanup(manager->ctrl);
         mac_selinux_finish();

commit 39fd2ca1616e6d0bc8ca49bb8de1245a9087f2a2
Author: Tom Gundersen <teg at jklm.no>
Date:   Fri May 29 18:32:15 2015 +0200

    udevd: notify - keep NOTIFY_SOCKET around
    
    Only unset the env var in the workers, but otherwise keep it around in the main daemon.

diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index 5bfeefd..81ba665 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -351,6 +351,8 @@ static void worker_spawn(Manager *manager, struct event *event) {
                 dev = event->dev;
                 event->dev = NULL;
 
+                unsetenv("NOTIFY_SOCKET");
+
                 manager_workers_free(manager);
                 event_queue_cleanup(manager, EVENT_UNDEF);
 
@@ -1684,7 +1686,7 @@ int main(int argc, char *argv[]) {
 
                 write_string_file("/proc/self/oom_score_adj", "-1000");
         } else
-                sd_notify(true,
+                sd_notify(false,
                           "READY=1\n"
                           "STATUS=Processing...");
 

commit 3cbb20578b4cc239b049d4901fdac42640f4879e
Author: Tom Gundersen <teg at jklm.no>
Date:   Fri May 29 18:31:01 2015 +0200

    udevd: modernize status notification
    
    Only log about starting in daemon mode, rely on PID1 to log this in notify mode. Also
    explicitly set the STATUS variable, as is done in notify mode as is done for other
    serivecs.

diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index dbfe5f9..5bfeefd 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -1658,8 +1658,6 @@ int main(int argc, char *argv[]) {
         if (r < 0)
                 goto exit;
 
-        log_info("starting version " VERSION);
-
         r = udev_rules_apply_static_dev_perms(manager->rules);
         if (r < 0)
                 log_error_errno(r, "failed to apply permissions on static device nodes: %m");
@@ -1667,6 +1665,8 @@ int main(int argc, char *argv[]) {
         if (arg_daemonize) {
                 pid_t pid;
 
+                log_info("starting version " VERSION);
+
                 pid = fork();
                 switch (pid) {
                 case 0:
@@ -1684,7 +1684,9 @@ int main(int argc, char *argv[]) {
 
                 write_string_file("/proc/self/oom_score_adj", "-1000");
         } else
-                sd_notify(true, "READY=1");
+                sd_notify(true,
+                          "READY=1\n"
+                          "STATUS=Processing...");
 
         r = manager_listen(manager);
         if (r < 0)

commit 8128f2297da0c2fdd82b3d48f049deb01763f8c8
Author: Tom Gundersen <teg at jklm.no>
Date:   Fri May 15 11:35:15 2015 +0200

    udevd: event - port spawn_wait() to sd-event
    
    This allows us to drop the special sigterm handling in spawn_wait()
    as this will now be passed directly to the worker event loop.
    
    We now log failing spawend processes at 'warning' level, and timeouts
    are in terms of CLOCK_BOOTTIME when available, otherwise the behavior
    is unchanged.

diff --git a/src/test/test-udev.c b/src/test/test-udev.c
index 23b7faa..f3953fe 100644
--- a/src/test/test-udev.c
+++ b/src/test/test-udev.c
@@ -120,11 +120,6 @@ int main(int argc, char *argv[]) {
 
         sigfillset(&mask);
         sigprocmask(SIG_SETMASK, &mask, &sigmask_orig);
-        event->fd_signal = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
-        if (event->fd_signal < 0) {
-                fprintf(stderr, "error creating signalfd\n");
-                goto out;
-        }
 
         /* do what devtmpfs usually provides us */
         if (udev_device_get_devnode(dev) != NULL) {
@@ -153,8 +148,6 @@ int main(int argc, char *argv[]) {
                                3 * USEC_PER_SEC, USEC_PER_SEC,
                                NULL);
 out:
-        if (event != NULL && event->fd_signal >= 0)
-                close(event->fd_signal);
         mac_selinux_finish();
 
         return err ? EXIT_FAILURE : EXIT_SUCCESS;
diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c
index 2fa26a4..92dc44f 100644
--- a/src/udev/udev-event.c
+++ b/src/udev/udev-event.c
@@ -32,7 +32,16 @@
 
 #include "udev.h"
 #include "rtnl-util.h"
+#include "event-util.h"
 #include "formats-util.h"
+#include "process-util.h"
+
+typedef struct Spawn {
+        const char *cmd;
+        pid_t pid;
+        usec_t timeout_warn;
+        usec_t timeout;
+} Spawn;
 
 struct udev_event *udev_event_new(struct udev_device *dev) {
         struct udev *udev = udev_device_get_udev(dev);
@@ -45,8 +54,7 @@ struct udev_event *udev_event_new(struct udev_device *dev) {
         event->udev = udev;
         udev_list_init(udev, &event->run_list, false);
         udev_list_init(udev, &event->seclabel_list, false);
-        event->fd_signal = -1;
-        event->birth_usec = now(CLOCK_MONOTONIC);
+        event->birth_usec = clock_boottime_or_monotonic();
         return event;
 }
 
@@ -467,7 +475,7 @@ static void spawn_read(struct udev_event *event,
                 if (timeout_usec > 0) {
                         usec_t age_usec;
 
-                        age_usec = now(CLOCK_MONOTONIC) - event->birth_usec;
+                        age_usec = clock_boottime_or_monotonic() - event->birth_usec;
                         if (age_usec >= timeout_usec) {
                                 log_error("timeout '%s'", cmd);
                                 return;
@@ -540,102 +548,116 @@ static void spawn_read(struct udev_event *event,
                 result[respos] = '\0';
 }
 
+static int on_spawn_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
+        Spawn *spawn = userdata;
+        char timeout[FORMAT_TIMESTAMP_RELATIVE_MAX];
+
+        assert(spawn);
+
+        kill_and_sigcont(spawn->pid, SIGKILL);
+
+        log_error("spawned process '%s' ["PID_FMT"] timed out after %s, killing", spawn->cmd, spawn->pid,
+                  format_timestamp_relative(timeout, sizeof(timeout), spawn->timeout));
+
+        return 1;
+}
+
+static int on_spawn_timeout_warning(sd_event_source *s, uint64_t usec, void *userdata) {
+        Spawn *spawn = userdata;
+        char timeout[FORMAT_TIMESTAMP_RELATIVE_MAX];
+
+        assert(spawn);
+
+        log_warning("spawned process '%s' ["PID_FMT"] is taking longer than %s to complete", spawn->cmd, spawn->pid,
+                    format_timestamp_relative(timeout, sizeof(timeout), spawn->timeout));
+
+        return 1;
+}
+
+static int on_spawn_sigchld(sd_event_source *s, const siginfo_t *si, void *userdata) {
+        Spawn *spawn = userdata;
+
+        assert(spawn);
+
+        switch (si->si_code) {
+        case CLD_EXITED:
+                if (si->si_status != 0)
+                        log_warning("process '%s' failed with exit code %i.", spawn->cmd, si->si_status);
+                else {
+                        log_debug("process '%s' succeeded.", spawn->cmd);
+                        sd_event_exit(sd_event_source_get_event(s), 0);
+
+                        return 1;
+                }
+
+                break;
+        case CLD_KILLED:
+        case CLD_DUMPED:
+                log_warning("process '%s' terminated by signal %s.", spawn->cmd, signal_to_string(si->si_status));
+
+                break;
+        default:
+                log_error("process '%s' failed due to unknown reason.", spawn->cmd);
+        }
+
+        sd_event_exit(sd_event_source_get_event(s), -EIO);
+
+        return 1;
+}
+
 static int spawn_wait(struct udev_event *event,
                       usec_t timeout_usec,
                       usec_t timeout_warn_usec,
                       const char *cmd, pid_t pid) {
-        struct pollfd pfd[1];
-        int err = 0;
-
-        pfd[0].events = POLLIN;
-        pfd[0].fd = event->fd_signal;
+        Spawn spawn = {
+                .cmd = cmd,
+                .pid = pid,
+        };
+        _cleanup_event_unref_ sd_event *e = NULL;
+        int r, ret;
 
-        while (pid > 0) {
-                int timeout;
-                int timeout_warn = 0;
-                int fdcount;
+        r = sd_event_new(&e);
+        if (r < 0)
+                return r;
 
-                if (timeout_usec > 0) {
-                        usec_t age_usec;
+        if (timeout_usec > 0) {
+                usec_t usec, age_usec;
 
-                        age_usec = now(CLOCK_MONOTONIC) - event->birth_usec;
-                        if (age_usec >= timeout_usec)
-                                timeout = 1000;
-                        else {
-                                if (timeout_warn_usec > 0)
-                                        timeout_warn = ((timeout_warn_usec - age_usec) / USEC_PER_MSEC) + MSEC_PER_SEC;
+                usec = now(clock_boottime_or_monotonic());
+                age_usec = usec - event->birth_usec;
+                if (age_usec < timeout_usec) {
+                        if (timeout_warn_usec > 0 && timeout_warn_usec < timeout_usec && age_usec < timeout_warn_usec) {
+                                spawn.timeout_warn = timeout_warn_usec - age_usec;
 
-                                timeout = ((timeout_usec - timeout_warn_usec - age_usec) / USEC_PER_MSEC) + MSEC_PER_SEC;
+                                r =  sd_event_add_time(e, NULL, clock_boottime_or_monotonic(),
+                                                       usec + spawn.timeout_warn, USEC_PER_SEC,
+                                                       on_spawn_timeout_warning, &spawn);
+                                if (r < 0)
+                                        return r;
                         }
-                } else {
-                        timeout = -1;
-                }
 
-                fdcount = poll(pfd, 1, timeout_warn);
-                if (fdcount < 0) {
-                        if (errno == EINTR)
-                                continue;
-                        err = -errno;
-                        log_error_errno(errno, "failed to poll: %m");
-                        goto out;
-                }
-                if (fdcount == 0) {
-                        log_warning("slow: '%s' ["PID_FMT"]", cmd, pid);
+                        spawn.timeout = timeout_usec - age_usec;
 
-                        fdcount = poll(pfd, 1, timeout);
-                        if (fdcount < 0) {
-                                if (errno == EINTR)
-                                        continue;
-                                err = -errno;
-                                log_error_errno(errno, "failed to poll: %m");
-                                goto out;
-                        }
-                        if (fdcount == 0) {
-                                log_error("timeout: killing '%s' ["PID_FMT"]", cmd, pid);
-                                kill(pid, SIGKILL);
-                        }
+                        r = sd_event_add_time(e, NULL, clock_boottime_or_monotonic(),
+                                              usec + spawn.timeout, USEC_PER_SEC, on_spawn_timeout, &spawn);
+                        if (r < 0)
+                                return r;
                 }
+        }
 
-                if (pfd[0].revents & POLLIN) {
-                        struct signalfd_siginfo fdsi;
-                        int status;
-                        ssize_t size;
+        r = sd_event_add_child(e, NULL, pid, WEXITED, on_spawn_sigchld, &spawn);
+        if (r < 0)
+                return r;
 
-                        size = read(event->fd_signal, &fdsi, sizeof(struct signalfd_siginfo));
-                        if (size != sizeof(struct signalfd_siginfo))
-                                continue;
+        r = sd_event_loop(e);
+        if (r < 0)
+                return r;
 
-                        switch (fdsi.ssi_signo) {
-                        case SIGTERM:
-                                event->sigterm = true;
-                                break;
-                        case SIGCHLD:
-                                if (waitpid(pid, &status, WNOHANG) < 0)
-                                        break;
-                                if (WIFEXITED(status)) {
-                                        log_debug("'%s' ["PID_FMT"] exit with return code %i", cmd, pid, WEXITSTATUS(status));
-                                        if (WEXITSTATUS(status) != 0)
-                                                err = -1;
-                                } else if (WIFSIGNALED(status)) {
-                                        log_error("'%s' ["PID_FMT"] terminated by signal %i (%s)", cmd, pid, WTERMSIG(status), strsignal(WTERMSIG(status)));
-                                        err = -1;
-                                } else if (WIFSTOPPED(status)) {
-                                        log_error("'%s' ["PID_FMT"] stopped", cmd, pid);
-                                        err = -1;
-                                } else if (WIFCONTINUED(status)) {
-                                        log_error("'%s' ["PID_FMT"] continued", cmd, pid);
-                                        err = -1;
-                                } else {
-                                        log_error("'%s' ["PID_FMT"] exit with status 0x%04x", cmd, pid, status);
-                                        err = -1;
-                                }
-                                pid = 0;
-                                break;
-                        }
-                }
-        }
-out:
-        return err;
+        r = sd_event_get_exit_code(e, &ret);
+        if (r < 0)
+                return r;
+
+        return ret;
 }
 
 int udev_build_argv(struct udev *udev, char *cmd, int *argc, char *argv[]) {
diff --git a/src/udev/udev.h b/src/udev/udev.h
index dece6ec..1b17c61 100644
--- a/src/udev/udev.h
+++ b/src/udev/udev.h
@@ -44,11 +44,9 @@ struct udev_event {
         struct udev_list run_list;
         int exec_delay;
         usec_t birth_usec;
-        int fd_signal;
         sd_rtnl *rtnl;
         unsigned int builtin_run;
         unsigned int builtin_ret;
-        bool sigterm;
         bool inotify_watch;
         bool inotify_watch_final;
         bool group_set;
diff --git a/src/udev/udevadm-test.c b/src/udev/udevadm-test.c
index fe092cf..46ec0e3 100644
--- a/src/udev/udevadm-test.c
+++ b/src/udev/udevadm-test.c
@@ -131,12 +131,6 @@ static int adm_test(struct udev *udev, int argc, char *argv[]) {
 
         sigfillset(&mask);
         sigprocmask(SIG_SETMASK, &mask, &sigmask_orig);
-        event->fd_signal = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
-        if (event->fd_signal < 0) {
-                fprintf(stderr, "error creating signalfd\n");
-                rc = 5;
-                goto out;
-        }
 
         udev_event_execute_rules(event,
                                  60 * USEC_PER_SEC, 20 * USEC_PER_SEC,
@@ -154,8 +148,6 @@ static int adm_test(struct udev *udev, int argc, char *argv[]) {
                 printf("run: '%s'\n", program);
         }
 out:
-        if (event != NULL && event->fd_signal >= 0)
-                close(event->fd_signal);
         udev_builtin_exit(udev);
         return rc;
 }
diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index 3022cd2..dbfe5f9 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -406,9 +406,6 @@ static void worker_spawn(Manager *manager, struct event *event) {
                                 goto out;
                         }
 
-                        /* needed for SIGCHLD/SIGTERM in spawn() */
-                        udev_event->fd_signal = fd_signal;
-
                         if (arg_exec_delay > 0)
                                 udev_event->exec_delay = arg_exec_delay;
 
@@ -481,11 +478,6 @@ skip:
                         udev_device_unref(dev);
                         dev = NULL;
 
-                        if (udev_event->sigterm) {
-                                udev_event_unref(udev_event);
-                                goto out;
-                        }
-
                         udev_event_unref(udev_event);
 
                         /* wait for more device messages from main udevd, or term signal */

commit 693d371d30fee1da58365121801445b404416ada
Author: Tom Gundersen <teg at jklm.no>
Date:   Mon May 18 17:22:36 2015 +0200

    udevd: move main-loop to sd-event

diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index b9c7034..3022cd2 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -41,6 +41,8 @@
 #include <sys/inotify.h>
 
 #include "sd-daemon.h"
+#include "sd-event.h"
+#include "event-util.h"
 #include "rtnl-util.h"
 #include "cgroup-util.h"
 #include "process-util.h"
@@ -62,6 +64,7 @@ static usec_t arg_event_timeout_warn_usec = 180 * USEC_PER_SEC / 3;
 
 typedef struct Manager {
         struct udev *udev;
+        sd_event *event;
         Hashmap *workers;
         struct udev_list_node events;
         char *cgroup;
@@ -74,15 +77,13 @@ typedef struct Manager {
         struct udev_monitor *monitor;
         struct udev_ctrl *ctrl;
         struct udev_ctrl_connection *ctrl_conn_blocking;
-
-        int fd_ep;
-        int fd_ctrl;
-        int fd_uevent;
-        int fd_signal;
         int fd_inotify;
-        int fd_worker;
         int worker_watch[2];
 
+        sd_event_source *ctrl_event;
+        sd_event_source *uevent_event;
+        sd_event_source *inotify_event;
+
         usec_t last_usec;
 
         bool stop_exec_queue:1;
@@ -111,8 +112,8 @@ struct event {
         dev_t devnum;
         int ifindex;
         bool is_block;
-        usec_t start_usec;
-        bool warned;
+        sd_event_source *timeout_warning;
+        sd_event_source *timeout;
 };
 
 static inline struct event *node_to_event(struct udev_list_node *node) {
@@ -152,6 +153,9 @@ static void event_free(struct event *event) {
         udev_device_unref(event->dev);
         udev_device_unref(event->dev_kernel);
 
+        sd_event_source_unref(event->timeout_warning);
+        sd_event_source_unref(event->timeout);
+
         if (event->worker)
                 event->worker->event = NULL;
 
@@ -253,7 +257,12 @@ static int on_event_timeout_warning(sd_event_source *s, uint64_t usec, void *use
 }
 
 static void worker_attach_event(struct worker *worker, struct event *event) {
+        sd_event *e;
+        uint64_t usec;
+        int r;
+
         assert(worker);
+        assert(worker->manager);
         assert(event);
         assert(!event->worker);
         assert(!worker->event);
@@ -261,9 +270,19 @@ static void worker_attach_event(struct worker *worker, struct event *event) {
         worker->state = WORKER_RUNNING;
         worker->event = event;
         event->state = EVENT_RUNNING;
-        event->start_usec = now(CLOCK_MONOTONIC);
-        event->warned = false;
         event->worker = worker;
+
+        e = worker->manager->event;
+
+        r = sd_event_now(e, clock_boottime_or_monotonic(), &usec);
+        if (r < 0)
+                return;
+
+        (void) sd_event_add_time(e, &event->timeout_warning, clock_boottime_or_monotonic(),
+                                 usec + arg_event_timeout_warn_usec, USEC_PER_SEC, on_event_timeout_warning, event);
+
+        (void) sd_event_add_time(e, &event->timeout, clock_boottime_or_monotonic(),
+                                 usec + arg_event_timeout_usec, USEC_PER_SEC, on_event_timeout, event);
 }
 
 static void manager_free(Manager *manager) {
@@ -272,7 +291,12 @@ static void manager_free(Manager *manager) {
 
         udev_builtin_exit(manager->udev);
 
+        sd_event_source_unref(manager->ctrl_event);
+        sd_event_source_unref(manager->uevent_event);
+        sd_event_source_unref(manager->inotify_event);
+
         udev_unref(manager->udev);
+        sd_event_unref(manager->event);
         manager_workers_free(manager);
         event_queue_cleanup(manager, EVENT_UNDEF);
 
@@ -284,8 +308,6 @@ static void manager_free(Manager *manager) {
         udev_rules_unref(manager->rules);
         free(manager->cgroup);
 
-        safe_close(manager->fd_ep);
-        safe_close(manager->fd_signal);
         safe_close(manager->fd_inotify);
         safe_close_pair(manager->worker_watch);
 
@@ -335,11 +357,15 @@ static void worker_spawn(Manager *manager, struct event *event) {
                 manager->monitor = udev_monitor_unref(manager->monitor);
                 manager->ctrl_conn_blocking = udev_ctrl_connection_unref(manager->ctrl_conn_blocking);
                 manager->ctrl = udev_ctrl_unref(manager->ctrl);
-
-                manager->fd_ep = safe_close(manager->fd_ep);
-                manager->fd_signal = safe_close(manager->fd_signal);
+                manager->ctrl_conn_blocking = udev_ctrl_connection_unref(manager->ctrl_conn_blocking);
                 manager->worker_watch[READ_END] = safe_close(manager->worker_watch[READ_END]);
 
+                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->event = sd_event_unref(manager->event);
+
                 sigfillset(&mask);
                 fd_signal = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
                 if (fd_signal < 0) {
@@ -690,31 +716,48 @@ static bool is_devpath_busy(Manager *manager, struct event *event) {
         return false;
 }
 
+static int on_exit_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
+        Manager *manager = userdata;
+
+        assert(manager);
+
+        log_error_errno(ETIMEDOUT, "giving up waiting for workers to finish");
+
+        sd_event_exit(manager->event, -ETIMEDOUT);
+
+        return 1;
+}
+
 static void manager_exit(Manager *manager) {
+        uint64_t usec;
+        int r;
 
         assert(manager);
 
         manager->exit = true;
 
         /* close sources of new events and discard buffered events */
-        if (manager->fd_ctrl >= 0) {
-                epoll_ctl(manager->fd_ep, EPOLL_CTL_DEL, manager->fd_ctrl, NULL);
-                manager->fd_ctrl = safe_close(manager->fd_ctrl);
-        }
+        manager->ctrl = udev_ctrl_unref(manager->ctrl);
+        manager->ctrl_event = sd_event_source_unref(manager->ctrl_event);
 
-        if (manager->monitor) {
-                epoll_ctl(manager->fd_ep, EPOLL_CTL_DEL, manager->fd_uevent, NULL);
-                manager->monitor = udev_monitor_unref(manager->monitor);
-        }
+        manager->fd_inotify = safe_close(manager->fd_inotify);
+        manager->inotify_event = sd_event_source_unref(manager->inotify_event);
 
-        if (manager->fd_inotify >= 0) {
-                epoll_ctl(manager->fd_ep, EPOLL_CTL_DEL, manager->fd_inotify, NULL);
-                manager->fd_inotify = safe_close(manager->fd_inotify);
-        }
+        manager->monitor = udev_monitor_unref(manager->monitor);
+        manager->uevent_event = sd_event_source_unref(manager->uevent_event);
 
         /* discard queued events and kill workers */
         event_queue_cleanup(manager, EVENT_QUEUED);
         manager_kill_workers(manager);
+
+        r = sd_event_now(manager->event, clock_boottime_or_monotonic(), &usec);
+        if (r < 0)
+                return;
+
+        r = sd_event_add_time(manager->event, NULL, clock_boottime_or_monotonic(),
+                              usec + 30 * USEC_PER_SEC, USEC_PER_SEC, on_exit_timeout, manager);
+        if (r < 0)
+                return;
 }
 
 /* reload requested, HUP signal received, rules changed, builtin changed */
@@ -729,6 +772,8 @@ static void manager_reload(Manager *manager) {
 
 static void event_queue_start(Manager *manager) {
         struct udev_list_node *loop;
+        usec_t usec;
+        int r;
 
         assert(manager);
 
@@ -736,14 +781,17 @@ static void event_queue_start(Manager *manager) {
             manager->exit || manager->stop_exec_queue)
                 return;
 
-        /* check for changed config, every 3 seconds at most */
-        if (manager->last_usec == 0 ||
-            (now(CLOCK_MONOTONIC) - manager->last_usec) > 3 * USEC_PER_SEC) {
-                if (udev_rules_check_timestamp(manager->rules) ||
-                    udev_builtin_validate(manager->udev))
-                        manager_reload(manager);
-
-                manager->last_usec = now(CLOCK_MONOTONIC);
+        r = sd_event_now(manager->event, clock_boottime_or_monotonic(), &usec);
+        if (r >= 0) {
+                /* check for changed config, every 3 seconds at most */
+                if (manager->last_usec == 0 ||
+                    (usec - manager->last_usec) > 3 * USEC_PER_SEC) {
+                        if (udev_rules_check_timestamp(manager->rules) ||
+                            udev_builtin_validate(manager->udev))
+                                manager_reload(manager);
+
+                        manager->last_usec = usec;
+                }
         }
 
         udev_builtin_init(manager->udev);
@@ -1180,6 +1228,33 @@ static int on_sigchld(sd_event_source *s, const struct signalfd_siginfo *si, voi
         return 1;
 }
 
+static int on_post(sd_event_source *s, void *userdata) {
+        Manager *manager = userdata;
+        int r;
+
+        assert(manager);
+
+        if (udev_list_node_is_empty(&manager->events)) {
+                /* no pending events */
+                if (!hashmap_isempty(manager->workers)) {
+                        /* there are idle workers */
+                        log_debug("cleanup idle workers");
+                        manager_kill_workers(manager);
+                } else {
+                        /* we are idle */
+                        if (manager->exit) {
+                                r = sd_event_exit(manager->event, 0);
+                                if (r < 0)
+                                        return r;
+                        } else if (manager->cgroup)
+                                /* cleanup possible left-over processes in our cgroup */
+                                cg_kill(SYSTEMD_CGROUP_CONTROLLER, manager->cgroup, SIGKILL, false, true, NULL);
+                }
+        }
+
+        return 1;
+}
+
 static int systemd_fds(int *rctrl, int *rnetlink) {
         int ctrl = -1, netlink = -1;
         int fd, n;
@@ -1358,6 +1433,7 @@ static int parse_argv(int argc, char *argv[]) {
 
 static int manager_new(Manager **ret) {
         _cleanup_(manager_freep) Manager *manager = NULL;
+        int r;
 
         assert(ret);
 
@@ -1365,14 +1441,14 @@ static int manager_new(Manager **ret) {
         if (!manager)
                 return log_oom();
 
-        manager->fd_ep = -1;
-        manager->fd_ctrl = -1;
-        manager->fd_uevent = -1;
-        manager->fd_signal = -1;
         manager->fd_inotify = -1;
         manager->worker_watch[WRITE_END] = -1;
         manager->worker_watch[READ_END] = -1;
 
+        r = sd_event_default(&manager->event);
+        if (r < 0)
+                return log_error_errno(errno, "could not allocate event loop: %m");
+
         manager->udev = udev_new();
         if (!manager->udev)
                 return log_error_errno(errno, "could not allocate udev context: %m");
@@ -1393,24 +1469,19 @@ static int manager_new(Manager **ret) {
 }
 
 static int manager_listen(Manager *manager) {
-        struct epoll_event ep_ctrl = { .events = EPOLLIN };
-        struct epoll_event ep_inotify = { .events = EPOLLIN };
-        struct epoll_event ep_signal = { .events = EPOLLIN };
-        struct epoll_event ep_netlink = { .events = EPOLLIN };
-        struct epoll_event ep_worker = { .events = EPOLLIN };
         sigset_t mask;
-        int r, one = 1;
+        int r, fd_worker, fd_ctrl, fd_uevent, one = 1;
 
         assert(manager);
 
-        r = systemd_fds(&manager->fd_ctrl, &manager->fd_uevent);
+        r = systemd_fds(&fd_ctrl, &fd_uevent);
         if (r >= 0) {
                 /* get control and netlink socket from systemd */
-                manager->ctrl = udev_ctrl_new_from_fd(manager->udev, manager->fd_ctrl);
+                manager->ctrl = udev_ctrl_new_from_fd(manager->udev, fd_ctrl);
                 if (!manager->ctrl)
                         return log_error_errno(EINVAL, "error taking over udev control socket");
 
-                manager->monitor = udev_monitor_new_from_netlink_fd(manager->udev, "kernel", manager->fd_uevent);
+                manager->monitor = udev_monitor_new_from_netlink_fd(manager->udev, "kernel", fd_uevent);
                 if (!manager->monitor)
                         return log_error_errno(EINVAL, "error taking over netlink socket");
 
@@ -1424,13 +1495,13 @@ static int manager_listen(Manager *manager) {
                 if (!manager->ctrl)
                         return log_error_errno(EINVAL, "error initializing udev control socket");
 
-                manager->fd_ctrl = udev_ctrl_get_fd(manager->ctrl);
+                fd_ctrl = udev_ctrl_get_fd(manager->ctrl);
 
                 manager->monitor = udev_monitor_new_from_netlink(manager->udev, "kernel");
                 if (!manager->monitor)
                         return log_error_errno(EINVAL, "error initializing netlink socket");
 
-                manager->fd_uevent = udev_monitor_get_fd(manager->monitor);
+                fd_uevent = udev_monitor_get_fd(manager->monitor);
 
                 (void) udev_monitor_set_receive_buffer_size(manager->monitor, 128 * 1024 * 1024);
         }
@@ -1448,9 +1519,9 @@ static int manager_listen(Manager *manager) {
         if (r < 0)
                 return log_error_errno(errno, "error creating socketpair: %m");
 
-        manager->fd_worker = manager->worker_watch[READ_END];
+        fd_worker = manager->worker_watch[READ_END];
 
-        r = setsockopt(manager->fd_worker, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
+        r = setsockopt(fd_worker, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
         if (r < 0)
                 return log_error_errno(errno, "could not enable SO_PASSCRED: %m");
 
@@ -1463,26 +1534,54 @@ static int manager_listen(Manager *manager) {
         /* block and listen to all signals on signalfd */
         sigfillset(&mask);
         sigprocmask(SIG_SETMASK, &mask, &manager->sigmask_orig);
-        manager->fd_signal = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
-        if (manager->fd_signal < 0)
-                return log_error_errno(errno, "error creating signalfd");
-
-        ep_ctrl.data.fd = manager->fd_ctrl;
-        ep_inotify.data.fd = manager->fd_inotify;
-        ep_signal.data.fd = manager->fd_signal;
-        ep_netlink.data.fd = manager->fd_uevent;
-        ep_worker.data.fd = manager->fd_worker;
-
-        manager->fd_ep = epoll_create1(EPOLL_CLOEXEC);
-        if (manager->fd_ep < 0)
-                return log_error_errno(errno, "error creating epoll fd: %m");
-
-        if (epoll_ctl(manager->fd_ep, EPOLL_CTL_ADD, manager->fd_ctrl, &ep_ctrl) < 0 ||
-            epoll_ctl(manager->fd_ep, EPOLL_CTL_ADD, manager->fd_inotify, &ep_inotify) < 0 ||
-            epoll_ctl(manager->fd_ep, EPOLL_CTL_ADD, manager->fd_signal, &ep_signal) < 0 ||
-            epoll_ctl(manager->fd_ep, EPOLL_CTL_ADD, manager->fd_uevent, &ep_netlink) < 0 ||
-            epoll_ctl(manager->fd_ep, EPOLL_CTL_ADD, manager->fd_worker, &ep_worker) < 0)
-                return log_error_errno(errno, "fail to add fds to epoll: %m");
+
+        r = sd_event_add_signal(manager->event, NULL, SIGINT, on_sigterm, manager);
+        if (r < 0)
+                return log_error_errno(r, "error creating sigint event source: %m");
+
+        r = sd_event_add_signal(manager->event, NULL, SIGTERM, on_sigterm, manager);
+        if (r < 0)
+                return log_error_errno(r, "error creating sigterm event source: %m");
+
+        r = sd_event_add_signal(manager->event, NULL, SIGHUP, on_sighup, manager);
+        if (r < 0)
+                return log_error_errno(r, "error creating sighup event source: %m");
+
+        r = sd_event_add_signal(manager->event, NULL, SIGCHLD, on_sigchld, manager);
+        if (r < 0)
+                return log_error_errno(r, "error creating sigchld event source: %m");
+
+        r = sd_event_set_watchdog(manager->event, true);
+        if (r < 0)
+                return log_error_errno(r, "error creating watchdog event source: %m");
+
+        r = sd_event_add_io(manager->event, &manager->ctrl_event, fd_ctrl, EPOLLIN, on_ctrl_msg, manager);
+        if (r < 0)
+                return log_error_errno(r, "error creating ctrl event source: %m");
+
+        /* This needs to be after the inotify and uevent handling, to make sure
+         * that the ping is send back after fully processing the pending uevents
+         * (including the synthetic ones we may create due to inotify events).
+         */
+        r = sd_event_source_set_priority(manager->ctrl_event, SD_EVENT_PRIORITY_IDLE);
+        if (r < 0)
+                return log_error_errno(r, "cold not set IDLE event priority for ctrl event source: %m");
+
+        r = sd_event_add_io(manager->event, &manager->inotify_event, manager->fd_inotify, EPOLLIN, on_inotify, manager);
+        if (r < 0)
+                return log_error_errno(r, "error creating inotify event source: %m");
+
+        r = sd_event_add_io(manager->event, &manager->uevent_event, fd_uevent, EPOLLIN, on_uevent, manager);
+        if (r < 0)
+                return log_error_errno(r, "error creating uevent event source: %m");
+
+        r = sd_event_add_io(manager->event, NULL, fd_worker, EPOLLIN, on_worker, manager);
+        if (r < 0)
+                return log_error_errno(r, "error creating worker event source: %m");
+
+        r = sd_event_add_post(manager->event, NULL, on_post, manager);
+        if (r < 0)
+                return log_error_errno(r, "error creating post event source: %m");
 
         return 0;
 }
@@ -1593,142 +1692,20 @@ int main(int argc, char *argv[]) {
 
                 write_string_file("/proc/self/oom_score_adj", "-1000");
         } else
-                sd_notify(1, "READY=1");
+                sd_notify(true, "READY=1");
 
         r = manager_listen(manager);
         if (r < 0)
                 return log_error_errno(r, "failed to set up fds and listen for events: %m");
 
-        for (;;) {
-                struct epoll_event ev[8];
-                int fdcount;
-                int timeout;
-                bool is_worker, is_signal, is_inotify, is_uevent, is_ctrl;
-                int i;
-
-                if (manager->exit) {
-                        /* exit after all has cleaned up */
-                        if (udev_list_node_is_empty(&manager->events) && hashmap_isempty(manager->workers))
-                                break;
-
-                        /* timeout at exit for workers to finish */
-                        timeout = 30 * MSEC_PER_SEC;
-                } else if (udev_list_node_is_empty(&manager->events) && hashmap_isempty(manager->workers)) {
-                        /* we are idle */
-                        timeout = -1;
-
-                        /* cleanup possible left-over processes in our cgroup */
-                        if (manager->cgroup)
-                                cg_kill(SYSTEMD_CGROUP_CONTROLLER, manager->cgroup, SIGKILL, false, true, NULL);
-                } else {
-                        /* kill idle or hanging workers */
-                        timeout = 3 * MSEC_PER_SEC;
-                }
-
-                fdcount = epoll_wait(manager->fd_ep, ev, ELEMENTSOF(ev), timeout);
-                if (fdcount < 0)
-                        continue;
-
-                if (fdcount == 0) {
-                        struct worker *worker;
-                        Iterator j;
-
-                        /* timeout */
-                        if (manager->exit) {
-                                log_error("timeout, giving up waiting for workers to finish");
-                                break;
-                        }
-
-                        /* kill idle workers */
-                        if (udev_list_node_is_empty(&manager->events)) {
-                                log_debug("cleanup idle workers");
-                                manager_kill_workers(manager);
-                        }
-
-                        /* check for hanging events */
-                        HASHMAP_FOREACH(worker, manager->workers, j) {
-                                struct event *event = worker->event;
-                                usec_t ts;
-
-                                if (worker->state != WORKER_RUNNING)
-                                        continue;
-
-                                assert(event);
-
-                                ts = now(CLOCK_MONOTONIC);
-
-                                if ((ts - event->start_usec) > arg_event_timeout_warn_usec) {
-                                        if ((ts - event->start_usec) > arg_event_timeout_usec)
-                                                on_event_timeout(NULL, 0, event);
-                                        else if (!event->warned) {
-                                                on_event_timeout_warning(NULL, 0, event);
-                                                event->warned = true;
-                                        }
-                                }
-                        }
-
-                }
-
-                is_worker = is_signal = is_inotify = is_uevent = is_ctrl = false;
-                for (i = 0; i < fdcount; i++) {
-                        if (ev[i].data.fd == manager->fd_worker && ev[i].events & EPOLLIN)
-                                is_worker = true;
-                        else if (ev[i].data.fd == manager->fd_uevent && ev[i].events & EPOLLIN)
-                                is_uevent = true;
-                        else if (ev[i].data.fd == manager->fd_signal && ev[i].events & EPOLLIN)
-                                is_signal = true;
-                        else if (ev[i].data.fd == manager->fd_inotify && ev[i].events & EPOLLIN)
-                                is_inotify = true;
-                        else if (ev[i].data.fd == manager->fd_ctrl && ev[i].events & EPOLLIN)
-                                is_ctrl = true;
-                }
-
-                /* event has finished */
-                if (is_worker)
-                        on_worker(NULL, manager->fd_worker, 0, manager);
-
-                /* uevent from kernel */
-                if (is_uevent)
-                        on_uevent(NULL, manager->fd_uevent, 0, manager);
-
-                if (is_signal) {
-                        struct signalfd_siginfo fdsi;
-                        ssize_t size;
-
-                        size = read(manager->fd_signal, &fdsi, sizeof(struct signalfd_siginfo));
-                        if (size == sizeof(struct signalfd_siginfo)) {
-                                switch (fdsi.ssi_signo) {
-                                case SIGINT:
-                                case SIGTERM:
-                                        on_sigterm(NULL, &fdsi, manager);
-                                        break;
-                                case SIGHUP:
-                                        on_sighup(NULL, &fdsi, manager);
-                                        break;
-                                case SIGCHLD:
-                                        on_sigchld(NULL, &fdsi, manager);
-                                        break;
-                                }
-                        }
-                }
-
-                /* we are shutting down, the events below are not handled anymore */
-                if (manager->exit)
-                        continue;
-
-                /* device node watch */
-                if (is_inotify)
-                        on_inotify(NULL, manager->fd_inotify, 0, manager);
-
-                /*
-                 * This needs to be after the inotify handling, to make sure,
-                 * that the ping is send back after the possibly generated
-                 * "change" events by the inotify device node watch.
-                 */
-                if (is_ctrl)
-                        on_ctrl_msg(NULL, manager->fd_ctrl, 0, manager);
+        r = sd_event_loop(manager->event);
+        if (r < 0) {
+                log_error_errno(r, "event loop failed: %m");
+                goto exit;
         }
 
+        sd_event_get_exit_code(manager->event, &r);
+
 exit:
         if (manager)
                 udev_ctrl_cleanup(manager->ctrl);

commit 8302fe5a132ab0b6af21aad051b91b7e655e200b
Author: Tom Gundersen <teg at jklm.no>
Date:   Mon May 18 17:06:00 2015 +0200

    udevd: explicitly try to start event queue when it may be possible
    
    Rather than trying to schedule new events on every main-loop iteration, do it explicitly when
    processing an event finishes, a worker is killed, a new uevent is received, or the event queue
    is explicitly restarted.

diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index 300b8de..b9c7034 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -847,6 +847,9 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat
                 event_free(worker->event);
         }
 
+        /* we have free workers, try to schedule events */
+        event_queue_start(manager);
+
         return 1;
 }
 
@@ -863,6 +866,9 @@ static int on_uevent(sd_event_source *s, int fd, uint32_t revents, void *userdat
                 r = event_queue_insert(manager, dev);
                 if (r < 0)
                         udev_device_unref(dev);
+                else
+                        /* we have fresh events, try to schedule them */
+                        event_queue_start(manager);
         }
 
         return 1;
@@ -901,6 +907,7 @@ static int on_ctrl_msg(sd_event_source *s, int fd, uint32_t revents, void *userd
         if (udev_ctrl_get_start_exec_queue(ctrl_msg) > 0) {
                 log_debug("udevd message (START_EXEC_QUEUE) received");
                 manager->stop_exec_queue = false;
+                event_queue_start(manager);
         }
 
         if (udev_ctrl_get_reload(ctrl_msg) > 0) {
@@ -1167,6 +1174,9 @@ static int on_sigchld(sd_event_source *s, const struct signalfd_siginfo *si, voi
                 worker_free(worker);
         }
 
+        /* we can start new workers, try to schedule events */
+        event_queue_start(manager);
+
         return 1;
 }
 
@@ -1681,9 +1691,6 @@ int main(int argc, char *argv[]) {
                 if (is_uevent)
                         on_uevent(NULL, manager->fd_uevent, 0, manager);
 
-                /* start new events */
-                event_queue_start(manager);
-
                 if (is_signal) {
                         struct signalfd_siginfo fdsi;
                         ssize_t size;

commit 7c4c7e891364660597c2511c44c7bfccb6a5b124
Author: Tom Gundersen <teg at jklm.no>
Date:   Mon May 18 16:25:22 2015 +0200

    udevd: only check for changed config before scheduling new events
    
    Also move builtin and rules initialization from main loop to
    event_queue_start().
    
    No functional change.

diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index a4b2969..300b8de 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -83,6 +83,8 @@ typedef struct Manager {
         int fd_worker;
         int worker_watch[2];
 
+        usec_t last_usec;
+
         bool stop_exec_queue:1;
         bool exit:1;
 } Manager;
@@ -730,6 +732,28 @@ static void event_queue_start(Manager *manager) {
 
         assert(manager);
 
+        if (udev_list_node_is_empty(&manager->events) ||
+            manager->exit || manager->stop_exec_queue)
+                return;
+
+        /* check for changed config, every 3 seconds at most */
+        if (manager->last_usec == 0 ||
+            (now(CLOCK_MONOTONIC) - manager->last_usec) > 3 * USEC_PER_SEC) {
+                if (udev_rules_check_timestamp(manager->rules) ||
+                    udev_builtin_validate(manager->udev))
+                        manager_reload(manager);
+
+                manager->last_usec = now(CLOCK_MONOTONIC);
+        }
+
+        udev_builtin_init(manager->udev);
+
+        if (!manager->rules) {
+                manager->rules = udev_rules_new(manager->udev, arg_resolve_names);
+                if (!manager->rules)
+                        return;
+        }
+
         udev_list_node_foreach(loop, &manager->events) {
                 struct event *event = node_to_event(loop);
 
@@ -1566,7 +1590,6 @@ int main(int argc, char *argv[]) {
                 return log_error_errno(r, "failed to set up fds and listen for events: %m");
 
         for (;;) {
-                static usec_t last_usec;
                 struct epoll_event ev[8];
                 int fdcount;
                 int timeout;
@@ -1650,15 +1673,6 @@ int main(int argc, char *argv[]) {
                                 is_ctrl = true;
                 }
 
-                /* check for changed config, every 3 seconds at most */
-                if ((now(CLOCK_MONOTONIC) - last_usec) > 3 * USEC_PER_SEC) {
-                        if (udev_rules_check_timestamp(manager->rules) ||
-                            udev_builtin_validate(manager->udev))
-                                manager_reload(manager);
-
-                        last_usec = now(CLOCK_MONOTONIC);
-                }
-
                 /* event has finished */
                 if (is_worker)
                         on_worker(NULL, manager->fd_worker, 0, manager);
@@ -1668,13 +1682,7 @@ int main(int argc, char *argv[]) {
                         on_uevent(NULL, manager->fd_uevent, 0, manager);
 
                 /* start new events */
-                if (!udev_list_node_is_empty(&manager->events) && !manager->exit && !manager->stop_exec_queue) {
-                        udev_builtin_init(manager->udev);
-                        if (!manager->rules)
-                                manager->rules = udev_rules_new(manager->udev, arg_resolve_names);
-                        if (manager->rules)
-                                event_queue_start(manager);
-                }
+                event_queue_start(manager);
 
                 if (is_signal) {
                         struct signalfd_siginfo fdsi;

commit 62d43dac795beb715dd608c08762daa39fc92807
Author: Tom Gundersen <teg at jklm.no>
Date:   Wed May 13 11:26:32 2015 +0200

    udevd: introduce manager_exit() and manager_reload()
    
    The behavior is mostly unchanged, but rather than only ever calling these functions at
    fixed points in the event loop, they are called directly whenever they are invoked.

diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index 299fda8..a4b2969 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -84,7 +84,6 @@ typedef struct Manager {
         int worker_watch[2];
 
         bool stop_exec_queue:1;
-        bool reload:1;
         bool exit:1;
 } Manager;
 
@@ -689,6 +688,43 @@ static bool is_devpath_busy(Manager *manager, struct event *event) {
         return false;
 }
 
+static void manager_exit(Manager *manager) {
+
+        assert(manager);
+
+        manager->exit = true;
+
+        /* close sources of new events and discard buffered events */
+        if (manager->fd_ctrl >= 0) {
+                epoll_ctl(manager->fd_ep, EPOLL_CTL_DEL, manager->fd_ctrl, NULL);
+                manager->fd_ctrl = safe_close(manager->fd_ctrl);
+        }
+
+        if (manager->monitor) {
+                epoll_ctl(manager->fd_ep, EPOLL_CTL_DEL, manager->fd_uevent, NULL);
+                manager->monitor = udev_monitor_unref(manager->monitor);
+        }
+
+        if (manager->fd_inotify >= 0) {
+                epoll_ctl(manager->fd_ep, EPOLL_CTL_DEL, manager->fd_inotify, NULL);
+                manager->fd_inotify = safe_close(manager->fd_inotify);
+        }
+
+        /* discard queued events and kill workers */
+        event_queue_cleanup(manager, EVENT_QUEUED);
+        manager_kill_workers(manager);
+}
+
+/* reload requested, HUP signal received, rules changed, builtin changed */
+static void manager_reload(Manager *manager) {
+
+        assert(manager);
+
+        manager_kill_workers(manager);
+        manager->rules = udev_rules_unref(manager->rules);
+        udev_builtin_exit(manager->udev);
+}
+
 static void event_queue_start(Manager *manager) {
         struct udev_list_node *loop;
 
@@ -845,7 +881,7 @@ static int on_ctrl_msg(sd_event_source *s, int fd, uint32_t revents, void *userd
 
         if (udev_ctrl_get_reload(ctrl_msg) > 0) {
                 log_debug("udevd message (RELOAD) received");
-                manager->reload = true;
+                manager_reload(manager);
         }
 
         str = udev_ctrl_get_set_env(ctrl_msg);
@@ -884,7 +920,7 @@ static int on_ctrl_msg(sd_event_source *s, int fd, uint32_t revents, void *userd
 
         if (udev_ctrl_get_exit(ctrl_msg) > 0) {
                 log_debug("udevd message (EXIT) received");
-                manager->exit = true;
+                manager_exit(manager);
                 /* keep reference to block the client until we exit
                    TODO: deal with several blocking exit requests */
                 manager->ctrl_conn_blocking = udev_ctrl_connection_ref(ctrl_conn);
@@ -1042,7 +1078,7 @@ static int on_sigterm(sd_event_source *s, const struct signalfd_siginfo *si, voi
 
         assert(manager);
 
-        manager->exit = true;
+        manager_exit(manager);
 
         return 1;
 }
@@ -1052,7 +1088,7 @@ static int on_sighup(sd_event_source *s, const struct signalfd_siginfo *si, void
 
         assert(manager);
 
-        manager->reload = true;
+        manager_reload(manager);
 
         return 1;
 }
@@ -1538,26 +1574,6 @@ int main(int argc, char *argv[]) {
                 int i;
 
                 if (manager->exit) {
-                        /* close sources of new events and discard buffered events */
-                        if (manager->fd_ctrl >= 0) {
-                                epoll_ctl(manager->fd_ep, EPOLL_CTL_DEL, manager->fd_ctrl, NULL);
-                                manager->fd_ctrl = safe_close(manager->fd_ctrl);
-                        }
-
-                        if (manager->monitor) {
-                                epoll_ctl(manager->fd_ep, EPOLL_CTL_DEL, manager->fd_uevent, NULL);
-                                manager->monitor = udev_monitor_unref(manager->monitor);
-                        }
-
-                        if (manager->fd_inotify >= 0) {
-                                epoll_ctl(manager->fd_ep, EPOLL_CTL_DEL, manager->fd_inotify, NULL);
-                                manager->fd_inotify = safe_close(manager->fd_inotify);
-                        }
-
-                        /* discard queued events and kill workers */
-                        event_queue_cleanup(manager, EVENT_QUEUED);
-                        manager_kill_workers(manager);
-
                         /* exit after all has cleaned up */
                         if (udev_list_node_is_empty(&manager->events) && hashmap_isempty(manager->workers))
                                 break;
@@ -1636,22 +1652,13 @@ int main(int argc, char *argv[]) {
 
                 /* check for changed config, every 3 seconds at most */
                 if ((now(CLOCK_MONOTONIC) - last_usec) > 3 * USEC_PER_SEC) {
-                        if (udev_rules_check_timestamp(manager->rules))
-                                manager->reload = true;
-                        if (udev_builtin_validate(manager->udev))
-                                manager->reload = true;
+                        if (udev_rules_check_timestamp(manager->rules) ||
+                            udev_builtin_validate(manager->udev))
+                                manager_reload(manager);
 
                         last_usec = now(CLOCK_MONOTONIC);
                 }
 
-                /* reload requested, HUP signal received, rules changed, builtin changed */
-                if (manager->reload) {
-                        manager_kill_workers(manager);
-                        manager->rules = udev_rules_unref(manager->rules);
-                        udev_builtin_exit(manager->udev);
-                        manager->reload = false;
-                }
-
                 /* event has finished */
                 if (is_worker)
                         on_worker(NULL, manager->fd_worker, 0, manager);



More information about the systemd-commits mailing list