fix deadlock in SoundSDL::deinit() #139 #130

On SoundSDL destructor and `reset()`, there was a deadlock with Linux
pthreads, it happened sometimes that the reader thread would call
`SDL_SemWait(data_available)` while `deinit()` would destroy the
semaphore and the `SDL_SemWait()` would end up waiting forever on a null
semaphore.

Change the sequencing of deinit() to prevent this from happening, set
`initialized = false` at the beginning of the sequence to prevent
subsequent entries into the reader callback, and add an SDL_Delay(100)
between the final `SDL_SemPost()` and `SDL_UnlockMutex()`s and the
`SDL_DestroySemaphore()` and `SDL_DestroyMutex()`s to allow a running
reader to complete with a valid mutex and semaphores before they are
destroyed and the thread is joined.

Resetting the sound system also sometimes triggers a memory corruption
bug, but that's a separate issue.
This commit is contained in:
Rafael Kitover 2017-09-21 15:39:30 -07:00
parent 3d792457b2
commit e9a86c541d
1 changed files with 8 additions and 5 deletions

View File

@ -51,12 +51,13 @@ std::size_t SoundSDL::buffer_size() {
} }
void SoundSDL::read(uint16_t* stream, int length) { void SoundSDL::read(uint16_t* stream, int length) {
if (!initialized || length <= 0) if (length <= 0)
return; return;
SDL_memset(stream, audio_spec.silence, length); SDL_memset(stream, audio_spec.silence, length);
if (!emulating) // if not initialzed, paused or shutting down, do nothing
if (!initialized || !emulating)
return; return;
if (!buffer_size()) if (!buffer_size())
@ -148,6 +149,8 @@ void SoundSDL::deinit() {
if (!initialized) if (!initialized)
return; return;
initialized = false;
SDL_LockMutex(mutex); SDL_LockMutex(mutex);
int is_emulating = emulating; int is_emulating = emulating;
emulating = 0; emulating = 0;
@ -155,6 +158,8 @@ void SoundSDL::deinit() {
SDL_SemPost(data_read); SDL_SemPost(data_read);
SDL_UnlockMutex(mutex); SDL_UnlockMutex(mutex);
SDL_Delay(100);
SDL_DestroySemaphore(data_available); SDL_DestroySemaphore(data_available);
data_available = nullptr; data_available = nullptr;
SDL_DestroySemaphore(data_read); SDL_DestroySemaphore(data_read);
@ -166,8 +171,6 @@ void SoundSDL::deinit() {
SDL_CloseAudioDevice(sound_device); SDL_CloseAudioDevice(sound_device);
emulating = is_emulating; emulating = is_emulating;
initialized = false;
} }
SoundSDL::~SoundSDL() { SoundSDL::~SoundSDL() {