summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Gundersen <teg@jklm.no>2015-04-27 11:26:47 +0200
committerTom Gundersen <teg@jklm.no>2015-05-06 18:35:55 +0200
commit3a19b32a673f133f8b953869dd11a2a17344856c (patch)
tree20a094ed31b1b4aba1d8821d52292e175f4f7bfc
parente03c7cc26ed731245827ada3aa24f6c937ff80a1 (diff)
udevd: worker - make refcounting clearer
Take and drop explicit references where it makes sense.
-rw-r--r--src/udev/udevd.c48
1 files changed, 32 insertions, 16 deletions
diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index 4ab3216ab7..f8dbe26b8f 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -144,6 +144,7 @@ static struct worker *worker_ref(struct worker *worker) {
static void worker_cleanup(struct worker *worker) {
udev_list_node_remove(&worker->node);
udev_monitor_unref(worker->monitor);
+ udev_unref(worker->udev);
children--;
free(worker);
}
@@ -166,9 +167,36 @@ static void worker_list_cleanup(struct udev *udev) {
}
}
+static int worker_new(struct worker **ret, struct udev *udev, struct udev_monitor *worker_monitor, pid_t pid) {
+ struct worker *worker;
+
+ assert(ret);
+ assert(udev);
+ assert(worker_monitor);
+ assert(pid > 1);
+
+ worker = new0(struct worker, 1);
+ if (!worker)
+ return -ENOMEM;
+
+ /* worker + event reference */
+ worker->refcount = 2;
+ worker->udev = udev_ref(udev);
+ /* close monitor, but keep address around */
+ udev_monitor_disconnect(worker_monitor);
+ worker->monitor = udev_monitor_ref(worker_monitor);
+ worker->pid = pid;
+ udev_list_node_append(&worker->node, &worker_list);
+ children++;
+
+ *ret = worker;
+
+ return 0;
+}
+
static void worker_spawn(struct event *event) {
struct udev *udev = event->udev;
- struct udev_monitor *worker_monitor;
+ _cleanup_udev_monitor_unref_ struct udev_monitor *worker_monitor = NULL;
pid_t pid;
/* listen for new events */
@@ -373,40 +401,28 @@ out:
close(worker_watch[WRITE_END]);
udev_rules_unref(rules);
udev_builtin_exit(udev);
- udev_monitor_unref(worker_monitor);
udev_unref(udev);
log_close();
exit(rc);
}
case -1:
- udev_monitor_unref(worker_monitor);
event->state = EVENT_QUEUED;
log_error_errno(errno, "fork of child failed: %m");
break;
default:
{
struct worker *worker;
+ int r;
- worker = new0(struct worker, 1);
- if (!worker) {
- udev_monitor_unref(worker_monitor);
+ r = worker_new(&worker, udev, worker_monitor, pid);
+ if (r < 0)
return;
- }
- /* worker + event reference */
- worker->refcount = 2;
- worker->udev = udev;
- /* close monitor, but keep address around */
- udev_monitor_disconnect(worker_monitor);
- worker->monitor = worker_monitor;
- worker->pid = pid;
worker->state = WORKER_RUNNING;
worker->event_start_usec = now(CLOCK_MONOTONIC);
worker->event_warned = false;
worker->event = event;
event->state = EVENT_RUNNING;
- udev_list_node_append(&worker->node, &worker_list);
- children++;
log_debug("seq %llu forked new worker ["PID_FMT"]", udev_device_get_seqnum(event->dev), pid);
break;
}