wineusb.sys: Move event handling to a single thread.

Also fixes a segmentation fault on exit of winedevice.exe.

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52213
This commit is contained in:
Ivo Ivanov 2022-09-04 11:47:37 +03:00 committed by Alexandre Julliard
parent f5ce9f6312
commit 46360dd732
3 changed files with 43 additions and 56 deletions

View file

@ -51,10 +51,7 @@ struct unix_device
static libusb_hotplug_callback_handle hotplug_cb_handle; static libusb_hotplug_callback_handle hotplug_cb_handle;
static bool thread_shutdown; static volatile bool thread_shutdown;
static pthread_cond_t event_cond = PTHREAD_COND_INITIALIZER;
static pthread_mutex_t event_mutex = PTHREAD_MUTEX_INITIALIZER;
static struct usb_event *usb_events; static struct usb_event *usb_events;
static size_t usb_event_count, usb_events_capacity; static size_t usb_event_count, usb_events_capacity;
@ -92,28 +89,21 @@ static bool array_reserve(void **elements, size_t *capacity, size_t count, size_
static void queue_event(const struct usb_event *event) 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))) if (array_reserve((void **)&usb_events, &usb_events_capacity, usb_event_count + 1, sizeof(*usb_events)))
usb_events[usb_event_count++] = *event; usb_events[usb_event_count++] = *event;
else else
ERR("Failed to queue event.\n"); ERR("Failed to queue event.\n");
pthread_mutex_unlock(&event_mutex);
pthread_cond_signal(&event_cond);
} }
static NTSTATUS usb_get_event(void *args) static bool get_event(struct usb_event *event)
{ {
const struct usb_get_event_params *params = args; if (!usb_event_count) return false;
pthread_mutex_lock(&event_mutex); *event = usb_events[0];
while (!usb_event_count)
pthread_cond_wait(&event_cond, &event_mutex);
*params->event = usb_events[0];
if (--usb_event_count) if (--usb_event_count)
memmove(usb_events, usb_events + 1, usb_event_count * sizeof(*usb_events)); memmove(usb_events, usb_events + 1, usb_event_count * sizeof(*usb_events));
pthread_mutex_unlock(&event_mutex);
return STATUS_SUCCESS; return true;
} }
static void add_usb_device(libusb_device *libusb_device) static void add_usb_device(libusb_device *libusb_device)
@ -239,10 +229,30 @@ static int LIBUSB_CALL hotplug_cb(libusb_context *context, libusb_device *device
static NTSTATUS usb_main_loop(void *args) static NTSTATUS usb_main_loop(void *args)
{ {
static const struct usb_event shutdown_event = {.type = USB_EVENT_SHUTDOWN}; const struct usb_main_loop_params *params = args;
int ret; int ret;
TRACE("Starting libusb event thread.\n"); while (!thread_shutdown)
{
if (get_event(params->event)) return STATUS_PENDING;
if ((ret = libusb_handle_events(NULL)))
ERR("Error handling events: %s\n", libusb_strerror(ret));
}
libusb_exit(NULL);
free(usb_events);
usb_events = NULL;
usb_event_count = usb_events_capacity = 0;
thread_shutdown = false;
TRACE("USB main loop exiting.\n");
return STATUS_SUCCESS;
}
static NTSTATUS usb_init(void *args)
{
int ret;
if ((ret = libusb_init(NULL))) if ((ret = libusb_init(NULL)))
{ {
@ -260,17 +270,6 @@ static NTSTATUS usb_main_loop(void *args)
return STATUS_UNSUCCESSFUL; return STATUS_UNSUCCESSFUL;
} }
while (!thread_shutdown)
{
if ((ret = libusb_handle_events(NULL)))
ERR("Error handling events: %s\n", libusb_strerror(ret));
}
libusb_exit(NULL);
queue_event(&shutdown_event);
TRACE("Shutting down libusb event thread.\n");
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
@ -566,8 +565,8 @@ const unixlib_entry_t __wine_unix_call_funcs[] =
{ {
#define X(name) [unix_ ## name] = name #define X(name) [unix_ ## name] = name
X(usb_main_loop), X(usb_main_loop),
X(usb_init),
X(usb_exit), X(usb_exit),
X(usb_get_event),
X(usb_submit_urb), X(usb_submit_urb),
X(usb_cancel_transfer), X(usb_cancel_transfer),
X(usb_destroy_device), X(usb_destroy_device),

View file

@ -31,7 +31,6 @@ enum usb_event_type
USB_EVENT_ADD_DEVICE, USB_EVENT_ADD_DEVICE,
USB_EVENT_REMOVE_DEVICE, USB_EVENT_REMOVE_DEVICE,
USB_EVENT_TRANSFER_COMPLETE, USB_EVENT_TRANSFER_COMPLETE,
USB_EVENT_SHUTDOWN,
}; };
struct usb_event struct usb_event
@ -53,7 +52,7 @@ struct usb_event
} u; } u;
}; };
struct usb_get_event_params struct usb_main_loop_params
{ {
struct usb_event *event; struct usb_event *event;
}; };
@ -77,8 +76,8 @@ struct usb_destroy_device_params
enum unix_funcs enum unix_funcs
{ {
unix_usb_main_loop, unix_usb_main_loop,
unix_usb_init,
unix_usb_exit, unix_usb_exit,
unix_usb_get_event,
unix_usb_submit_urb, unix_usb_submit_urb,
unix_usb_cancel_transfer, unix_usb_cancel_transfer,
unix_usb_destroy_device, unix_usb_destroy_device,

View file

@ -165,14 +165,7 @@ static void remove_unix_device(struct unix_device *unix_device)
IoInvalidateDeviceRelations(bus_pdo, BusRelations); IoInvalidateDeviceRelations(bus_pdo, BusRelations);
} }
static HANDLE libusb_event_thread, event_thread; static HANDLE event_thread;
static DWORD CALLBACK libusb_event_thread_proc(void *arg)
{
WINE_UNIX_CALL(unix_usb_main_loop, NULL);
return 0;
}
static void complete_irp(IRP *irp) static void complete_irp(IRP *irp)
{ {
@ -187,18 +180,18 @@ static void complete_irp(IRP *irp)
static DWORD CALLBACK event_thread_proc(void *arg) static DWORD CALLBACK event_thread_proc(void *arg)
{ {
struct usb_event event; struct usb_event event;
struct usb_main_loop_params params =
TRACE("Starting client event thread.\n");
for (;;)
{ {
struct usb_get_event_params params = .event = &event,
{ };
.event = &event,
};
WINE_UNIX_CALL(unix_usb_get_event, &params); TRACE("Starting event thread.\n");
if (WINE_UNIX_CALL(unix_usb_init, NULL) != STATUS_SUCCESS)
return 0;
while (WINE_UNIX_CALL(unix_usb_main_loop, &params) == STATUS_PENDING)
{
switch (event.type) switch (event.type)
{ {
case USB_EVENT_ADD_DEVICE: case USB_EVENT_ADD_DEVICE:
@ -212,12 +205,11 @@ static DWORD CALLBACK event_thread_proc(void *arg)
case USB_EVENT_TRANSFER_COMPLETE: case USB_EVENT_TRANSFER_COMPLETE:
complete_irp(event.u.completed_irp); complete_irp(event.u.completed_irp);
break; break;
case USB_EVENT_SHUTDOWN:
TRACE("Shutting down client event thread.\n");
return 0;
} }
} }
TRACE("Shutting down event thread.\n");
return 0;
} }
static NTSTATUS fdo_pnp(IRP *irp) static NTSTATUS fdo_pnp(IRP *irp)
@ -266,7 +258,6 @@ static NTSTATUS fdo_pnp(IRP *irp)
} }
case IRP_MN_START_DEVICE: case IRP_MN_START_DEVICE:
libusb_event_thread = CreateThread(NULL, 0, libusb_event_thread_proc, NULL, 0, NULL);
event_thread = CreateThread(NULL, 0, event_thread_proc, NULL, 0, NULL); event_thread = CreateThread(NULL, 0, event_thread_proc, NULL, 0, NULL);
irp->IoStatus.Status = STATUS_SUCCESS; irp->IoStatus.Status = STATUS_SUCCESS;
@ -281,8 +272,6 @@ static NTSTATUS fdo_pnp(IRP *irp)
struct usb_device *device, *cursor; struct usb_device *device, *cursor;
WINE_UNIX_CALL(unix_usb_exit, NULL); WINE_UNIX_CALL(unix_usb_exit, NULL);
WaitForSingleObject(libusb_event_thread, INFINITE);
CloseHandle(libusb_event_thread);
WaitForSingleObject(event_thread, INFINITE); WaitForSingleObject(event_thread, INFINITE);
CloseHandle(event_thread); CloseHandle(event_thread);