Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Protect the game controller API the same way the joystick API is prot…
…ected from multi-threaded access
  • Loading branch information
slouken committed Dec 8, 2016
1 parent 1b08f0c commit a525017
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 11 deletions.
28 changes: 23 additions & 5 deletions src/joystick/SDL_gamecontroller.c
Expand Up @@ -25,6 +25,7 @@
#include "SDL_events.h"
#include "SDL_assert.h"
#include "SDL_sysjoystick.h"
#include "SDL_joystick_c.h"
#include "SDL_hints.h"
#include "SDL_gamecontrollerdb.h"

Expand Down Expand Up @@ -1086,12 +1087,15 @@ SDL_GameControllerOpen(int device_index)
return (NULL);
}

SDL_LockJoystickList();

gamecontrollerlist = SDL_gamecontrollers;
/* If the controller is already open, return it */
while (gamecontrollerlist) {
if (SDL_SYS_GetInstanceIdOfDeviceIndex(device_index) == gamecontrollerlist->joystick->instance_id) {
gamecontroller = gamecontrollerlist;
++gamecontroller->ref_count;
SDL_UnlockJoystickList();
return (gamecontroller);
}
gamecontrollerlist = gamecontrollerlist->next;
Expand All @@ -1101,20 +1105,23 @@ SDL_GameControllerOpen(int device_index)
pSupportedController = SDL_PrivateGetControllerMapping(device_index);
if (!pSupportedController) {
SDL_SetError("Couldn't find mapping for device (%d)", device_index);
return (NULL);
SDL_UnlockJoystickList();
return NULL;
}

/* Create and initialize the joystick */
gamecontroller = (SDL_GameController *) SDL_malloc((sizeof *gamecontroller));
if (gamecontroller == NULL) {
SDL_OutOfMemory();
SDL_UnlockJoystickList();
return NULL;
}

SDL_memset(gamecontroller, 0, (sizeof *gamecontroller));
gamecontroller->joystick = SDL_JoystickOpen(device_index);
if (!gamecontroller->joystick) {
SDL_free(gamecontroller);
SDL_UnlockJoystickList();
return NULL;
}

Expand All @@ -1140,7 +1147,7 @@ SDL_GameControllerOpen(int device_index)
gamecontroller->next = SDL_gamecontrollers;
SDL_gamecontrollers = gamecontroller;

SDL_SYS_JoystickUpdate(gamecontroller->joystick);
SDL_UnlockJoystickList();

return (gamecontroller);
}
Expand Down Expand Up @@ -1274,14 +1281,18 @@ SDL_Joystick *SDL_GameControllerGetJoystick(SDL_GameController * gamecontroller)
SDL_GameController *
SDL_GameControllerFromInstanceID(SDL_JoystickID joyid)
{
SDL_GameController *gamecontroller = SDL_gamecontrollers;
SDL_GameController *gamecontroller;

SDL_LockJoystickList();
gamecontroller = SDL_gamecontrollers;
while (gamecontroller) {
if (gamecontroller->joystick->instance_id == joyid) {
SDL_UnlockJoystickList();
return gamecontroller;
}
gamecontroller = gamecontroller->next;
}

SDL_UnlockJoystickList();
return NULL;
}

Expand Down Expand Up @@ -1344,8 +1355,11 @@ SDL_GameControllerClose(SDL_GameController * gamecontroller)
if (!gamecontroller)
return;

SDL_LockJoystickList();

/* First decrement ref count */
if (--gamecontroller->ref_count > 0) {
SDL_UnlockJoystickList();
return;
}

Expand All @@ -1361,14 +1375,15 @@ SDL_GameControllerClose(SDL_GameController * gamecontroller)
} else {
SDL_gamecontrollers = gamecontroller->next;
}

break;
}
gamecontrollerlistprev = gamecontrollerlist;
gamecontrollerlist = gamecontrollerlist->next;
}

SDL_free(gamecontroller);

SDL_UnlockJoystickList();
}


Expand All @@ -1379,10 +1394,13 @@ void
SDL_GameControllerQuit(void)
{
ControllerMapping_t *pControllerMap;

SDL_LockJoystickList();
while (SDL_gamecontrollers) {
SDL_gamecontrollers->ref_count = 1;
SDL_GameControllerClose(SDL_gamecontrollers);
}
SDL_UnlockJoystickList();

while (s_pSupportedControllers) {
pControllerMap = s_pSupportedControllers;
Expand Down
23 changes: 17 additions & 6 deletions src/joystick/SDL_joystick.c
Expand Up @@ -37,16 +37,16 @@ static SDL_Joystick *SDL_joysticks = NULL;
static SDL_Joystick *SDL_updating_joystick = NULL;
static SDL_mutex *SDL_joystick_lock = NULL; /* This needs to support recursive locks */

static void
SDL_LockJoystickList()
void
SDL_LockJoystickList(void)
{
if (SDL_joystick_lock) {
SDL_LockMutex(SDL_joystick_lock);
}
}

static void
SDL_UnlockJoystickList()
void
SDL_UnlockJoystickList(void)
{
if (SDL_joystick_lock) {
SDL_UnlockMutex(SDL_joystick_lock);
Expand Down Expand Up @@ -216,10 +216,10 @@ SDL_JoystickOpen(int device_index)
joystick->next = SDL_joysticks;
SDL_joysticks = joystick;

SDL_SYS_JoystickUpdate(joystick);

SDL_UnlockJoystickList();

SDL_SYS_JoystickUpdate(joystick);

return (joystick);
}

Expand Down Expand Up @@ -787,6 +787,12 @@ SDL_JoystickUpdate(void)

SDL_LockJoystickList();

if (SDL_updating_joystick) {
/* The joysticks are already being updated */
SDL_UnlockJoystickList();
return;
}

for (joystick = SDL_joysticks; joystick; joystick = joysticknext) {
/* save off the next pointer, the Update call may cause a joystick removed event
* and cause our joystick pointer to be freed
Expand All @@ -795,6 +801,9 @@ SDL_JoystickUpdate(void)

SDL_updating_joystick = joystick;

/* Make sure the list is unlocked while dispatching events to prevent application deadlocks */
SDL_UnlockJoystickList();

SDL_SYS_JoystickUpdate(joystick);

if (joystick->force_recentering) {
Expand All @@ -816,6 +825,8 @@ SDL_JoystickUpdate(void)
joystick->force_recentering = SDL_FALSE;
}

SDL_LockJoystickList();

SDL_updating_joystick = NULL;

/* If the joystick was closed while updating, free it here */
Expand Down
3 changes: 3 additions & 0 deletions src/joystick/SDL_joystick_c.h
Expand Up @@ -31,6 +31,9 @@ extern void SDL_JoystickQuit(void);
extern int SDL_GameControllerInit(void);
extern void SDL_GameControllerQuit(void);

/* Locking for multi-threaded access to the joystick API */
extern void SDL_LockJoystickList(void);
extern void SDL_UnlockJoystickList(void);

/* Internal event queueing functions */
extern void SDL_PrivateJoystickAdded(int device_index);
Expand Down

0 comments on commit a525017

Please sign in to comment.