mirror of
https://github.com/libsdl-org/SDL.git
synced 2025-10-05 09:26:25 +00:00
audio: Handle device disconnects on the main thread.
This avoids situations like: - PulseAudio holds its own lock in the hotplug thread. - The hotplug thread notices a device went away. - The hotplug thread calls SDL_AudioDeviceDisconnected(). - SDL_AudioDeviceDisconnected() tries to grab the device lock. - The device thread is holding the device lock... - ...but is currently waiting on PulseAudio's lock to release. In short: deadlock. It's better to queue this work to run on the main thread, where we can guarantee a start with _none_ of the audio subsystem locks held.
This commit is contained in:
@@ -734,11 +734,10 @@ SDL_AudioDevice *SDL_AddAudioDevice(bool recording, const char *name, const SDL_
|
||||
}
|
||||
|
||||
// Called when a device is removed from the system, or it fails unexpectedly, from any thread, possibly even the audio device's thread.
|
||||
void SDL_AudioDeviceDisconnected(SDL_AudioDevice *device)
|
||||
static void SDLCALL SDL_AudioDeviceDisconnected_OnMainThread(void *userdata)
|
||||
{
|
||||
if (!device) {
|
||||
return;
|
||||
}
|
||||
SDL_AudioDevice *device = (SDL_AudioDevice *) userdata;
|
||||
SDL_assert(device != NULL);
|
||||
|
||||
// Save off removal info in a list so we can send events for each, next
|
||||
// time the event queue pumps, in case something tries to close a device
|
||||
@@ -808,6 +807,23 @@ void SDL_AudioDeviceDisconnected(SDL_AudioDevice *device)
|
||||
|
||||
UnrefPhysicalAudioDevice(device);
|
||||
}
|
||||
|
||||
// We always ref this in SDL_AudioDeviceDisconnected(), so if multiple attempts
|
||||
// to disconnect are queued, the pointer stays valid until the last one comes
|
||||
// through.
|
||||
UnrefPhysicalAudioDevice(device);
|
||||
}
|
||||
|
||||
void SDL_AudioDeviceDisconnected(SDL_AudioDevice *device)
|
||||
{
|
||||
// lots of risk of various audio backends deadlocking because they're calling
|
||||
// this while holding a backend-specific lock, which causes problems when we
|
||||
// want to obtain the device lock while its audio thread is also waiting for
|
||||
// that lock to be released. So just queue the work on the main thread.
|
||||
if (device) {
|
||||
RefPhysicalAudioDevice(device);
|
||||
SDL_RunOnMainThread(SDL_AudioDeviceDisconnected_OnMainThread, device, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user