[PATCH 3/4] winebus.sys: Look for duplicate UDEV devices on the unix side.

Rémi Bernon rbernon at codeweavers.com
Fri Sep 3 02:30:50 CDT 2021


Devices are only added from a single thread but they may be destroyed
concurrently so we need to guard the list against race conditions.

Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
 dlls/winebus.sys/bus_udev.c     | 73 +++++++++++++++++++++++----------
 dlls/winebus.sys/unix_private.h |  1 +
 2 files changed, 52 insertions(+), 22 deletions(-)

diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c
index d87ee2c043e..cca1bf5e168 100644
--- a/dlls/winebus.sys/bus_udev.c
+++ b/dlls/winebus.sys/bus_udev.c
@@ -88,11 +88,21 @@ WINE_DEFAULT_DEBUG_CHANNEL(plugplay);
 
 WINE_DECLARE_DEBUG_CHANNEL(hid_report);
 
+static CRITICAL_SECTION udev_cs;
+static CRITICAL_SECTION_DEBUG udev_cs_debug =
+{
+    0, 0, &udev_cs,
+    { &udev_cs_debug.ProcessLocksList, &udev_cs_debug.ProcessLocksList },
+      0, 0, { (DWORD_PTR)(__FILE__ ": udev_cs") }
+};
+static CRITICAL_SECTION udev_cs = { &udev_cs_debug, -1, 0, 0, 0, 0 };
+
 static struct udev *udev_context = NULL;
 static struct udev_monitor *udev_monitor;
 static int deviceloop_control[2];
 static int udev_monitor_fd;
 static struct list event_queue = LIST_INIT(event_queue);
+static struct list device_list = LIST_INIT(device_list);
 
 static const WCHAR hidraw_busidW[] = {'H','I','D','R','A','W',0};
 static const WCHAR lnxev_busidW[] = {'L','N','X','E','V',0};
@@ -119,6 +129,29 @@ static inline struct platform_private *impl_from_DEVICE_OBJECT(DEVICE_OBJECT *de
     return impl_from_unix_device(get_unix_device(device));
 }
 
+static const char *get_device_syspath(struct udev_device *dev)
+{
+    struct udev_device *parent;
+
+    if ((parent = udev_device_get_parent_with_subsystem_devtype(dev, "hid", NULL)))
+        return udev_device_get_syspath(parent);
+
+    if ((parent = udev_device_get_parent_with_subsystem_devtype(dev, "usb", "usb_device")))
+        return udev_device_get_syspath(parent);
+
+    return "";
+}
+
+static struct platform_private *find_device_from_syspath(const char *path)
+{
+    struct platform_private *device;
+
+    LIST_FOR_EACH_ENTRY(device, &device_list, struct platform_private, unix_device.entry)
+        if (!strcmp(get_device_syspath(device->udev_device), path)) return device;
+
+    return NULL;
+}
+
 #ifdef HAS_PROPER_INPUT_HEADER
 
 static const BYTE ABS_TO_HID_MAP[][2] = {
@@ -547,6 +580,10 @@ static void hidraw_device_destroy(struct unix_device *iface)
 {
     struct platform_private *private = impl_from_unix_device(iface);
 
+    EnterCriticalSection(&udev_cs);
+    list_remove(&private->unix_device.entry);
+    LeaveCriticalSection(&udev_cs);
+
     if (private->report_thread)
     {
         write(private->control_pipe[1], "q", 1);
@@ -858,6 +895,10 @@ static void lnxev_device_destroy(struct unix_device *iface)
 {
     struct wine_input_private *ext = input_impl_from_unix_device(iface);
 
+    EnterCriticalSection(&udev_cs);
+    list_remove(&ext->base.unix_device.entry);
+    LeaveCriticalSection(&udev_cs);
+
     if (ext->base.report_thread)
     {
         write(ext->base.control_pipe[1], "q", 1);
@@ -1005,25 +1046,6 @@ static const struct unix_device_vtbl lnxev_device_vtbl =
 };
 #endif
 
-static const char *get_device_syspath(struct udev_device *dev)
-{
-    struct udev_device *parent;
-
-    if ((parent = udev_device_get_parent_with_subsystem_devtype(dev, "hid", NULL)))
-        return udev_device_get_syspath(parent);
-
-    if ((parent = udev_device_get_parent_with_subsystem_devtype(dev, "usb", "usb_device")))
-        return udev_device_get_syspath(parent);
-
-    return "";
-}
-
-static int check_device_syspath(DEVICE_OBJECT *device, void* context)
-{
-    struct platform_private *private = impl_from_DEVICE_OBJECT(device);
-    return strcmp(get_device_syspath(private->udev_device), context);
-}
-
 static void get_device_subsystem_info(struct udev_device *dev, char const *subsystem, struct device_desc *desc)
 {
     struct udev_device *parent = NULL;
@@ -1093,9 +1115,10 @@ static void udev_add_device(struct udev_device *dev)
     TRACE("udev %s syspath %s\n", debugstr_a(devnode), udev_device_get_syspath(dev));
 
 #ifdef HAS_PROPER_INPUT_HEADER
-    device = bus_enumerate_hid_devices(lnxev_busidW, check_device_syspath, (void *)get_device_syspath(dev));
-    if (!device) device = bus_enumerate_hid_devices(hidraw_busidW, check_device_syspath, (void *)get_device_syspath(dev));
-    if (device)
+    EnterCriticalSection(&udev_cs);
+    private = find_device_from_syspath(get_device_syspath(dev));
+    LeaveCriticalSection(&udev_cs);
+    if (private)
     {
         TRACE("duplicate device found, not adding the new one\n");
         close(fd);
@@ -1156,6 +1179,9 @@ static void udev_add_device(struct udev_device *dev)
         if (!(private = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct platform_private))))
             return;
         private->unix_device.vtbl = &hidraw_device_vtbl;
+        EnterCriticalSection(&udev_cs);
+        list_add_tail(&device_list, &private->unix_device.entry);
+        LeaveCriticalSection(&udev_cs);
 
         device = bus_create_hid_device(&desc, &private->unix_device);
         if (!device) HeapFree(GetProcessHeap(), 0, private);
@@ -1166,6 +1192,9 @@ static void udev_add_device(struct udev_device *dev)
         if (!(private = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct wine_input_private))))
             return;
         private->unix_device.vtbl = &lnxev_device_vtbl;
+        EnterCriticalSection(&udev_cs);
+        list_add_tail(&device_list, &private->unix_device.entry);
+        LeaveCriticalSection(&udev_cs);
 
         device = bus_create_hid_device(&desc, &private->unix_device);
         if (!device) HeapFree(GetProcessHeap(), 0, private);
diff --git a/dlls/winebus.sys/unix_private.h b/dlls/winebus.sys/unix_private.h
index 874a837deff..81c4658068b 100644
--- a/dlls/winebus.sys/unix_private.h
+++ b/dlls/winebus.sys/unix_private.h
@@ -44,6 +44,7 @@ struct unix_device_vtbl
 struct unix_device
 {
     const struct unix_device_vtbl *vtbl;
+    struct list entry;
 };
 
 extern NTSTATUS sdl_bus_init(void *) DECLSPEC_HIDDEN;
-- 
2.33.0




More information about the wine-devel mailing list