[systemd-devel] [PATCH 6/6] udevd: event - port spawn_wait() to sd-event

Tom Gundersen teg at jklm.no
Mon May 25 15:38:48 PDT 2015


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 processe at 'warning' leve, otherwise the
behavior is unchanged.
---
 src/test/test-udev.c    |   7 --
 src/udev/udev-event.c   | 177 +++++++++++++++++++++++++-----------------------
 src/udev/udev.h         |   2 -
 src/udev/udevadm-test.c |   8 ---
 src/udev/udevd.c        |   8 ---
 5 files changed, 94 insertions(+), 108 deletions(-)

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..b8c79b1 100644
--- a/src/udev/udev-event.c
+++ b/src/udev/udev-event.c
@@ -32,7 +32,14 @@
 
 #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;
+} Spawn;
 
 struct udev_event *udev_event_new(struct udev_device *dev) {
         struct udev *udev = udev_device_get_udev(dev);
@@ -45,7 +52,6 @@ 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);
         return event;
 }
@@ -540,102 +546,107 @@ static void spawn_read(struct udev_event *event,
                 result[respos] = '\0';
 }
 
-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;
+static int on_spawn_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
+        Spawn *spawn = userdata;
 
-        pfd[0].events = POLLIN;
-        pfd[0].fd = event->fd_signal;
+        assert(spawn);
 
-        while (pid > 0) {
-                int timeout;
-                int timeout_warn = 0;
-                int fdcount;
+        kill_and_sigcont(spawn->pid, SIGKILL);
 
-                if (timeout_usec > 0) {
-                        usec_t age_usec;
+        log_error("timeout: '%s' ["PID_FMT"], killing", spawn->cmd, spawn->pid);
 
-                        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;
+        return 1;
+}
 
-                                timeout = ((timeout_usec - timeout_warn_usec - age_usec) / USEC_PER_MSEC) + MSEC_PER_SEC;
-                        }
-                } else {
-                        timeout = -1;
-                }
+static int on_spawn_timeout_warning(sd_event_source *s, uint64_t usec, void *userdata) {
+        Spawn *spawn = userdata;
 
-                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);
+        assert(spawn);
 
-                        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);
-                        }
+        log_warning("slow: '%s' ["PID_FMT"]", spawn->cmd, spawn->pid);
+
+        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;
                 }
 
-                if (pfd[0].revents & POLLIN) {
-                        struct signalfd_siginfo fdsi;
-                        int status;
-                        ssize_t size;
+                break;
+        case CLD_KILLED:
+        case CLD_DUMPED:
+                log_warning("process '%s' terminated by signal %s.", spawn->cmd, signal_to_string(si->si_status));
 
-                        size = read(event->fd_signal, &fdsi, sizeof(struct signalfd_siginfo));
-                        if (size != sizeof(struct signalfd_siginfo))
-                                continue;
+                break;
+        default:
+                log_error("process '%s' failed due to unknown reason.", spawn->cmd);
+        }
 
-                        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;
+        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) {
+        Spawn spawn = {
+                .cmd = cmd,
+                .pid = pid,
+        };
+        _cleanup_event_unref_ sd_event *e = NULL;
+        int r, ret;
+
+        r = sd_event_new(&e);
+        if (r < 0)
+                return r;
+
+        if (timeout_usec > 0) {
+                usec_t usec, age_usec;
+
+                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) {
+                                r =  sd_event_add_time(e, NULL, clock_boottime_or_monotonic(),
+                                                       usec + timeout_warn_usec - age_usec, USEC_PER_SEC, on_spawn_timeout_warning, &spawn);
+                                if (r < 0)
+                                        return r;
                         }
+
+                        r = sd_event_add_time(e, NULL, clock_boottime_or_monotonic(),
+                                              usec + timeout_usec - age_usec, USEC_PER_SEC, on_spawn_timeout, &spawn);
+                        if (r < 0)
+                                return r;
                 }
         }
-out:
-        return err;
+
+        r = sd_event_add_child(e, NULL, pid, WEXITED, on_spawn_sigchld, &spawn);
+        if (r < 0)
+                return r;
+
+        r = sd_event_loop(e);
+        if (r < 0)
+                return r;
+
+        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 8cffd81..962c080 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -408,9 +408,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;
 
@@ -483,11 +480,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 */
-- 
2.3.4



More information about the systemd-devel mailing list