By default SDL will only enumerate controllers, to reduce risk of hanging or crashing on devices with bad drivers and avoiding macOS keyboard capture permission prompts.
The hidapi method of storing the error on the device is not thread-safe, and not only could it result in a double free if multiple threads were setting the error at the same time, but SDL could be trying to use the error message and have it be freed out from under it by another thread.
Use SDL's error functions since they already use thread-local storage.
This reverts commit 2b386b6c80.
This isn't the right approach. Even if the string itself isn't double-freed, it can be returned to the application and then freed while the application is trying to use it. This really needs to be in thread-local storage to be completely safe.
In SDL we already have a global thread-local error string, so I'm going to make an SDL-specific change to handle the error strings safely.
The error string is not protected by a mutex, and can be set from multiple threads at the same time. Without this change, it can be double-freed. It can still be double-allocated, leading to a memory leak, but at least it won't crash now.
Signed-off-by: Sam Lantinga <slouken@libsdl.org>
They can vanish for UP TO EIGHT SECONDS...!
This is for devices that connect to HDMI/DisplayPort/etc, where it
presumably has to wait for a display to get up and running before it
can play audio through it, so one can see the audio device fail when
changing display modes, or the system returning from sleep. Since this
can be triggered by a game changing video resolutions at startup (either
before or after opening the audio device!), it's important to deal with.
In normal conditions, it shouldn't take this long to open or recover an
audio device, but this is better than unexpectedly losing the device
in this situation.
Fixes#7044.
Fixes#5571.
(cherry picked from commit 48e71ae87be425f117dece3735b148fbc5f2606e)
This is unsafe because the event is auto-reset, therefore the call to
WaitForSingleObject() resets the event which GetOverlappedResult() will
try to wait on.
Even though the overlapped operation is guaranteed to be completed at
the point we call GetOverlappedResult(), it will still wait on the event
handle for a short time to trigger the reset for auto-reset events. This
amounts to roughly a 100 ms sleep each time GetOverlappedResult() is called
for a completed I/O with a non-signalled event.
In the context of HIDAPI, this extra sleep means that callers that loop
on hid_read_timeout() with timeout=0 will loop forever, since the 100 ms
sleep each iteration ensures ReadFile() will always have new data.
Signed-off-by: Cameron Gutman <aicommander@gmail.com>
Signed-off-by: Sam Lantinga <slouken@libsdl.org>
- hidapi already called CancelIo on hid_close but that only cancels pending IO for the current thread. Controller read/writes originate from multiple threads (serialized, but on a different thread nonetheless) but device destruction was always done on the main device thread which left any pending overlapped reads still running after hidapi's internal read buffer is deallocated leading to intermittent free list corruption.
Signed-off-by: Sam Lantinga <slouken@libsdl.org>
Touching HID devices with keyboard usages will trigger a keyboard capture
permission prompt on macOS 11+. See #4887
Like the IOKit joystick backend, we accept HID devices that have joystick,
gamepad, or multi-axis controller usages. We also allow the Valve VID for
the Steam Controller, just like the Windows HIDAPI implementation does.
Signed-off-by: Cameron Gutman <aicommander@gmail.com>
Signed-off-by: Sam Lantinga <slouken@libsdl.org>
The get_usb_string call is rather expensive on some USB devices, so we
cache the vendor/product strings for future lookups (e.g. when
hid_enumerate is invoked again later).
This way, we only need to ask libusb for strings for devices we haven't
seen since before we started.
Signed-off-by: Steven Noonan <steven@valvesoftware.com>
Signed-off-by: Sam Lantinga <slouken@libsdl.org>