[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