Rémi Bernon : winebus.sys: Return an event from SDL bus wait on device removal.

Alexandre Julliard julliard at winehq.org
Thu Sep 2 15:45:30 CDT 2021


Module: wine
Branch: master
Commit: 6006758ca87d7e38fb4b84bafe917e108524029f
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=6006758ca87d7e38fb4b84bafe917e108524029f

Author: Rémi Bernon <rbernon at codeweavers.com>
Date:   Mon Aug 30 11:22:52 2021 +0200

winebus.sys: Return an event from SDL bus wait on device removal.

Instead of calling bus_unlink_hid_device or IoInvalidateDeviceRelations.

Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/winebus.sys/bus_sdl.c      | 14 +++++---------
 dlls/winebus.sys/main.c         | 20 +++++++++++++++++++-
 dlls/winebus.sys/unix_private.h |  6 ++++++
 dlls/winebus.sys/unixlib.c      | 39 +++++++++++++++++++++++++++++++++++++++
 dlls/winebus.sys/unixlib.h      | 12 ++++++++++++
 5 files changed, 81 insertions(+), 10 deletions(-)

diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c
index 8259531779b..e8ae69633c0 100644
--- a/dlls/winebus.sys/bus_sdl.c
+++ b/dlls/winebus.sys/bus_sdl.c
@@ -64,6 +64,7 @@ static struct sdl_bus_options options;
 
 static void *sdl_handle = NULL;
 static UINT quit_event = -1;
+static struct list event_queue = LIST_INIT(event_queue);
 
 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
 MAKE_FUNCPTR(SDL_GetError);
@@ -730,12 +731,6 @@ static BOOL set_mapped_report_from_event(DEVICE_OBJECT *device, SDL_Event *event
     return FALSE;
 }
 
