From: Zebediah Figura zfigura@codeweavers.com
--- dlls/wineusb.sys/wineusb.c | 99 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 95 insertions(+), 4 deletions(-)
diff --git a/dlls/wineusb.sys/wineusb.c b/dlls/wineusb.sys/wineusb.c index cfa88616a8f..b3d14e91839 100644 --- a/dlls/wineusb.sys/wineusb.c +++ b/dlls/wineusb.sys/wineusb.c @@ -20,6 +20,7 @@
#include <assert.h> #include <stdarg.h> +#include <stdbool.h> #include <stdlib.h> #include <pthread.h> #include <libusb.h> @@ -107,6 +108,71 @@ static DEVICE_OBJECT *bus_fdo, *bus_pdo;
static libusb_hotplug_callback_handle hotplug_cb_handle;
+static pthread_cond_t event_cond = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t event_mutex = PTHREAD_MUTEX_INITIALIZER; + +enum usb_event_type +{ + USB_EVENT_SHUTDOWN, +}; + +struct usb_event +{ + enum usb_event_type type; +}; + +static struct usb_event *usb_events; +static size_t usb_event_count, usb_events_capacity; + +static bool array_reserve(void **elements, size_t *capacity, size_t count, size_t size) +{ + unsigned int new_capacity, max_capacity; + void *new_elements; + + if (count <= *capacity) + return true; + + max_capacity = ~(size_t)0 / size; + if (count > max_capacity) + return false; + + new_capacity = max(4, *capacity); + while (new_capacity < count && new_capacity <= max_capacity / 2) + new_capacity *= 2; + if (new_capacity < count) + new_capacity = max_capacity; + + if (!(new_elements = realloc(*elements, new_capacity * size))) + return false; + + *elements = new_elements; + *capacity = new_capacity; + + return true; +} + +static void queue_event(const struct usb_event *event) +{ + pthread_mutex_lock(&event_mutex); + if (array_reserve((void **)&usb_events, &usb_events_capacity, usb_event_count + 1, sizeof(*usb_events))) + usb_events[usb_event_count++] = *event; + else + ERR("Failed to queue event.\n"); + pthread_mutex_unlock(&event_mutex); + pthread_cond_signal(&event_cond); +} + +static void get_event(struct usb_event *event) +{ + pthread_mutex_lock(&event_mutex); + while (!usb_event_count) + pthread_cond_wait(&event_cond, &event_mutex); + *event = usb_events[0]; + if (--usb_event_count) + memmove(usb_events, usb_events + 1, usb_event_count * sizeof(*usb_events)); + pthread_mutex_unlock(&event_mutex); +} + static void destroy_unix_device(struct unix_device *unix_device) { pthread_mutex_lock(&unix_device_mutex); @@ -293,7 +359,7 @@ static void remove_usb_device(libusb_device *libusb_device) }
static BOOL thread_shutdown; -static HANDLE event_thread; +static HANDLE libusb_event_thread, event_thread;
static int LIBUSB_CALL hotplug_cb(libusb_context *context, libusb_device *device, libusb_hotplug_event event, void *user_data) @@ -306,11 +372,12 @@ static int LIBUSB_CALL hotplug_cb(libusb_context *context, libusb_device *device return 0; }
-static DWORD CALLBACK event_thread_proc(void *arg) +static DWORD CALLBACK libusb_event_thread_proc(void *arg) { + static const struct usb_event shutdown_event = {.type = USB_EVENT_SHUTDOWN}; int ret;
- TRACE("Starting event thread.\n"); + TRACE("Starting libusb event thread.\n");
while (!thread_shutdown) { @@ -318,10 +385,31 @@ static DWORD CALLBACK event_thread_proc(void *arg) ERR("Error handling events: %s\n", libusb_strerror(ret)); }
- TRACE("Shutting down event thread.\n"); + queue_event(&shutdown_event); + + TRACE("Shutting down libusb event thread.\n"); return 0; }
+static DWORD CALLBACK event_thread_proc(void *arg) +{ + struct usb_event event; + + TRACE("Starting client event thread.\n"); + + for (;;) + { + get_event(&event); + + switch (event.type) + { + case USB_EVENT_SHUTDOWN: + TRACE("Shutting down client event thread.\n"); + return 0; + } + } +} + static NTSTATUS fdo_pnp(IRP *irp) { IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp); @@ -391,6 +479,8 @@ static NTSTATUS fdo_pnp(IRP *irp) libusb_hotplug_deregister_callback(NULL, hotplug_cb_handle); thread_shutdown = TRUE; libusb_interrupt_event_handler(NULL); + WaitForSingleObject(libusb_event_thread, INFINITE); + CloseHandle(libusb_event_thread); WaitForSingleObject(event_thread, INFINITE); CloseHandle(event_thread);
@@ -1007,6 +1097,7 @@ NTSTATUS WINAPI DriverEntry(DRIVER_OBJECT *driver, UNICODE_STRING *path) return STATUS_UNSUCCESSFUL; }
+ libusb_event_thread = CreateThread(NULL, 0, libusb_event_thread_proc, NULL, 0, NULL); event_thread = CreateThread(NULL, 0, event_thread_proc, NULL, 0, NULL);
driver->DriverExtension->AddDevice = driver_add_device;