udevd: pass a Manager objcet to event handlers
authorTom Gundersen <teg@jklm.no>
Tue, 12 May 2015 16:37:04 +0000 (18:37 +0200)
committerTom Gundersen <teg@jklm.no>
Tue, 12 May 2015 17:16:43 +0000 (19:16 +0200)
Stop relying on global variables in event handlers, and move them
all to a Manager object instead.

src/udev/udevd.c

index 1443a0d..a90e4d4 100644 (file)
 #include "hashmap.h"
 
 static struct udev_rules *rules;
-static struct udev_ctrl *udev_ctrl;
-static struct udev_ctrl_connection *udev_ctrl_conn;
-static struct udev_monitor *monitor;
 static int worker_watch[2] = { -1, -1 };
 static int fd_signal = -1;
 static int fd_ep = -1;
 static int fd_inotify = -1;
-static bool stop_exec_queue;
-static bool reload;
 static bool arg_debug = false;
 static int arg_daemonize = false;
 static int arg_resolve_names = 1;
@@ -70,10 +65,22 @@ static usec_t arg_event_timeout_usec = 180 * USEC_PER_SEC;
 static usec_t arg_event_timeout_warn_usec = 180 * USEC_PER_SEC / 3;
 static sigset_t sigmask_orig;
 static UDEV_LIST(event_list);
-Hashmap *workers;
 static char *udev_cgroup;
