Module: wine Branch: master Commit: 5addec396680ea25bdc2f6c2dfce45159ca0364f URL: https://gitlab.winehq.org/wine/wine/-/commit/5addec396680ea25bdc2f6c2dfce451...
Author: Zebediah Figura zfigura@codeweavers.com Date: Wed Nov 30 12:22:32 2022 -0600
wineusb.sys: Do not close the device handle more than once.
Since multiple interfaces can hold onto it, we need to refcount it. In order to do this just refcount the parent device, and close the handle only when the parent device refcount reaches 0.
---
dlls/wineusb.sys/unixlib.c | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-)
diff --git a/dlls/wineusb.sys/unixlib.c b/dlls/wineusb.sys/unixlib.c index 278750c37f6..7889270c37d 100644 --- a/dlls/wineusb.sys/unixlib.c +++ b/dlls/wineusb.sys/unixlib.c @@ -45,8 +45,8 @@ struct unix_device struct list entry;
libusb_device_handle *handle; - - bool interface; + struct unix_device *parent; + unsigned int refcount; };
static libusb_hotplug_callback_handle hotplug_cb_handle; @@ -128,7 +128,7 @@ static void add_usb_device(libusb_device *libusb_device) free(unix_device); return; } - unix_device->interface = false; + unix_device->refcount = 1;
pthread_mutex_lock(&device_mutex); list_add_tail(&device_list, &unix_device->entry); @@ -175,8 +175,10 @@ static void add_usb_device(libusb_device *libusb_device) if (!(unix_iface = calloc(1, sizeof(*unix_iface)))) return;
+ ++unix_device->refcount; + unix_iface->refcount = 1; unix_iface->handle = unix_device->handle; - unix_iface->interface = true; + unix_iface->parent = unix_device; pthread_mutex_lock(&device_mutex); list_add_tail(&device_list, &unix_iface->entry); pthread_mutex_unlock(&device_mutex); @@ -547,16 +549,33 @@ static NTSTATUS usb_cancel_transfer(void *args) return STATUS_SUCCESS; }
-static NTSTATUS usb_destroy_device(void *args) +static void decref_device(struct unix_device *device) { - const struct usb_destroy_device_params *params = args; - struct unix_device *device = params->device; - pthread_mutex_lock(&device_mutex); - libusb_close(device->handle); + + if (--device->refcount) + { + pthread_mutex_unlock(&device_mutex); + return; + } + list_remove(&device->entry); + pthread_mutex_unlock(&device_mutex); + + if (device->parent) + decref_device(device->parent); + else + libusb_close(device->handle); free(device); +} + +static NTSTATUS usb_destroy_device(void *args) +{ + const struct usb_destroy_device_params *params = args; + struct unix_device *device = params->device; + + decref_device(device);
return STATUS_SUCCESS; }