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 bool thread_shutdown;
static pthread_cond_t event_cond = PTHREAD_COND_INITIALIZER;
static pthread_mutex_t event_mutex = PTHREAD_MUTEX_INITIALIZER;
static volatile bool thread_shutdown;
static struct usb_event *usb_events;
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)
{
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 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);
while (!usb_event_count)
pthread_cond_wait(&event_cond, &event_mutex);
*params->event = usb_events[0];
*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);
return STATUS_SUCCESS;
return true;
}
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 const struct usb_event shutdown_event = {.type = USB_EVENT_SHUTDOWN};
const struct usb_main_loop_params *params = args;
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)))
{
@ -260,17 +270,6 @@ static NTSTATUS usb_main_loop(void *args)
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;
}
@ -566,8 +565,8 @@ const unixlib_entry_t __wine_unix_call_funcs[] =
{
#define X(name) [unix_ ## name] = name
X(usb_main_loop),
X(usb_init),
X(usb_exit),
X(usb_get_event),
X(usb_submit_urb),
X(usb_cancel_transfer),
X(usb_destroy_device),

View file

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

View file

@ -165,14 +165,7 @@ static void remove_unix_device(struct unix_device *unix_device)
IoInvalidateDeviceRelations(bus_pdo, BusRelations);
}
static HANDLE libusb_event_thread, event_thread;
static DWORD CALLBACK libusb_event_thread_proc(void *arg)
{
WINE_UNIX_CALL(unix_usb_main_loop, NULL);
return 0;
}
static HANDLE event_thread;
static void complete_irp(IRP *irp)
{
@ -187,18 +180,18 @@ static void complete_irp(IRP *irp)
static DWORD CALLBACK event_thread_proc(void *arg)
{
struct usb_event event;
TRACE("Starting client event thread.\n");
for (;;)
struct usb_main_loop_params params =
{
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)
{
case USB_EVENT_ADD_DEVICE:
@ -212,12 +205,11 @@ static DWORD CALLBACK event_thread_proc(void *arg)
case USB_EVENT_TRANSFER_COMPLETE:
complete_irp(event.u.completed_irp);
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)
@ -266,7 +258,6 @@ static NTSTATUS fdo_pnp(IRP *irp)
}
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);
irp->IoStatus.Status = STATUS_SUCCESS;
@ -281,8 +272,6 @@ static NTSTATUS fdo_pnp(IRP *irp)
struct usb_device *device, *cursor;
WINE_UNIX_CALL(unix_usb_exit, NULL);
WaitForSingleObject(libusb_event_thread, INFINITE);
CloseHandle(libusb_event_thread);
WaitForSingleObject(event_thread, INFINITE);
CloseHandle(event_thread);