summaryrefslogtreecommitdiff
path: root/src/udev/udevd.c
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2022-04-07 03:00:20 +0900
committerYu Watanabe <watanabe.yu+github@gmail.com>2022-04-13 01:08:42 +0900
commit82e0b63183cf2f3057506b29cd086e6117d506ba (patch)
tree4e3ffcbb0b2b3864c5af669ec195aa93d4825080 /src/udev/udevd.c
parenta79cba332678d72eb4efc1e1f0bef85868e33afd (diff)
downloadsystemd-82e0b63183cf2f3057506b29cd086e6117d506ba.tar.gz
udev: use child event source to manage workers
Diffstat (limited to 'src/udev/udevd.c')
-rw-r--r--src/udev/udevd.c96
1 files changed, 44 insertions, 52 deletions
diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index 532387b832..d140dcf6f6 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -151,6 +151,7 @@ typedef enum WorkerState {
typedef struct Worker {
Manager *manager;
pid_t pid;
+ sd_event_source *child_event_source;
sd_device_monitor *monitor;
WorkerState state;
Event *event;
@@ -203,9 +204,10 @@ static Worker *worker_free(Worker *worker) {
if (!worker)
return NULL;
- assert(worker->manager);
+ if (worker->manager)
+ hashmap_remove(worker->manager->workers, PID_TO_PTR(worker->pid));
- hashmap_remove(worker->manager->workers, PID_TO_PTR(worker->pid));
+ sd_event_source_unref(worker->child_event_source);
sd_device_monitor_unref(worker->monitor);
event_free(worker->event);
@@ -256,6 +258,8 @@ static Manager* manager_free(Manager *manager) {
DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
+static int on_sigchld(sd_event_source *s, const siginfo_t *si, void *userdata);
+
static int worker_new(Worker **ret, Manager *manager, sd_device_monitor *worker_monitor, pid_t pid) {
_cleanup_(worker_freep) Worker *worker = NULL;
int r;
@@ -273,17 +277,21 @@ static int worker_new(Worker **ret, Manager *manager, sd_device_monitor *worker_
return -ENOMEM;
*worker = (Worker) {
- .manager = manager,
.monitor = sd_device_monitor_ref(worker_monitor),
.pid = pid,
};
+ r = sd_event_add_child(manager->event, &worker->child_event_source, pid, WEXITED, on_sigchld, worker);
+ if (r < 0)
+ return r;
+
r = hashmap_ensure_put(&manager->workers, &worker_hash_op, PID_TO_PTR(pid), worker);
if (r < 0)
return r;
- *ret = TAKE_PTR(worker);
+ worker->manager = manager;
+ *ret = TAKE_PTR(worker);
return 0;
}
@@ -1544,59 +1552,47 @@ static int on_sighup(sd_event_source *s, const struct signalfd_siginfo *si, void
return 1;
}
-static int on_sigchld(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
- Manager *manager = userdata;
+static int on_sigchld(sd_event_source *s, const siginfo_t *si, void *userdata) {
+ Worker *worker = ASSERT_PTR(userdata);
+ Manager *manager = ASSERT_PTR(worker->manager);
+ sd_device *dev = worker->event ? ASSERT_PTR(worker->event->dev) : NULL;
+ EventResult result;
int r;
- assert(manager);
-
- for (;;) {
- pid_t pid;
- int status;
- Worker *worker;
-
- pid = waitpid(-1, &status, WNOHANG);
- if (pid <= 0)
- break;
-
- worker = hashmap_get(manager->workers, PID_TO_PTR(pid));
- if (!worker) {
- log_warning("Worker ["PID_FMT"] is unknown, ignoring", pid);
- continue;
- }
+ assert(si);
- 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), signal_to_string(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);
+ switch (si->si_code) {
+ case CLD_EXITED:
+ if (si->si_status == 0)
+ log_device_debug(dev, "Worker ["PID_FMT"] exited.", si->si_pid);
+ else
+ log_device_warning(dev, "Worker ["PID_FMT"] exited with return code %i.",
+ si->si_pid, si->si_status);
+ result = EVENT_RESULT_EXIT_STATUS_BASE + si->si_status;
+ break;
- if ((!WIFEXITED(status) || WEXITSTATUS(status) != 0) && worker->event) {
- log_device_error(worker->event->dev, "Worker ["PID_FMT"] failed", pid);
+ case CLD_KILLED:
+ case CLD_DUMPED:
+ log_device_warning(dev, "Worker ["PID_FMT"] terminated by signal %i (%s).",
+ si->si_pid, si->si_status, signal_to_string(si->si_status));
+ result = EVENT_RESULT_SIGNAL_BASE + si->si_status;
+ break;
- /* delete state from disk */
- device_delete_db(worker->event->dev);
- device_tag_index(worker->event->dev, NULL, false);
+ default:
+ assert_not_reached();
+ }
- /* Forward kernel event to libudev listeners */
- device_broadcast(manager->monitor, worker->event->dev,
- WIFEXITED(status) ? EVENT_RESULT_EXIT_STATUS_BASE + WEXITSTATUS(status):
- WIFSIGNALED(status) ? EVENT_RESULT_SIGNAL_BASE + WTERMSIG(status) : 0);
- }
+ if (result != EVENT_RESULT_SUCCESS && dev) {
+ /* delete state from disk */
+ device_delete_db(dev);
+ device_tag_index(dev, NULL, false);
- worker_free(worker);
+ /* Forward kernel event to libudev listeners */
+ device_broadcast(manager->monitor, dev, result);
}
+ worker_free(worker);
+
/* we can start new workers, try to schedule events */
event_queue_start(manager);
@@ -2018,10 +2014,6 @@ static int main_loop(Manager *manager) {
if (r < 0)
return log_error_errno(r, "Failed to create SIGHUP event source: %m");
- r = sd_event_add_signal(manager->event, NULL, SIGCHLD, on_sigchld, manager);
- if (r < 0)
- return log_error_errno(r, "Failed to create SIGCHLD event source: %m");
-
r = sd_event_set_watchdog(manager->event, true);
if (r < 0)
return log_error_errno(r, "Failed to create watchdog event source: %m");