summaryrefslogtreecommitdiff
path: root/udev/udevd.c
diff options
context:
space:
mode:
Diffstat (limited to 'udev/udevd.c')
-rw-r--r--udev/udevd.c47
1 files changed, 33 insertions, 14 deletions
diff --git a/udev/udevd.c b/udev/udevd.c
index 876d2ec1df..14736366d0 100644
--- a/udev/udevd.c
+++ b/udev/udevd.c
@@ -128,6 +128,8 @@ enum worker_state {
struct worker {
struct udev_list_node node;
+ struct udev *udev;
+ int refcount;
pid_t pid;
struct udev_monitor *monitor;
enum worker_state state;
@@ -176,9 +178,22 @@ static void event_sig_handler(int signum)
}
}
+static struct worker *worker_ref(struct worker *worker)
+{
+ worker->refcount++;
+ return worker;
+}
+
static void worker_unref(struct worker *worker)
{
+ worker->refcount--;
+ if (worker->refcount > 0)
+ return;
+
+ udev_list_node_remove(&worker->node);
udev_monitor_unref(worker->monitor);
+ childs--;
+ info(worker->udev, "worker [%u] cleaned up\n", worker->pid);
free(worker);
}
@@ -201,6 +216,9 @@ static void worker_new(struct event *event)
worker = calloc(1, sizeof(struct worker));
if (worker == NULL)
return;
+ /* worker + event reference */
+ worker->refcount = 2;
+ worker->udev = event->udev;
pid = fork();
switch (pid) {
@@ -339,18 +357,17 @@ static void event_run(struct event *event)
if (worker->state != WORKER_IDLE)
continue;
- worker->event = event;
- worker->state = WORKER_RUNNING;
- event->state = EVENT_RUNNING;
count = udev_monitor_send_device(monitor, worker->monitor, event->dev);
if (count < 0) {
- event->state = EVENT_QUEUED;
- worker->event = NULL;
err(event->udev, "worker [%u] did not accept message %zi (%m), kill it\n", worker->pid, count);
- worker->state = WORKER_KILLED;
kill(worker->pid, SIGKILL);
+ worker->state = WORKER_KILLED;
continue;
}
+ worker_ref(worker);
+ worker->event = event;
+ worker->state = WORKER_RUNNING;
+ event->state = EVENT_RUNNING;
return;
}
@@ -544,6 +561,7 @@ static void worker_returned(void)
worker->event = NULL;
if (worker->state != WORKER_KILLED)
worker->state = WORKER_IDLE;
+ worker_unref(worker);
break;
}
}
@@ -702,17 +720,18 @@ static void handle_signal(struct udev *udev, int signo)
if (worker->pid != pid)
continue;
- /* fail event, if worker died unexpectedly */
- if (worker->event != NULL) {
- worker->event->exitcode = status;
+ info(udev, "worker [%u] exit\n", pid);
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
err(udev, "worker [%u] unexpectedly returned with status 0x%04x\n", pid, status);
- event_queue_delete(worker->event);
+ if (worker->event != NULL) {
+ err(udev, "worker [%u] failed while handling '%s'\n", pid, worker->event->devpath);
+ worker->event->exitcode = -32;
+ event_queue_delete(worker->event);
+ /* drop reference from running event */
+ worker_unref(worker);
+ }
}
-
- udev_list_node_remove(&worker->node);
worker_unref(worker);
- childs--;
- info(udev, "worker [%u] exit\n", pid);
break;
}
}