mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-06 12:27:09 +00:00
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:
parent
f5ce9f6312
commit
46360dd732
|
@ -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),
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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, ¶ms);
|
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, ¶ms) == 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);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue