[PATCH] winejoystick.drv: Fix long time consuming task of looking for joysticks

Bruno Jesus 00cpxxx at gmail.com
Wed Aug 31 22:18:32 CDT 2016


Fixes bug https://bugs.winehq.org/show_bug.cgi?id=41217

This is a regression I didn't think could happen initially but now I see. In the worst case if there are no joysticks the code will attempt 60 open calls to invalid files, this takes too much time on applications that share time with other tasks. In the particular case of bug 41217 the emulator sound gets choppy.

This approach scans the joystick directory and only tries to open real joysticks. To reduce wasted time even further it will only try to look again for joysticks after 2 seconds if the last attempt failed.

Signed-off-by: Bruno Jesus <00cpxxx at gmail.com>
---
 dlls/winejoystick.drv/joystick_linux.c | 80 ++++++++++++++++++++++++----------
 1 file changed, 56 insertions(+), 24 deletions(-)

diff --git a/dlls/winejoystick.drv/joystick_linux.c b/dlls/winejoystick.drv/joystick_linux.c
index 289e728..b1494ee 100644
--- a/dlls/winejoystick.drv/joystick_linux.c
+++ b/dlls/winejoystick.drv/joystick_linux.c
@@ -47,6 +47,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <fcntl.h>
+#include <dirent.h>
 #ifdef HAVE_SYS_IOCTL_H
 #include <sys/ioctl.h>
 #endif
@@ -57,8 +58,8 @@
 #ifdef SW_MAX
 #undef SW_MAX
 #endif
-#define JOYDEV_NEW "/dev/input/js%d"
-#define JOYDEV_OLD "/dev/js%d"
+#define JOYDEV_NEW "/dev/input/"
+#define JOYDEV_OLD "/dev/"
 #include <errno.h>
 
 #include "joystick.h"
@@ -156,44 +157,75 @@ struct js_status
     int y;
 };
 
+static int filter_js(const struct dirent *file)
+{
+    return file->d_name[0] == 'j' && file->d_name[1] == 's' && isdigit(file->d_name[2]);
+}
+
+static int sort_js(const struct dirent **a, const struct dirent **b)
+{
+    return atoi(a[0]->d_name + 2) - atoi(b[0]->d_name + 2);
+}
+
 /**************************************************************************
  *                              JSTCK_OpenDevice           [internal]
  */
 static	int	JSTCK_OpenDevice(WINE_JSTCK* jstick)
 {
-    char  buf[20];
-    int   flags, fd, found_ix, i;
-
-    if (jstick->dev > 0)
-      return jstick->dev;
-
 #ifdef HAVE_LINUX_22_JOYSTICK_API
-    flags = O_RDONLY | O_NONBLOCK;
+    static const int flags = O_RDONLY | O_NONBLOCK;
 #else
-    flags = O_RDONLY;
+    static const int flags = O_RDONLY;
 #endif
+    char buf[20];
+    const char *p;
+    int fd, found_ix, joysticks, i;
+    struct dirent **files;
+    DIR *dir;
+    static DWORD last_attempt;
+    DWORD now;
+
+    if (jstick->dev > 0)
+        return jstick->dev;
+
+    /* If we failed to find the joystick in previous attempts avoid redoing
+     * the file scan in every attempt. */
+    now = GetTickCount();
+    if (now - last_attempt < 2000)
+        return -1;
+    last_attempt = now;
 
     /* The first joystick may not be at /dev/input/js0, find the correct
      * first or second device. For example the driver for XBOX 360 wireless
      * receiver creates entries starting at 20.
      */
-    for (found_ix = i = 0; i < MAXJOYSTICK; i++) {
-        sprintf(buf, JOYDEV_NEW, i);
-        if ((fd = open(buf, flags)) < 0) {
-            sprintf(buf, JOYDEV_OLD, i);
-            if ((fd = open(buf, flags)) < 0)
-                continue;
-        }
-
-        if (found_ix++ == jstick->joyIntf)
-        {
-            TRACE("Found joystick[%d] at %s\n", jstick->joyIntf, buf);
-            jstick->dev = fd;
-            break;
+    dir = opendir(JOYDEV_NEW);
+    if (dir) {
+        p = JOYDEV_NEW;
+        closedir(dir);
+    } else
+        p = JOYDEV_OLD;
+
+    joysticks = scandir(p, &files, filter_js, sort_js);
+    for (i = found_ix = 0; i < joysticks; i++) {
+        sprintf(buf, "%s%s", p, files[i]->d_name);
+        if ((fd = open(buf, flags)) < 0)
+            continue;
+
+        if (found_ix++ != jstick->joyIntf) {
+            close(fd);
+            continue;
         }
 
-        close(fd);
+        TRACE("Found joystick[%d] at %s\n", jstick->joyIntf, buf);
+        jstick->dev = fd;
+        last_attempt = 0; /* clear interval on success */
+        break;
     }
+    for (i = 0; i < joysticks; i++)
+        free(files[i]);
+    if (i)
+        free(files);
 
 #ifdef HAVE_LINUX_22_JOYSTICK_API
     if (jstick->dev > 0)
-- 
2.9.3




More information about the wine-patches mailing list