-static void try_remove_device(DEVICE_OBJECT *device)
-{
-    bus_unlink_hid_device(device);
-    IoInvalidateDeviceRelations(bus_pdo, BusRelations);
-}
-
 static void try_add_device(unsigned int index)
 {
     DWORD vid = 0, pid = 0, version = 0;
@@ -821,9 +816,7 @@ static void process_device_event(SDL_Event *event)
     else if (event->type == SDL_JOYDEVICEREMOVED)
     {
         id = ((SDL_JoyDeviceEvent *)event)->which;
-        device = bus_find_hid_device(sdl_busidW, ULongToPtr(id));
-        if (device) try_remove_device(device);
-        else WARN("failed to find device with id %d\n", id);
+        bus_event_queue_device_removed(&event_queue, sdl_busidW, ULongToPtr(id));
     }
     else if (event->type >= SDL_JOYAXISMOTION && event->type <= SDL_JOYBUTTONUP)
     {
@@ -980,15 +973,18 @@ failed:
 
 NTSTATUS sdl_bus_wait(void *args)
 {
+    struct bus_event *result = args;
     SDL_Event event;
 
     do
     {
+        if (bus_event_queue_pop(&event_queue, result)) return STATUS_PENDING;
         if (pSDL_WaitEvent(&event) != 0) process_device_event(&event);
         else WARN("SDL_WaitEvent failed: %s\n", pSDL_GetError());
     } while (event.type != quit_event);
 
     TRACE("SDL main loop exiting\n");
+    bus_event_queue_destroy(&event_queue);
     dlclose(sdl_handle);
     sdl_handle = NULL;
     return STATUS_SUCCESS;
diff --git a/dlls/winebus.sys/main.c b/dlls/winebus.sys/main.c
index 4c8c84ffe9b..ec5e7715488 100644
--- a/dlls/winebus.sys/main.c
+++ b/dlls/winebus.sys/main.c
@@ -654,6 +654,7 @@ struct bus_main_params
 static DWORD CALLBACK bus_main_thread(void *args)
 {
     struct bus_main_params bus = *(struct bus_main_params *)args;
+    DEVICE_OBJECT *device;
     NTSTATUS status;
 
     TRACE("%s main loop starting\n", debugstr_w(bus.name));
@@ -663,7 +664,24 @@ static DWORD CALLBACK bus_main_thread(void *args)
 
     bus.bus_event->type = BUS_EVENT_TYPE_NONE;
     if (status) WARN("%s bus init returned status %#x\n", debugstr_w(bus.name), status);
-    else while ((status = winebus_call(bus.wait_code, bus.bus_event)) == STATUS_PENDING) {}
+    else while ((status = winebus_call(bus.wait_code, bus.bus_event)) == STATUS_PENDING)
+    {
+        struct bus_event *event = bus.bus_event;
+        switch (event->type)
+        {
+        case BUS_EVENT_TYPE_NONE: break;
+        case BUS_EVENT_TYPE_DEVICE_REMOVED:
+            EnterCriticalSection(&device_list_cs);
+            if (!(device = bus_find_hid_device(event->device_removed.bus_id, event->device_removed.context)))
+                WARN("could not find removed device matching bus %s, context %p\n",
+                     debugstr_w(event->device_removed.bus_id), event->device_removed.context);
+            else
+                bus_unlink_hid_device(device);
+            LeaveCriticalSection(&device_list_cs);
+            IoInvalidateDeviceRelations(bus_pdo, BusRelations);
+            break;
+        }
+    }
 
     if (status) WARN("%s bus wait returned status %#x\n", debugstr_w(bus.name), status);
     else TRACE("%s main loop exited\n", debugstr_w(bus.name));
diff --git a/dlls/winebus.sys/unix_private.h b/dlls/winebus.sys/unix_private.h
index aff1e86263a..f3edef83cb7 100644
--- a/dlls/winebus.sys/unix_private.h
+++ b/dlls/winebus.sys/unix_private.h
@@ -27,6 +27,8 @@
 
 #include "unixlib.h"
 
+#include "wine/list.h"
+
 struct unix_device
 {
 };
@@ -43,4 +45,8 @@ extern NTSTATUS iohid_bus_init(void *) DECLSPEC_HIDDEN;
 extern NTSTATUS iohid_bus_wait(void *) DECLSPEC_HIDDEN;
 extern NTSTATUS iohid_bus_stop(void *) DECLSPEC_HIDDEN;
 
+extern void bus_event_queue_destroy(struct list *queue) DECLSPEC_HIDDEN;
+extern BOOL bus_event_queue_device_removed(struct list *queue, const WCHAR *bus_id, void *context) DECLSPEC_HIDDEN;
+extern BOOL bus_event_queue_pop(struct list *queue, struct bus_event *event) DECLSPEC_HIDDEN;
+
 #endif /* __WINEBUS_UNIX_PRIVATE_H */
diff --git a/dlls/winebus.sys/unixlib.c b/dlls/winebus.sys/unixlib.c
index c4090861675..13e2729e0c2 100644
--- a/dlls/winebus.sys/unixlib.c
+++ b/dlls/winebus.sys/unixlib.c
@@ -26,6 +26,7 @@
 #include "winternl.h"
 
 #include "wine/debug.h"
+#include "wine/list.h"
 #include "wine/unixlib.h"
 
 #include "unix_private.h"
@@ -42,3 +43,41 @@ const unixlib_entry_t __wine_unix_call_funcs[] =
     iohid_bus_wait,
     iohid_bus_stop,
 };
+
+void bus_event_queue_destroy(struct list *queue)
+{
+    struct bus_event *event, *next;
+
+    LIST_FOR_EACH_ENTRY_SAFE(event, next, queue, struct bus_event, entry)
+        HeapFree(GetProcessHeap(), 0, event);
+}
+
+BOOL bus_event_queue_device_removed(struct list *queue, const WCHAR *bus_id, void *context)
+{
+    ULONG size = sizeof(struct bus_event);
+    struct bus_event *event = HeapAlloc(GetProcessHeap(), 0, size);
+    if (!event) return FALSE;
+
+    event->type = BUS_EVENT_TYPE_DEVICE_REMOVED;
+    event->device_removed.bus_id = bus_id;
+    event->device_removed.context = context;
+    list_add_tail(queue, &event->entry);
+
+    return TRUE;
+}
+
+BOOL bus_event_queue_pop(struct list *queue, struct bus_event *event)
+{
+    struct list *entry = list_head(queue);
+    struct bus_event *tmp;
+
+    if (!entry) return FALSE;
+
+    tmp = LIST_ENTRY(entry, struct bus_event, entry);
+    list_remove(entry);
+
+    memcpy(event, tmp, sizeof(*event));
+    HeapFree(GetProcessHeap(), 0, tmp);
+
+    return TRUE;
+}
diff --git a/dlls/winebus.sys/unixlib.h b/dlls/winebus.sys/unixlib.h
index e6abd98601f..d9097ba9ca7 100644
--- a/dlls/winebus.sys/unixlib.h
+++ b/dlls/winebus.sys/unixlib.h
@@ -27,6 +27,7 @@
 #include <ddk/wdm.h>
 #include <hidusage.h>
 
+#include "wine/list.h"
 #include "wine/unixlib.h"
 
 struct sdl_bus_options
@@ -49,11 +50,22 @@ struct unix_device;
 enum bus_event_type
 {
     BUS_EVENT_TYPE_NONE,
+    BUS_EVENT_TYPE_DEVICE_REMOVED,
 };
 
 struct bus_event
 {
     enum bus_event_type type;
+    struct list entry;
+
+    union
+    {
+        struct
+        {
+            const WCHAR *bus_id;
+            void *context;
+        } device_removed;
+    };
 };
 
 enum unix_funcs




More information about the wine-cvs mailing list