# HG changeset patch # User David Ludwig # Date 1584480864 14400 # Tue Mar 17 17:34:24 2020 -0400 # Node ID ffccf76152a26f495a68b4408bea6a154acf22fe # Parent b1ebbd8cafef27a9c26beb51f9bcd7ee38f51d58 Fix for Bug 5034 - Replugging in a controller crashes on macOS in SDL 2.0.12 This is a multi-part fix, and is the 2nd attempt at a fix for Bug 5034. Here are the problems being addressed: 1. On macOS 10.14.x and earlier, trying to call IOHIDDeviceUnscheduleFromRunLoop without a prior, paired call to IOHIDDeviceScheduleWithRunLoop, appears to lead to a crash. A per-device flag has been added to make sure that these calls are paired. 2. DARWIN_JoystickDetect was free'ing its SDL_joystick's hwdata field (via FreeDevice) without setting it to NULL, and DARWIN_JoystickRumble wasn't checking for a NULL hwdata. FreeDevice will now set hwdata to NULL and DARWIN_JoystickRumble will check for a NULL hwdata. diff -r b1ebbd8cafef -r ffccf76152a2 src/joystick/darwin/SDL_sysjoystick.c --- a/src/joystick/darwin/SDL_sysjoystick.c Tue Mar 17 15:47:30 2020 +0100 +++ b/src/joystick/darwin/SDL_sysjoystick.c Tue Mar 17 17:34:24 2020 -0400 @@ -127,11 +127,28 @@ recDevice *pDeviceNext = NULL; if (removeDevice) { if (removeDevice->deviceRef) { - IOHIDDeviceUnscheduleFromRunLoop(removeDevice->deviceRef, CFRunLoopGetCurrent(), SDL_JOYSTICK_RUNLOOP_MODE); + if (removeDevice->runLoopAttached) { + /* Calling IOHIDDeviceUnscheduleFromRunLoop without a prior, + * paired call to IOHIDDeviceScheduleWithRunLoop can lead + * to crashes in MacOS 10.14.x and earlier. This doesn't + * appear to be a problem in MacOS 10.15.x, but we'll + * do it anyways. (Part-of fix for Bug 5034) + */ + IOHIDDeviceUnscheduleFromRunLoop(removeDevice->deviceRef, CFRunLoopGetCurrent(), SDL_JOYSTICK_RUNLOOP_MODE); + } CFRelease(removeDevice->deviceRef); removeDevice->deviceRef = NULL; } + /* clear out any reference to removeDevice from an associated, + * live instance of SDL_Joystick (Part-of fix for Bug 5034) + */ + SDL_LockJoysticks(); + if (removeDevice->joystick) { + removeDevice->joystick->hwdata = NULL; + } + SDL_UnlockJoysticks(); + /* save next device prior to disposing of this device */ pDeviceNext = removeDevice->pNext; @@ -398,6 +415,7 @@ } } + static SDL_bool GetDeviceInfo(IOHIDDeviceRef hidDevice, recDevice *pDevice) { @@ -552,6 +570,7 @@ /* Get notified when this device is disconnected. */ IOHIDDeviceRegisterRemovalCallback(ioHIDDeviceObject, JoystickDeviceWasRemovedCallback, device); IOHIDDeviceScheduleWithRunLoop(ioHIDDeviceObject, CFRunLoopGetCurrent(), SDL_JOYSTICK_RUNLOOP_MODE); + device->runLoopAttached = SDL_TRUE; /* Allocate an instance ID for this device */ device->instance_id = SDL_GetNextJoystickInstanceID(); @@ -760,6 +779,7 @@ joystick->instance_id = device->instance_id; joystick->hwdata = device; + device->joystick = joystick; joystick->name = device->product; joystick->naxes = device->axes; @@ -870,6 +890,10 @@ /* Scale and average the two rumble strengths */ Sint16 magnitude = (Sint16)(((low_frequency_rumble / 2) + (high_frequency_rumble / 2)) / 2); + + if (!device) { + return SDL_SetError("Rumble failed, device disconnected"); + } if (!device->ffservice) { return SDL_Unsupported(); @@ -1007,6 +1031,10 @@ static void DARWIN_JoystickClose(SDL_Joystick * joystick) { + recDevice *device = joystick->hwdata; + if (device) { + device->joystick = NULL; + } } static void diff -r b1ebbd8cafef -r ffccf76152a2 src/joystick/darwin/SDL_sysjoystick_c.h --- a/src/joystick/darwin/SDL_sysjoystick_c.h Tue Mar 17 15:47:30 2020 +0100 +++ b/src/joystick/darwin/SDL_sysjoystick_c.h Tue Mar 17 17:34:24 2020 -0400 @@ -66,6 +66,8 @@ recElement *firstHat; SDL_bool removed; + SDL_Joystick *joystick; + SDL_bool runLoopAttached; /* is 'deviceRef' attached to a CFRunLoop? */ int instance_id; SDL_JoystickGUID guid;