-static struct udev_list properties_list;
-static bool udev_exit;
+
+typedef struct Manager {
+        struct udev *udev;
+        Hashmap *workers;
+
+        struct udev_list properties;
+
+        struct udev_monitor *monitor;
+        struct udev_ctrl *ctrl;
+        struct udev_ctrl_connection *ctrl_conn_blocking;
+
+        bool stop_exec_queue:1;
+        bool reload:1;
+        bool exit:1;
+} Manager;
 
 enum event_state {
         EVENT_UNDEF,
@@ -114,8 +121,8 @@ enum worker_state {
 };
 
 struct worker {
+        Manager *manager;
         struct udev_list_node node;
-        struct udev *udev;
         int refcount;
         pid_t pid;
         struct udev_monitor *monitor;
@@ -145,31 +152,33 @@ static void worker_free(struct worker *worker) {
         if (!worker)
                 return;
 
-        hashmap_remove(workers, UINT_TO_PTR(worker->pid));
+        assert(worker->manager);
+
+        hashmap_remove(worker->manager->workers, UINT_TO_PTR(worker->pid));
         udev_monitor_unref(worker->monitor);
-        udev_unref(worker->udev);
         event_free(worker->event);
 
         free(worker);
 }
 
-static void workers_free(void) {
+static void manager_workers_free(Manager *manager) {
         struct worker *worker;
         Iterator i;
 
-        HASHMAP_FOREACH(worker, workers, i)
+        assert(manager);
+
+        HASHMAP_FOREACH(worker, manager->workers, i)
                 worker_free(worker);
 
-        hashmap_free(workers);
-        workers = NULL;
+        manager->workers = hashmap_free(manager->workers);
 }
 
-static int worker_new(struct worker **ret, struct udev *udev, struct udev_monitor *worker_monitor, pid_t pid) {
+static int worker_new(struct worker **ret, Manager *manager, struct udev_monitor *worker_monitor, pid_t pid) {
         _cleanup_free_ struct worker *worker = NULL;
         int r;
 
         assert(ret);
-        assert(udev);
+        assert(manager);
         assert(worker_monitor);
         assert(pid > 1);
 
@@ -178,17 +187,17 @@ static int worker_new(struct worker **ret, struct udev *udev, struct udev_monito
                 return -ENOMEM;
 
         worker->refcount = 1;
-        worker->udev = udev_ref(udev);
+        worker->manager = manager;
         /* close monitor, but keep address around */
         udev_monitor_disconnect(worker_monitor);
         worker->monitor = udev_monitor_ref(worker_monitor);
         worker->pid = pid;
 
-        r = hashmap_ensure_allocated(&workers, NULL);
+        r = hashmap_ensure_allocated(&manager->workers, NULL);
         if (r < 0)
                 return r;
 
-        r = hashmap_put(workers, UINT_TO_PTR(pid), worker);
+        r = hashmap_put(manager->workers, UINT_TO_PTR(pid), worker);
         if (r < 0)
                 return r;
 
@@ -212,7 +221,7 @@ static void worker_attach_event(struct worker *worker, struct event *event) {
         event->worker = worker;
 }
 
-static void worker_spawn(struct event *event) {
+static void worker_spawn(Manager *manager, struct event *event) {
         struct udev *udev = event->udev;
         _cleanup_udev_monitor_unref_ struct udev_monitor *worker_monitor = NULL;
         pid_t pid;
@@ -222,7 +231,7 @@ static void worker_spawn(struct event *event) {
         if (worker_monitor == NULL)
                 return;
         /* allow the main daemon netlink address to send devices to the worker */
-        udev_monitor_allow_unicast_sender(worker_monitor, monitor);
+        udev_monitor_allow_unicast_sender(worker_monitor, manager->monitor);
         udev_monitor_enable_receiving(worker_monitor);
 
         pid = fork();
@@ -239,10 +248,10 @@ static void worker_spawn(struct event *event) {
                 dev = event->dev;
                 event->dev = NULL;
 
-                workers_free();
+                manager_workers_free(manager);
                 event_queue_cleanup(udev, EVENT_UNDEF);
-                udev_monitor_unref(monitor);
-                udev_ctrl_unref(udev_ctrl);
+                udev_monitor_unref(manager->monitor);
+                udev_ctrl_unref(manager->ctrl);
                 close(fd_signal);
                 close(fd_ep);
                 close(worker_watch[READ_END]);
@@ -333,7 +342,7 @@ static void worker_spawn(struct event *event) {
                         /* apply rules, create node, symlinks */
                         udev_event_execute_rules(udev_event,
                                                  arg_event_timeout_usec, arg_event_timeout_warn_usec,
-                                                 &properties_list,
+                                                 &manager->properties,
                                                  rules,
                                                  &sigmask_orig);
 
@@ -430,7 +439,7 @@ out:
                 struct worker *worker;
                 int r;
 
-                r = worker_new(&worker, udev, worker_monitor, pid);
+                r = worker_new(&worker, manager, worker_monitor, pid);
                 if (r < 0)
                         return;
 
@@ -442,17 +451,20 @@ out:
         }
 }
 
-static void event_run(struct event *event) {
+static void event_run(Manager *manager, struct event *event) {
         struct worker *worker;
         Iterator i;
 
-        HASHMAP_FOREACH(worker, workers, i) {
+        assert(manager);
+        assert(event);
+
+        HASHMAP_FOREACH(worker, manager->workers, i) {
                 ssize_t count;
 
                 if (worker->state != WORKER_IDLE)
                         continue;
 
-                count = udev_monitor_send_device(monitor, worker->monitor, event->dev);
+                count = udev_monitor_send_device(manager->monitor, worker->monitor, event->dev);
                 if (count < 0) {
                         log_error_errno(errno, "worker ["PID_FMT"] did not accept message %zi (%m), kill it",
                                         worker->pid, count);
@@ -464,14 +476,14 @@ static void event_run(struct event *event) {
                 return;
         }
 
-        if (hashmap_size(workers) >= arg_children_max) {
+        if (hashmap_size(manager->workers) >= arg_children_max) {
                 if (arg_children_max > 1)
-                        log_debug("maximum number (%i) of children reached", hashmap_size(workers));
+                        log_debug("maximum number (%i) of children reached", hashmap_size(manager->workers));
                 return;
         }
 
         /* start new worker and pass initial device */
-        worker_spawn(event);
+        worker_spawn(manager, event);
 }
 
 static int event_queue_insert(struct udev_device *dev) {
@@ -501,11 +513,13 @@ static int event_queue_insert(struct udev_device *dev) {
         return 0;
 }
 
-static void worker_kill(void) {
+static void manager_kill_workers(Manager *manager) {
         struct worker *worker;
         Iterator i;
 
-        HASHMAP_FOREACH(worker, workers, i) {
+        assert(manager);
+
+        HASHMAP_FOREACH(worker, manager->workers, i) {
                 if (worker->state == WORKER_KILLED)
                         continue;
 
@@ -586,9 +600,11 @@ static bool is_devpath_busy(struct event *event) {
         return false;
 }
 
-static void event_queue_start(struct udev *udev) {
+static void event_queue_start(Manager *manager) {
         struct udev_list_node *loop;
 
+        assert(manager);
+
         udev_list_node_foreach(loop, &event_list) {
                 struct event *event = node_to_event(loop);
 
@@ -599,7 +615,7 @@ static void event_queue_start(struct udev *udev) {
                 if (is_devpath_busy(event))
                         continue;
 
-                event_run(event);
+                event_run(manager, event);
         }
 }
 
@@ -617,6 +633,10 @@ static void event_queue_cleanup(struct udev *udev, enum event_state match_type)
 }
 
 static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
+        Manager *manager = userdata;
+
+        assert(manager);
+
         for (;;) {
                 struct worker_message msg;
                 struct iovec iovec = {
@@ -662,7 +682,7 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat
                 }
 
                 /* lookup worker who sent the signal */
-                worker = hashmap_get(workers, UINT_TO_PTR(ucred->pid));
+                worker = hashmap_get(manager->workers, UINT_TO_PTR(ucred->pid));
                 if (!worker) {
                         log_debug("worker ["PID_FMT"] returned, but is no longer tracked", ucred->pid);
                         continue;
@@ -679,13 +699,13 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat
 }
 
 static int on_uevent(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
-        struct udev_monitor *m = userdata;
+        Manager *manager = userdata;
         struct udev_device *dev;
         int r;
 
-        assert(m);
+        assert(manager);
 
-        dev = udev_monitor_receive_device(m);
+        dev = udev_monitor_receive_device(manager->monitor);
         if (dev) {
                 udev_device_ensure_usec_initialized(dev, NULL);
                 r = event_queue_insert(dev);
@@ -712,15 +732,15 @@ static void event_queue_update(void) {
 
 /* receive the udevd message from userspace */
 static int on_ctrl_msg(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
-        struct udev_ctrl *uctrl = userdata;
+        Manager *manager = userdata;
         _cleanup_udev_ctrl_connection_unref_ struct udev_ctrl_connection *ctrl_conn = NULL;
         _cleanup_udev_ctrl_msg_unref_ struct udev_ctrl_msg *ctrl_msg = NULL;
         const char *str;
         int i;
 
-        assert(uctrl);
+        assert(manager);
 
-        ctrl_conn = udev_ctrl_get_connection(uctrl);
+        ctrl_conn = udev_ctrl_get_connection(manager->ctrl);
         if (!ctrl_conn)
                 return 1;
 
@@ -732,30 +752,30 @@ static int on_ctrl_msg(sd_event_source *s, int fd, uint32_t revents, void *userd
         if (i >= 0) {
                 log_debug("udevd message (SET_LOG_LEVEL) received, log_priority=%i", i);
                 log_set_max_level(i);
-                worker_kill();
+                manager_kill_workers(manager);
         }
 
         if (udev_ctrl_get_stop_exec_queue(ctrl_msg) > 0) {
                 log_debug("udevd message (STOP_EXEC_QUEUE) received");
-                stop_exec_queue = true;
+                manager->stop_exec_queue = true;
         }
 
         if (udev_ctrl_get_start_exec_queue(ctrl_msg) > 0) {
                 log_debug("udevd message (START_EXEC_QUEUE) received");
-                stop_exec_queue = false;
+                manager->stop_exec_queue = false;
         }
 
         if (udev_ctrl_get_reload(ctrl_msg) > 0) {
                 log_debug("udevd message (RELOAD) received");
-                reload = true;
+                manager->reload = true;
         }
 
         str = udev_ctrl_get_set_env(ctrl_msg);
         if (str != NULL) {
-                char *key;
+                _cleanup_free_ char *key = NULL;
 
                 key = strdup(str);
-                if (key != NULL) {
+                if (key) {
                         char *val;
 
                         val = strchr(key, '=');
@@ -764,17 +784,15 @@ static int on_ctrl_msg(sd_event_source *s, int fd, uint32_t revents, void *userd
                                 val = &val[1];
                                 if (val[0] == '\0') {
                                         log_debug("udevd message (ENV) received, unset '%s'", key);
-                                        udev_list_entry_add(&properties_list, key, NULL);
+                                        udev_list_entry_add(&manager->properties, key, NULL);
                                 } else {
                                         log_debug("udevd message (ENV) received, set '%s=%s'", key, val);
-                                        udev_list_entry_add(&properties_list, key, val);
+                                        udev_list_entry_add(&manager->properties, key, val);
                                 }
-                        } else {
+                        } else
                                 log_error("wrong key format '%s'", key);
-                        }
-                        free(key);
                 }
-                worker_kill();
+                manager_kill_workers(manager);
         }
 
         i = udev_ctrl_get_set_children_max(ctrl_msg);
@@ -793,9 +811,10 @@ 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");
-                udev_exit = true;
-                /* keep reference to block the client until we exit */
-                udev_ctrl_conn = udev_ctrl_connection_ref(ctrl_conn);
+                manager->exit = true;
+                /* 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);
         }
 
         return 1;
@@ -906,12 +925,12 @@ static int synthesize_change(struct udev_device *dev) {
 }
 
 static int on_inotify(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
-        struct udev *udev = userdata;
+        Manager *manager = userdata;
         union inotify_event_buffer buffer;
         struct inotify_event *e;
         ssize_t l;
 
-        assert(udev);
+        assert(manager);
 
         l = read(fd, &buffer, sizeof(buffer));
         if (l < 0) {
@@ -924,7 +943,7 @@ static int on_inotify(sd_event_source *s, int fd, uint32_t revents, void *userda
         FOREACH_INOTIFY_EVENT(e, buffer, l) {
                 _cleanup_udev_device_unref_ struct udev_device *dev = NULL;
 
-                dev = udev_watch_lookup(udev, e->wd);
+                dev = udev_watch_lookup(manager->udev, e->wd);
                 if (!dev)
                         continue;
 
@@ -937,27 +956,39 @@ static int on_inotify(sd_event_source *s, int fd, uint32_t revents, void *userda
                          * generated a "change" event, but we won't have queued up
                          * the resultant uevent yet. Do that.
                          */
-                        on_uevent(NULL, -1, 0, monitor);
+                        on_uevent(NULL, -1, 0, manager);
                 } else if (e->mask & IN_IGNORED)
-                        udev_watch_end(udev, dev);
+                        udev_watch_end(manager->udev, dev);
         }
 
         return 1;
 }
 
 static int on_request_exit(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
-        udev_exit = true;
+        Manager *manager = userdata;
+
+        assert(manager);
+
+        manager->exit = true;
 
         return 1;
 }
 
 static int on_request_reload(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
-        reload = true;
+        Manager *manager = userdata;
+
+        assert(manager);
+
+        manager->reload = true;
 
         return 1;
 }
 
 static int on_sigchld(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
+        Manager *manager = userdata;
+
+        assert(manager);
+
         for (;;) {
                 pid_t pid;
                 int status;
@@ -967,7 +998,7 @@ static int on_sigchld(sd_event_source *s, const struct signalfd_siginfo *si, voi
                 if (pid <= 0)
                         return 1;
 
-                worker = hashmap_get(workers, UINT_TO_PTR(pid));
+                worker = hashmap_get(manager->workers, UINT_TO_PTR(pid));
                 if (!worker) {
                         log_warning("worker ["PID_FMT"] is unknown, ignoring", pid);
                         return 1;
@@ -996,7 +1027,7 @@ static int on_sigchld(sd_event_source *s, const struct signalfd_siginfo *si, voi
                                 udev_device_delete_db(worker->event->dev);
                                 udev_device_tag_index(worker->event->dev, NULL, false);
                                 /* forward kernel event without amending it */
-                                udev_monitor_send_device(monitor, NULL, worker->event->dev_kernel);
+                                udev_monitor_send_device(manager->monitor, NULL, worker->event->dev_kernel);
                         }
                 }
 
@@ -1006,7 +1037,7 @@ static int on_sigchld(sd_event_source *s, const struct signalfd_siginfo *si, voi
         return 1;
 }
 
-static int systemd_fds(struct udev *udev, int *rctrl, int *rnetlink) {
+static int systemd_fds(int *rctrl, int *rnetlink) {
         int ctrl = -1, netlink = -1;
         int fd, n;
 
@@ -1182,8 +1213,45 @@ static int parse_argv(int argc, char *argv[]) {
         return 1;
 }
 
+static void manager_free(Manager *manager) {
+        if (!manager)
+                return;
+
+        udev_unref(manager->udev);
+        manager_workers_free(manager);
+
+        udev_monitor_unref(manager->monitor);
+        udev_ctrl_unref(manager->ctrl);
+        udev_ctrl_connection_unref(manager->ctrl_conn_blocking);
+
+        udev_list_cleanup(&manager->properties);
+
+        free(manager);
+}
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
+
+static int manager_new(Manager **ret) {
+        _cleanup_(manager_freep) Manager *manager = NULL;
+
+        assert(ret);
+
+        manager = new0(Manager, 1);
+        if (!manager)
+                return log_oom();
+
+        manager->udev = udev_new();
+        if (!manager->udev)
+                return log_error_errno(errno, "could not allocate udev context: %m");
+
+        *ret = manager;
+        manager = NULL;
+
+        return 1;
+}
+
 int main(int argc, char *argv[]) {
-        struct udev *udev;
+        _cleanup_(manager_freep) Manager *manager = NULL;
         sigset_t mask;
         int fd_ctrl = -1;
         int fd_netlink = -1;
@@ -1195,16 +1263,14 @@ int main(int argc, char *argv[]) {
         struct epoll_event ep_worker = { .events = EPOLLIN };
         int r = 0, one = 1;
 
-        udev = udev_new();
-        if (!udev) {
-                r = log_error_errno(errno, "could not allocate udev context: %m");
-                goto exit;
-        }
-
         log_set_target(LOG_TARGET_AUTO);
         log_parse_environment();
         log_open();
 
+        r = manager_new(&manager);
+        if (r < 0)
+                goto exit;
+
         r = parse_argv(argc, argv);
         if (r <= 0)
                 goto exit;
@@ -1236,7 +1302,7 @@ int main(int argc, char *argv[]) {
 
         umask(022);
 
-        udev_list_init(udev, &properties_list, true);
+        udev_list_init(manager->udev, &manager->properties, true);
 
         r = mkdir("/run/udev", 0755);
         if (r < 0 && errno != EEXIST) {
@@ -1263,16 +1329,16 @@ int main(int argc, char *argv[]) {
                 }
         }
 
-        if (systemd_fds(udev, &fd_ctrl, &fd_netlink) >= 0) {
+        if (systemd_fds(&fd_ctrl, &fd_netlink) >= 0) {
                 /* get control and netlink socket from systemd */
-                udev_ctrl = udev_ctrl_new_from_fd(udev, fd_ctrl);
-                if (!udev_ctrl) {
+                manager->ctrl = udev_ctrl_new_from_fd(manager->udev, fd_ctrl);
+                if (!manager->ctrl) {
                         r = log_error_errno(EINVAL, "error taking over udev control socket");
                         goto exit;
                 }
 
-                monitor = udev_monitor_new_from_netlink_fd(udev, "kernel", fd_netlink);
-                if (!monitor) {
+                manager->monitor = udev_monitor_new_from_netlink_fd(manager->udev, "kernel", fd_netlink);
+                if (!manager->monitor) {
                         r = log_error_errno(EINVAL, "error taking over netlink socket");
                         goto exit;
                 }
@@ -1282,38 +1348,38 @@ int main(int argc, char *argv[]) {
                         udev_cgroup = NULL;
         } else {
                 /* open control and netlink socket */
-                udev_ctrl = udev_ctrl_new(udev);
-                if (!udev_ctrl) {
+                manager->ctrl = udev_ctrl_new(manager->udev);
+                if (!manager->ctrl) {
                         r = log_error_errno(EINVAL, "error initializing udev control socket");
                         goto exit;
                 }
-                fd_ctrl = udev_ctrl_get_fd(udev_ctrl);
+                fd_ctrl = udev_ctrl_get_fd(manager->ctrl);
 
-                monitor = udev_monitor_new_from_netlink(udev, "kernel");
-                if (!monitor) {
+                manager->monitor = udev_monitor_new_from_netlink(manager->udev, "kernel");
+                if (!manager->monitor) {
                         r = log_error_errno(EINVAL, "error initializing netlink socket");
                         goto exit;
                 }
-                fd_netlink = udev_monitor_get_fd(monitor);
+                fd_netlink = udev_monitor_get_fd(manager->monitor);
 
-                udev_monitor_set_receive_buffer_size(monitor, 128 * 1024 * 1024);
+                udev_monitor_set_receive_buffer_size(manager->monitor, 128 * 1024 * 1024);
         }
 
-        if (udev_monitor_enable_receiving(monitor) < 0) {
+        if (udev_monitor_enable_receiving(manager->monitor) < 0) {
                 r = log_error_errno(EINVAL, "error binding netlink socket");
                 goto exit;
         }
 
-        if (udev_ctrl_enable_receiving(udev_ctrl) < 0) {
+        if (udev_ctrl_enable_receiving(manager->ctrl) < 0) {
                 r = log_error_errno(EINVAL, "error binding udev control socket");
                 goto exit;
         }
 
         log_info("starting version " VERSION);
 
-        udev_builtin_init(udev);
+        udev_builtin_init(manager->udev);
 
-        rules = udev_rules_new(udev, arg_resolve_names);
+        rules = udev_rules_new(manager->udev, arg_resolve_names);
         if (!rules) {
                 r = log_error_errno(ENOMEM, "error reading rules");
                 goto exit;
@@ -1357,12 +1423,12 @@ int main(int argc, char *argv[]) {
 
         udev_list_node_init(&event_list);
 
-        fd_inotify = udev_watch_init(udev);
+        fd_inotify = udev_watch_init(manager->udev);
         if (fd_inotify < 0) {
                 r = log_error_errno(ENOMEM, "error initializing inotify");
                 goto exit;
         }
-        udev_watch_restore(udev);
+        udev_watch_restore(manager->udev);
 
         /* block and listen to all signals on signalfd */
         sigfillset(&mask);
@@ -1412,16 +1478,15 @@ int main(int argc, char *argv[]) {
                 bool is_worker, is_signal, is_inotify, is_netlink, is_ctrl;
                 int i;
 
-                if (udev_exit) {
+                if (manager->exit) {
                         /* close sources of new events and discard buffered events */
                         if (fd_ctrl >= 0) {
                                 epoll_ctl(fd_ep, EPOLL_CTL_DEL, fd_ctrl, NULL);
                                 fd_ctrl = -1;
                         }
-                        if (monitor != NULL) {
+                        if (manager->monitor) {
                                 epoll_ctl(fd_ep, EPOLL_CTL_DEL, fd_netlink, NULL);
-                                udev_monitor_unref(monitor);
-                                monitor = NULL;
+                                manager->monitor = udev_monitor_unref(manager->monitor);
                         }
                         if (fd_inotify >= 0) {
                                 epoll_ctl(fd_ep, EPOLL_CTL_DEL, fd_inotify, NULL);
@@ -1430,16 +1495,16 @@ int main(int argc, char *argv[]) {
                         }
 
                         /* discard queued events and kill workers */
-                        event_queue_cleanup(udev, EVENT_QUEUED);
-                        worker_kill();
+                        event_queue_cleanup(manager->udev, EVENT_QUEUED);
+                        manager_kill_workers(manager);
 
                         /* exit after all has cleaned up */
-                        if (udev_list_node_is_empty(&event_list) && hashmap_isempty(workers))
+                        if (udev_list_node_is_empty(&event_list) && hashmap_isempty(manager->workers))
                                 break;
 
                         /* timeout at exit for workers to finish */
                         timeout = 30 * MSEC_PER_SEC;
-                } else if (udev_list_node_is_empty(&event_list) && hashmap_isempty(workers)) {
+                } else if (udev_list_node_is_empty(&event_list) && hashmap_isempty(manager->workers)) {
                         /* we are idle */
                         timeout = -1;
 
@@ -1463,7 +1528,7 @@ int main(int argc, char *argv[]) {
                         Iterator j;
 
                         /* timeout */
-                        if (udev_exit) {
+                        if (manager->exit) {
                                 log_error("timeout, giving up waiting for workers to finish");
                                 break;
                         }
@@ -1471,11 +1536,11 @@ int main(int argc, char *argv[]) {
                         /* kill idle workers */
                         if (udev_list_node_is_empty(&event_list)) {
                                 log_debug("cleanup idle workers");
-                                worker_kill();
+                                manager_kill_workers(manager);
                         }
 
                         /* check for hanging events */
-                        HASHMAP_FOREACH(worker, workers, j) {
+                        HASHMAP_FOREACH(worker, manager->workers, j) {
                                 struct event *event = worker->event;
                                 usec_t ts;
 
@@ -1519,36 +1584,36 @@ 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(rules))
-                                reload = true;
-                        if (udev_builtin_validate(udev))
-                                reload = true;
+                                manager->reload = true;
+                        if (udev_builtin_validate(manager->udev))
+                                manager->reload = true;
 
                         last_usec = now(CLOCK_MONOTONIC);
                 }
 
                 /* reload requested, HUP signal received, rules changed, builtin changed */
-                if (reload) {
-                        worker_kill();
+                if (manager->reload) {
+                        manager_kill_workers(manager);
                         rules = udev_rules_unref(rules);
-                        udev_builtin_exit(udev);
-                        reload = false;
+                        udev_builtin_exit(manager->udev);
+                        manager->reload = false;
                 }
 
                 /* event has finished */
                 if (is_worker)
-                        on_worker(NULL, fd_worker, 0, NULL);
+                        on_worker(NULL, fd_worker, 0, manager);
 
                 /* uevent from kernel */
                 if (is_netlink)
-                        on_uevent(NULL, fd_netlink, 0, monitor);
+                        on_uevent(NULL, fd_netlink, 0, manager);
 
                 /* start new events */
-                if (!udev_list_node_is_empty(&event_list) && !udev_exit && !stop_exec_queue) {
-                        udev_builtin_init(udev);
+                if (!udev_list_node_is_empty(&event_list) && !manager->exit && !manager->stop_exec_queue) {
+                        udev_builtin_init(manager->udev);
                         if (rules == NULL)
-                                rules = udev_rules_new(udev, arg_resolve_names);
+                                rules = udev_rules_new(manager->udev, arg_resolve_names);
                         if (rules != NULL)
-                                event_queue_start(udev);
+                                event_queue_start(manager);
                 }
 
                 if (is_signal) {
@@ -1560,25 +1625,25 @@ int main(int argc, char *argv[]) {
                                 switch (fdsi.ssi_signo) {
                                 case SIGINT:
                                 case SIGTERM:
-                                        on_request_exit(NULL, &fdsi, NULL);
+                                        on_request_exit(NULL, &fdsi, manager);
                                         break;
                                 case SIGHUP:
-                                        on_request_reload(NULL, &fdsi, NULL);
+                                        on_request_reload(NULL, &fdsi, manager);
                                         break;
                                 case SIGCHLD:
-                                        on_sigchld(NULL, &fdsi, NULL);
+                                        on_sigchld(NULL, &fdsi, manager);
                                         break;
                                 }
                         }
                 }
 
                 /* we are shutting down, the events below are not handled anymore */
-                if (udev_exit)
+                if (manager->exit)
                         continue;
 
                 /* device node watch */
                 if (is_inotify)
-                        on_inotify(NULL, fd_inotify, 0, udev);
+                        on_inotify(NULL, fd_inotify, 0, manager);
 
                 /*
                  * This needs to be after the inotify handling, to make sure,
@@ -1586,31 +1651,25 @@ int main(int argc, char *argv[]) {
                  * "change" events by the inotify device node watch.
                  */
                 if (is_ctrl)
-                        on_ctrl_msg(NULL, fd_ctrl, 0, udev_ctrl);
+                        on_ctrl_msg(NULL, fd_ctrl, 0, manager);
         }
 
 exit:
-        udev_ctrl_cleanup(udev_ctrl);
+        udev_ctrl_cleanup(manager->ctrl);
         unlink("/run/udev/queue");
 exit_daemonize:
         if (fd_ep >= 0)
                 close(fd_ep);
-        workers_free();
-        event_queue_cleanup(udev, EVENT_UNDEF);
+        event_queue_cleanup(manager->udev, EVENT_UNDEF);
         udev_rules_unref(rules);
-        udev_builtin_exit(udev);
+        udev_builtin_exit(manager->udev);
         if (fd_signal >= 0)
                 close(fd_signal);
         if (worker_watch[READ_END] >= 0)
                 close(worker_watch[READ_END]);
         if (worker_watch[WRITE_END] >= 0)
                 close(worker_watch[WRITE_END]);
-        udev_monitor_unref(monitor);
-        udev_ctrl_connection_unref(udev_ctrl_conn);
-        udev_ctrl_unref(udev_ctrl);
-        udev_list_cleanup(&properties_list);
         mac_selinux_finish();
-        udev_unref(udev);
         log_close();
         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
 }