[PATCH 1/4] wineusb.sys: Spawn a separate thread to consume Unix library events.
Zebediah Figura
wine at gitlab.winehq.org
Mon Jul 4 14:58:05 CDT 2022
From: Zebediah Figura <zfigura at 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;
--
GitLab
https://gitlab.winehq.org/wine/wine/-/merge_requests/373
More information about the wine-devel
mailing list