diff options
author | Tom Gundersen <teg@jklm.no> | 2015-04-27 11:26:47 +0200 |
---|---|---|
committer | Anthony G. Basile <blueness@gentoo.org> | 2015-05-26 11:26:45 -0400 |
commit | 0c804867b569142ffd07a13c6c350eca35cd81af (patch) | |
tree | b32213a87e5fcd8235c71920deaa688288724a3c /src/udev/udevd.c | |
parent | 818b85cb3bfeca3429e2b010e3437d4e532fcb4c (diff) |
udevd: worker - make refcounting clearer
Take and drop explicit references where it makes sense.
Signed-off-by: Anthony G. Basile <blueness@gentoo.org>
Diffstat (limited to 'src/udev/udevd.c')
-rw-r--r-- | src/udev/udevd.c | 48 |
1 files changed, 32 insertions, 16 deletions
diff --git a/src/udev/udevd.c b/src/udev/udevd.c index cc96a43b1c..8be9d136c5 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -147,6 +147,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); } @@ -169,9 +170,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 */ @@ -368,40 +396,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; } |