summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/udev/udevd.c156
1 files changed, 74 insertions, 82 deletions
diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index 8a97b4a405..1a2a38c990 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -49,6 +49,7 @@
#include "udev.h"
#include "udev-util.h"
#include "formats-util.h"
+#include "hashmap.h"
static struct udev_rules *rules;
static struct udev_ctrl *udev_ctrl;
@@ -69,7 +70,7 @@ 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);
-static UDEV_LIST(worker_list);
+Hashmap *workers;
static char *udev_cgroup;
static struct udev_list properties_list;
static bool udev_exit;
@@ -148,7 +149,7 @@ static void worker_free(struct worker *worker) {
if (!worker)
return;
- udev_list_node_remove(&worker->node);
+ hashmap_remove(workers, UINT_TO_PTR(worker->pid));
udev_monitor_unref(worker->monitor);
udev_unref(worker->udev);
event_free(worker->event);
@@ -158,18 +159,20 @@ static void worker_free(struct worker *worker) {
free(worker);
}
-static void worker_list_cleanup(struct udev *udev) {
- struct udev_list_node *loop, *tmp;
-
- udev_list_node_foreach_safe(loop, tmp, &worker_list) {
- struct worker *worker = node_to_worker(loop);
+static void workers_free(void) {
+ struct worker *worker;
+ Iterator i;
+ HASHMAP_FOREACH(worker, workers, i)
worker_free(worker);
- }
+
+ hashmap_free(workers);
+ workers = NULL;
}
static int worker_new(struct worker **ret, struct udev *udev, struct udev_monitor *worker_monitor, pid_t pid) {
- struct worker *worker;
+ _cleanup_free_ struct worker *worker = NULL;
+ int r;
assert(ret);
assert(udev);
@@ -186,10 +189,19 @@ static int worker_new(struct worker **ret, struct udev *udev, struct udev_monito
udev_monitor_disconnect(worker_monitor);
worker->monitor = udev_monitor_ref(worker_monitor);
worker->pid = pid;
- udev_list_node_append(&worker->node, &worker_list);
+
+ r = hashmap_ensure_allocated(&workers, NULL);
+ if (r < 0)
+ return r;
+
+ r = hashmap_put(workers, UINT_TO_PTR(pid), worker);
+ if (r < 0)
+ return r;
+
children++;
*ret = worker;
+ worker = NULL;
return 0;
}
@@ -235,7 +247,7 @@ static void worker_spawn(struct event *event) {
dev = event->dev;
event->dev = NULL;
- worker_list_cleanup(udev);
+ workers_free();
event_queue_cleanup(udev, EVENT_UNDEF);
udev_monitor_unref(monitor);
udev_ctrl_unref(udev_ctrl);
@@ -439,10 +451,10 @@ out:
}
static void event_run(struct event *event) {
- struct udev_list_node *loop;
+ struct worker *worker;
+ Iterator i;
- udev_list_node_foreach(loop, &worker_list) {
- struct worker *worker = node_to_worker(loop);
+ HASHMAP_FOREACH(worker, workers, i) {
ssize_t count;
if (worker->state != WORKER_IDLE)
@@ -498,11 +510,10 @@ static int event_queue_insert(struct udev_device *dev) {
}
static void worker_kill(struct udev *udev) {
- struct udev_list_node *loop;
-
- udev_list_node_foreach(loop, &worker_list) {
- struct worker *worker = node_to_worker(loop);
+ struct worker *worker;
+ Iterator i;
+ HASHMAP_FOREACH(worker, workers, i) {
if (worker->state == WORKER_KILLED)
continue;
@@ -633,8 +644,7 @@ static void worker_returned(int fd_worker) {
struct cmsghdr *cmsg;
ssize_t size;
struct ucred *ucred = NULL;
- struct udev_list_node *loop;
- bool found = false;
+ struct worker *worker;
size = recvmsg(fd_worker, &msghdr, MSG_DONTWAIT);
if (size < 0) {
@@ -661,25 +671,17 @@ static void worker_returned(int fd_worker) {
}
/* lookup worker who sent the signal */
- udev_list_node_foreach(loop, &worker_list) {
- struct worker *worker = node_to_worker(loop);
-
- if (worker->pid != ucred->pid)
- continue;
- else
- found = true;
-
- if (worker->state != WORKER_KILLED)
- worker->state = WORKER_IDLE;
-
- /* worker returned */
- event_free(worker->event);
-
- break;
+ worker = hashmap_get(workers, UINT_TO_PTR(ucred->pid));
+ if (!worker) {
+ log_debug("worker ["PID_FMT"] returned, but is no longer tracked", ucred->pid);
+ continue;
}
- if (!found)
- log_debug("worker ["PID_FMT"] returned, but is no longer tracked", ucred->pid);
+ if (worker->state != WORKER_KILLED)
+ worker->state = WORKER_IDLE;
+
+ /* worker returned */
+ event_free(worker->event);
}
}
@@ -914,57 +916,48 @@ static void handle_signal(struct udev *udev, int signo) {
for (;;) {
pid_t pid;
int status;
- struct udev_list_node *loop, *tmp;
- bool found = false;
+ struct worker *worker;
pid = waitpid(-1, &status, WNOHANG);
if (pid <= 0)
break;
- udev_list_node_foreach_safe(loop, tmp, &worker_list) {
- struct worker *worker = node_to_worker(loop);
+ worker = hashmap_get(workers, UINT_TO_PTR(pid));
+ if (!worker) {
+ log_warning("worker ["PID_FMT"] is unknown, ignoring", pid);
+ continue;
+ }
- if (worker->pid != pid)
- continue;
+ if (WIFEXITED(status)) {
+ if (WEXITSTATUS(status) == 0)
+ log_debug("worker ["PID_FMT"] exited", pid);
else
- found = true;
-
- if (WIFEXITED(status)) {
- if (WEXITSTATUS(status) == 0)
- log_debug("worker ["PID_FMT"] exited", pid);
- else
- log_warning("worker ["PID_FMT"] exited with return code %i", pid, WEXITSTATUS(status));
- } else if (WIFSIGNALED(status)) {
- log_warning("worker ["PID_FMT"] terminated by signal %i (%s)",
- pid, WTERMSIG(status), strsignal(WTERMSIG(status)));
- } else if (WIFSTOPPED(status)) {
- log_info("worker ["PID_FMT"] stopped", pid);
- break;
- } else if (WIFCONTINUED(status)) {
- log_info("worker ["PID_FMT"] continued", pid);
- break;
- } else {
- log_warning("worker ["PID_FMT"] exit with status 0x%04x", pid, status);
- }
+ log_warning("worker ["PID_FMT"] exited with return code %i", pid, WEXITSTATUS(status));
+ } else if (WIFSIGNALED(status)) {
+ log_warning("worker ["PID_FMT"] terminated by signal %i (%s)",
+ pid, WTERMSIG(status), strsignal(WTERMSIG(status)));
+ } else if (WIFSTOPPED(status)) {
+ log_info("worker ["PID_FMT"] stopped", pid);
+ continue;
+ } else if (WIFCONTINUED(status)) {
+ log_info("worker ["PID_FMT"] continued", pid);
+ continue;
+ } else {
+ log_warning("worker ["PID_FMT"] exit with status 0x%04x", pid, status);
+ }
- if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
- if (worker->event) {
- log_error("worker ["PID_FMT"] failed while handling '%s'", pid, worker->event->devpath);
- /* delete state from disk */
- 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);
- }
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+ if (worker->event) {
+ log_error("worker ["PID_FMT"] failed while handling '%s'", pid, worker->event->devpath);
+ /* delete state from disk */
+ 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);
}
-
- worker_free(worker);
-
- break;
}
- if (!found)
- log_warning("worker ["PID_FMT"] is unknown, ignoring", pid);
+ worker_free(worker);
}
break;
case SIGHUP:
@@ -1338,7 +1331,6 @@ int main(int argc, char *argv[]) {
log_debug("set children_max to %u", arg_children_max);
udev_list_node_init(&event_list);
- udev_list_node_init(&worker_list);
fd_inotify = udev_watch_init(udev);
if (fd_inotify < 0) {
@@ -1442,7 +1434,8 @@ int main(int argc, char *argv[]) {
continue;
if (fdcount == 0) {
- struct udev_list_node *loop;
+ struct worker *worker;
+ Iterator j;
/* timeout */
if (udev_exit) {
@@ -1457,8 +1450,7 @@ int main(int argc, char *argv[]) {
}
/* check for hanging events */
- udev_list_node_foreach(loop, &worker_list) {
- struct worker *worker = node_to_worker(loop);
+ HASHMAP_FOREACH(worker, workers, j) {
struct event *event = worker->event;
usec_t ts;
@@ -1595,7 +1587,7 @@ exit:
exit_daemonize:
if (fd_ep >= 0)
close(fd_ep);
- worker_list_cleanup(udev);
+ workers_free();
event_queue_cleanup(udev, EVENT_UNDEF);
udev_rules_unref(rules);
udev_builtin_exit(udev);