Skip to content

Commit

Permalink
hotplug_exit: removes all parents with a single child remaining in pa…
Browse files Browse the repository at this point in the history
…rent tree

This ensures that no parents of the direct parent of the device being considered
are left in the list, when appearing before their child(ren) in the processing order
of the context device list cleaning.
  • Loading branch information
sonatique committed Feb 4, 2024
1 parent 71ecf16 commit 7a470cf
Showing 1 changed file with 22 additions and 7 deletions.
29 changes: 22 additions & 7 deletions libusb/hotplug.c
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,25 @@ void usbi_hotplug_init(struct libusb_context *ctx)
usbi_atomic_store(&ctx->hotplug_ready, 1);
}

static void usbi_recursively_remove_parents(struct libusb_device *dev, struct libusb_device *next_dev)
{
if (dev && dev->parent_dev) {
if (usbi_atomic_load(&dev->parent_dev->refcnt) == 1) {
/* the parent was processed before this device in the list
* and therefore has its ref count already decrement for its own ref.
* The only remaining counted ref come from its remaining single child.
* It will thus be released when its child will be released.
* We remove it from the list. This is safe as parent_dev can not be
* equal to next_dev given we know at this point that it was
* previously seen in the list. */
assert (dev->parent_dev != next_dev);
list_del(&dev->parent_dev->list);
}

usbi_recursively_remove_parents(dev->parent_dev, next_dev);
}
}

void usbi_hotplug_exit(struct libusb_context *ctx)
{
struct usbi_hotplug_callback *hotplug_cb, *next_cb;
Expand Down Expand Up @@ -201,13 +220,9 @@ void usbi_hotplug_exit(struct libusb_context *ctx)
if (usbi_atomic_load(&dev->refcnt) == 1) {
list_del(&dev->list);
}
if (dev->parent_dev && usbi_atomic_load(&dev->parent_dev->refcnt) == 1) {
/* the parent was before this device in the list and will be released.
remove it from the list. this is safe as parent_dev can not be
equal to next_dev. */
assert (dev->parent_dev != next_dev);
list_del(&dev->parent_dev->list);
}

usbi_recursively_remove_parents(dev, next_dev);

libusb_unref_device(dev);
}

Expand Down

0 comments on commit 7a470cf

Please sign in to comment.