Protect the game controller API the same way the joystick API is protected from multi-threaded access
authorSam Lantinga <slouken@libsdl.org>
Thu, 08 Dec 2016 10:13:45 -0800
changeset 10688f910d0498992
parent 10687 485d388d2d28
child 10689 69d6c1c7a2bf
Protect the game controller API the same way the joystick API is protected from multi-threaded access
src/joystick/SDL_gamecontroller.c
src/joystick/SDL_joystick.c
src/joystick/SDL_joystick_c.h
     1.1 --- a/src/joystick/SDL_gamecontroller.c	Wed Dec 07 11:41:20 2016 -0800
     1.2 +++ b/src/joystick/SDL_gamecontroller.c	Thu Dec 08 10:13:45 2016 -0800
     1.3 @@ -25,6 +25,7 @@
     1.4  #include "SDL_events.h"
     1.5  #include "SDL_assert.h"
     1.6  #include "SDL_sysjoystick.h"
     1.7 +#include "SDL_joystick_c.h"
     1.8  #include "SDL_hints.h"
     1.9  #include "SDL_gamecontrollerdb.h"
    1.10  
    1.11 @@ -1086,12 +1087,15 @@
    1.12          return (NULL);
    1.13      }
    1.14  
    1.15 +    SDL_LockJoystickList();
    1.16 +
    1.17      gamecontrollerlist = SDL_gamecontrollers;
    1.18      /* If the controller is already open, return it */
    1.19      while (gamecontrollerlist) {
    1.20          if (SDL_SYS_GetInstanceIdOfDeviceIndex(device_index) == gamecontrollerlist->joystick->instance_id) {
    1.21                  gamecontroller = gamecontrollerlist;
    1.22                  ++gamecontroller->ref_count;
    1.23 +                SDL_UnlockJoystickList();
    1.24                  return (gamecontroller);
    1.25          }
    1.26          gamecontrollerlist = gamecontrollerlist->next;
    1.27 @@ -1101,13 +1105,15 @@
    1.28      pSupportedController =  SDL_PrivateGetControllerMapping(device_index);
    1.29      if (!pSupportedController) {
    1.30          SDL_SetError("Couldn't find mapping for device (%d)", device_index);
    1.31 -        return (NULL);
    1.32 +        SDL_UnlockJoystickList();
    1.33 +        return NULL;
    1.34      }
    1.35  
    1.36      /* Create and initialize the joystick */
    1.37      gamecontroller = (SDL_GameController *) SDL_malloc((sizeof *gamecontroller));
    1.38      if (gamecontroller == NULL) {
    1.39          SDL_OutOfMemory();
    1.40 +        SDL_UnlockJoystickList();
    1.41          return NULL;
    1.42      }
    1.43  
    1.44 @@ -1115,6 +1121,7 @@
    1.45      gamecontroller->joystick = SDL_JoystickOpen(device_index);
    1.46      if (!gamecontroller->joystick) {
    1.47          SDL_free(gamecontroller);
    1.48 +        SDL_UnlockJoystickList();
    1.49          return NULL;
    1.50      }
    1.51  
    1.52 @@ -1140,7 +1147,7 @@
    1.53      gamecontroller->next = SDL_gamecontrollers;
    1.54      SDL_gamecontrollers = gamecontroller;
    1.55  
    1.56 -    SDL_SYS_JoystickUpdate(gamecontroller->joystick);
    1.57 +    SDL_UnlockJoystickList();
    1.58  
    1.59      return (gamecontroller);
    1.60  }
    1.61 @@ -1274,14 +1281,18 @@
    1.62  SDL_GameController *
    1.63  SDL_GameControllerFromInstanceID(SDL_JoystickID joyid)
    1.64  {
    1.65 -    SDL_GameController *gamecontroller = SDL_gamecontrollers;
    1.66 +    SDL_GameController *gamecontroller;
    1.67 +
    1.68 +    SDL_LockJoystickList();
    1.69 +    gamecontroller = SDL_gamecontrollers;
    1.70      while (gamecontroller) {
    1.71          if (gamecontroller->joystick->instance_id == joyid) {
    1.72 +            SDL_UnlockJoystickList();
    1.73              return gamecontroller;
    1.74          }
    1.75          gamecontroller = gamecontroller->next;
    1.76      }
    1.77 -
    1.78 +    SDL_UnlockJoystickList();
    1.79      return NULL;
    1.80  }
    1.81  
    1.82 @@ -1344,8 +1355,11 @@
    1.83      if (!gamecontroller)
    1.84          return;
    1.85  
    1.86 +    SDL_LockJoystickList();
    1.87 +
    1.88      /* First decrement ref count */
    1.89      if (--gamecontroller->ref_count > 0) {
    1.90 +        SDL_UnlockJoystickList();
    1.91          return;
    1.92      }
    1.93  
    1.94 @@ -1361,7 +1375,6 @@
    1.95              } else {
    1.96                  SDL_gamecontrollers = gamecontroller->next;
    1.97              }
    1.98 -
    1.99              break;
   1.100          }
   1.101          gamecontrollerlistprev = gamecontrollerlist;
   1.102 @@ -1369,6 +1382,8 @@
   1.103      }
   1.104  
   1.105      SDL_free(gamecontroller);
   1.106 +
   1.107 +    SDL_UnlockJoystickList();
   1.108  }
   1.109  
   1.110  
   1.111 @@ -1379,10 +1394,13 @@
   1.112  SDL_GameControllerQuit(void)
   1.113  {
   1.114      ControllerMapping_t *pControllerMap;
   1.115 +
   1.116 +    SDL_LockJoystickList();
   1.117      while (SDL_gamecontrollers) {
   1.118          SDL_gamecontrollers->ref_count = 1;
   1.119          SDL_GameControllerClose(SDL_gamecontrollers);
   1.120      }
   1.121 +    SDL_UnlockJoystickList();
   1.122  
   1.123      while (s_pSupportedControllers) {
   1.124          pControllerMap = s_pSupportedControllers;
     2.1 --- a/src/joystick/SDL_joystick.c	Wed Dec 07 11:41:20 2016 -0800
     2.2 +++ b/src/joystick/SDL_joystick.c	Thu Dec 08 10:13:45 2016 -0800
     2.3 @@ -37,16 +37,16 @@
     2.4  static SDL_Joystick *SDL_updating_joystick = NULL;
     2.5  static SDL_mutex *SDL_joystick_lock = NULL; /* This needs to support recursive locks */
     2.6  
     2.7 -static void
     2.8 -SDL_LockJoystickList()
     2.9 +void
    2.10 +SDL_LockJoystickList(void)
    2.11  {
    2.12      if (SDL_joystick_lock) {
    2.13          SDL_LockMutex(SDL_joystick_lock);
    2.14      }
    2.15  }
    2.16  
    2.17 -static void
    2.18 -SDL_UnlockJoystickList()
    2.19 +void
    2.20 +SDL_UnlockJoystickList(void)
    2.21  {
    2.22      if (SDL_joystick_lock) {
    2.23          SDL_UnlockMutex(SDL_joystick_lock);
    2.24 @@ -216,9 +216,9 @@
    2.25      joystick->next = SDL_joysticks;
    2.26      SDL_joysticks = joystick;
    2.27  
    2.28 -    SDL_SYS_JoystickUpdate(joystick);
    2.29 +    SDL_UnlockJoystickList();
    2.30  
    2.31 -    SDL_UnlockJoystickList();
    2.32 +    SDL_SYS_JoystickUpdate(joystick);
    2.33  
    2.34      return (joystick);
    2.35  }
    2.36 @@ -787,6 +787,12 @@
    2.37  
    2.38      SDL_LockJoystickList();
    2.39  
    2.40 +    if (SDL_updating_joystick) {
    2.41 +        /* The joysticks are already being updated */
    2.42 +        SDL_UnlockJoystickList();
    2.43 +        return;
    2.44 +    }
    2.45 +
    2.46      for (joystick = SDL_joysticks; joystick; joystick = joysticknext) {
    2.47          /* save off the next pointer, the Update call may cause a joystick removed event
    2.48           * and cause our joystick pointer to be freed
    2.49 @@ -795,6 +801,9 @@
    2.50  
    2.51          SDL_updating_joystick = joystick;
    2.52  
    2.53 +        /* Make sure the list is unlocked while dispatching events to prevent application deadlocks */
    2.54 +        SDL_UnlockJoystickList();
    2.55 +
    2.56          SDL_SYS_JoystickUpdate(joystick);
    2.57  
    2.58          if (joystick->force_recentering) {
    2.59 @@ -816,6 +825,8 @@
    2.60              joystick->force_recentering = SDL_FALSE;
    2.61          }
    2.62  
    2.63 +        SDL_LockJoystickList();
    2.64 +
    2.65          SDL_updating_joystick = NULL;
    2.66  
    2.67          /* If the joystick was closed while updating, free it here */
     3.1 --- a/src/joystick/SDL_joystick_c.h	Wed Dec 07 11:41:20 2016 -0800
     3.2 +++ b/src/joystick/SDL_joystick_c.h	Thu Dec 08 10:13:45 2016 -0800
     3.3 @@ -31,6 +31,9 @@
     3.4  extern int SDL_GameControllerInit(void);
     3.5  extern void SDL_GameControllerQuit(void);
     3.6  
     3.7 +/* Locking for multi-threaded access to the joystick API */
     3.8 +extern void SDL_LockJoystickList(void);
     3.9 +extern void SDL_UnlockJoystickList(void);
    3.10  
    3.11  /* Internal event queueing functions */
    3.12  extern void SDL_PrivateJoystickAdded(int device_index);