Use stat() to minimize input device opens when not using udev
authorCameron Gutman <cameron.gutman@gmail.com>
Wed, 20 Nov 2019 20:27:45 -0800
changeset 13310f9a9707ff56d
parent 13309 a72231930f12
child 13311 81ca537d1287
Use stat() to minimize input device opens when not using udev

Calling open() on input devices can generate device I/O which blocks
the main thread and causes dropped frames. Using stat() we can avoid
opening anything unless /dev/input has changed since we last polled.

We could have used something fancy like inotify, but it didn't seem
worth the added complexity for this uncommon non-udev case.
src/joystick/linux/SDL_sysjoystick.c
     1.1 --- a/src/joystick/linux/SDL_sysjoystick.c	Tue Dec 03 07:12:55 2019 -0800
     1.2 +++ b/src/joystick/linux/SDL_sysjoystick.c	Wed Nov 20 20:27:45 2019 -0800
     1.3 @@ -80,7 +80,8 @@
     1.4  static int numjoysticks = 0;
     1.5  
     1.6  #if !SDL_USE_LIBUDEV
     1.7 -static Uint32 last_joy_detect_time = 0;
     1.8 +static Uint32 last_joy_detect_time;
     1.9 +static time_t last_input_dir_mtime;
    1.10  #endif
    1.11  
    1.12  #define test_bit(nr, addr) \
    1.13 @@ -421,21 +422,28 @@
    1.14      Uint32 now = SDL_GetTicks();
    1.15  
    1.16      if (!last_joy_detect_time || SDL_TICKS_PASSED(now, last_joy_detect_time + SDL_JOY_DETECT_INTERVAL_MS)) {
    1.17 -        DIR *folder;
    1.18 -        struct dirent *dent;
    1.19 +        struct stat sb;
    1.20  
    1.21 -        folder = opendir("/dev/input");
    1.22 -        if (folder) {
    1.23 -            while ((dent = readdir(folder))) {
    1.24 -                int len = SDL_strlen(dent->d_name);
    1.25 -                if (len > 5 && SDL_strncmp(dent->d_name, "event", 5) == 0) {
    1.26 -                    char path[PATH_MAX];
    1.27 -                    SDL_snprintf(path, SDL_arraysize(path), "/dev/input/%s", dent->d_name);
    1.28 -                    MaybeAddDevice(path);
    1.29 +        /* Opening input devices can generate synchronous device I/O, so avoid it if we can */
    1.30 +        if (stat("/dev/input", &sb) == 0 && sb.st_mtime != last_input_dir_mtime) {
    1.31 +            DIR *folder;
    1.32 +            struct dirent *dent;
    1.33 +
    1.34 +            folder = opendir("/dev/input");
    1.35 +            if (folder) {
    1.36 +                while ((dent = readdir(folder))) {
    1.37 +                    int len = SDL_strlen(dent->d_name);
    1.38 +                    if (len > 5 && SDL_strncmp(dent->d_name, "event", 5) == 0) {
    1.39 +                        char path[PATH_MAX];
    1.40 +                        SDL_snprintf(path, SDL_arraysize(path), "/dev/input/%s", dent->d_name);
    1.41 +                        MaybeAddDevice(path);
    1.42 +                    }
    1.43                  }
    1.44 +
    1.45 +                closedir(folder);
    1.46              }
    1.47  
    1.48 -            closedir(folder);
    1.49 +            last_input_dir_mtime = sb.st_mtime;
    1.50          }
    1.51  
    1.52          last_joy_detect_time = now;
    1.53 @@ -483,6 +491,10 @@
    1.54      /* Force a scan to build the initial device list */
    1.55      SDL_UDEV_Scan();
    1.56  #else
    1.57 +    /* Force immediate joystick detection */
    1.58 +    last_joy_detect_time = 0;
    1.59 +    last_input_dir_mtime = 0;
    1.60 +
    1.61      /* Report all devices currently present */
    1.62      LINUX_JoystickDetect();
    1.63  #endif