Fixed rare crash when unplugging Xbox controller on Windows
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
diff --git a/src/joystick/windows/SDL_rawinputjoystick.c b/src/joystick/windows/SDL_rawinputjoystick.c
index fbe9a78..a521a0f 100644
--- a/src/joystick/windows/SDL_rawinputjoystick.c
+++ b/src/joystick/windows/SDL_rawinputjoystick.c
@@ -223,6 +223,22 @@ RAWINPUT_JoystickGetCount(void)
}
static SDL_RAWINPUT_Device *
+RAWINPUT_AcquireDevice(SDL_RAWINPUT_Device *device)
+{
+ SDL_AtomicIncRef(&device->refcount);
+ return device;
+}
+
+static void
+RAWINPUT_ReleaseDevice(SDL_RAWINPUT_Device *device)
+{
+ if (SDL_AtomicDecRef(&device->refcount)) {
+ SDL_free(device->name);
+ SDL_free(device);
+ }
+}
+
+static SDL_RAWINPUT_Device *
RAWINPUT_DeviceFromHandle(HANDLE hDevice)
{
SDL_RAWINPUT_Device *curr;
@@ -360,6 +376,7 @@ RAWINPUT_AddDevice(HANDLE hDevice)
#endif
/* Add it to the list */
+ RAWINPUT_AcquireDevice(device);
for (curr = SDL_RAWINPUT_devices, last = NULL; curr; last = curr, curr = curr->next) {
continue;
}
@@ -391,7 +408,6 @@ RAWINPUT_DelDevice(SDL_RAWINPUT_Device *device, SDL_bool send_event)
SDL_RAWINPUT_Device *curr, *last;
for (curr = SDL_RAWINPUT_devices, last = NULL; curr; last = curr, curr = curr->next) {
if (curr == device) {
- SDL_Joystick *joystick;
if (last) {
last->next = curr->next;
} else {
@@ -399,19 +415,13 @@ RAWINPUT_DelDevice(SDL_RAWINPUT_Device *device, SDL_bool send_event)
}
--SDL_RAWINPUT_numjoysticks;
- joystick = device->joystick;
- if (joystick) {
- /* Detach from joystick */
- RAWINPUT_JoystickClose(joystick);
- }
/* Calls SDL_PrivateJoystickRemoved() */
HIDAPI_JoystickDisconnected(&device->hiddevice, device->joystick_id, SDL_TRUE);
#ifdef DEBUG_RAWINPUT
SDL_Log("Removing RAWINPUT device '%s' VID 0x%.4x, PID 0x%.4x, version %d, handle 0x%.8x\n", device->name, device->vendor_id, device->product_id, device->version, device->hDevice);
#endif
- SDL_free(device->name);
- SDL_free(device);
+ RAWINPUT_ReleaseDevice(device);
return;
}
}
@@ -575,7 +585,6 @@ RAWINPUT_JoystickOpen(SDL_Joystick * joystick, int device_index)
{
SDL_RAWINPUT_Device *device = RAWINPUT_GetJoystickByIndex(device_index, NULL);
struct joystick_hwdata *hwdata = SDL_callocStruct(struct joystick_hwdata);
- SDL_assert(!device->joystick);
if (!hwdata) {
return SDL_OutOfMemory();
@@ -587,7 +596,7 @@ RAWINPUT_JoystickOpen(SDL_Joystick * joystick, int device_index)
}
hwdata->reserved = (void*)-1; /* crash if some code slips by that tries to use this */
- hwdata->device = device;
+ hwdata->device = RAWINPUT_AcquireDevice(device);
device->joystick = joystick;
joystick->hwdata = hwdata;
@@ -630,6 +639,7 @@ RAWINPUT_JoystickClose(SDL_Joystick * joystick)
SDL_assert(device->joystick == joystick);
device->driver->CloseJoystick(&device->hiddevice, joystick);
device->joystick = NULL;
+ RAWINPUT_ReleaseDevice(device);
}
SDL_free(hwdata);