Commit 7d2108ce819c82e516199994302b6e3814f02af4

Ryan C. Gordon 2016-10-07T19:39:43

audio: Backed out the audio-thread detaching changes. It added a ton of complexity. A simpler solution might arise at some point though.

diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c
index 08b801e..460852d 100644
--- a/src/audio/SDL_audio.c
+++ b/src/audio/SDL_audio.c
@@ -708,38 +708,6 @@ SDL_ClearQueuedAudio(SDL_AudioDeviceID devid)
     free_audio_queue(packet);
 }
 
-void
-SDL_FinalizeAudioDevice(SDL_AudioDevice *device)
-{
-    if (!device) {
-        return;
-    }
-
-    SDL_AtomicSet(&device->shutdown, 1);  /* just in case. */
-    SDL_AtomicSet(&device->enabled, 0);
-
-    /* lock/unlock here so we don't race if the audio thread saw the shutdown
-       var without locking, and the thread that requested shutdown is now
-       trying to unlock the mutex while we destroy it. Threading is hard. */
-    current_audio.impl.LockDevice(device);
-    current_audio.impl.UnlockDevice(device);
-
-    if (device->mixer_lock != NULL) {
-        SDL_DestroyMutex(device->mixer_lock);
-    }
-    SDL_free(device->fake_stream);
-    if (device->convert.needed) {
-        SDL_free(device->convert.buf);
-    }
-    if (device->hidden != NULL) {
-        current_audio.impl.CloseDevice(device);
-    }
-
-    free_audio_queue(device->buffer_queue_head);
-    free_audio_queue(device->buffer_queue_pool);
-
-    SDL_free(device);
-}
 
 /* The general mixing thread function */
 static int SDLCALL
@@ -819,8 +787,6 @@ SDL_RunAudio(void *devicep)
     /* Wait for the audio to drain. */
     SDL_Delay(((device->spec.samples * 1000) / device->spec.freq) * 2);
 
-    SDL_FinalizeAudioDevice(device);
-
     return 0;
 }
 
@@ -902,8 +868,6 @@ SDL_CaptureAudio(void *devicep)
 
     current_audio.impl.FlushCapture(device);
 
-    SDL_FinalizeAudioDevice(device);
-
     return 0;
 }
 
@@ -1118,19 +1082,6 @@ close_audio_device(SDL_AudioDevice * device)
         return;
     }
 
-    /* It's possible the audio device can hang at the OS level for
-       several reasons (buggy drivers, etc), so if we've got a thread in
-       flight, we mark the device as ready to shutdown and return
-       immediately. The thread will either notice this and clean everything
-       up when it can, or it's frozen and helpless, but since we've already
-       detached the thread, it's none of our concern. Otherwise, we might
-       hang too. */
-
-    /* Note this can still hang if we initialized the device but failed
-       to finish setting up, forcing _this_ thread to do the cleanup, but
-       oh well. */
-
-    /* take it out of our open list now, though, even if device hangs. */
     if (device->id > 0) {
         SDL_AudioDevice *opendev = open_devices[device->id - 1];
         SDL_assert((opendev == device) || (opendev == NULL));
@@ -1139,43 +1090,26 @@ close_audio_device(SDL_AudioDevice * device)
         }
     }
 
-    if (!current_audio.impl.ProvidesOwnCallbackThread && !device->thread) {
-        /* no thread...maybe we're cleaning up a half-opened failure. */
-        SDL_FinalizeAudioDevice(device); /* do it ourselves. */
-    } else if (current_audio.impl.ProvidesOwnCallbackThread) {
-        /* !!! FIXME: this is sort of a mess, because we _should_ treat this
-           !!! FIXME:  the same as our internal threads, but those targets
-           !!! FIXME:  need refactoring first: they need to call
-           !!! FIXME:  SDL_FinalizeAudioDevice() themselves and also have
-           !!! FIXME:  their CloseDevice() code deal with cleaning up
-           !!! FIXME:  half-initialized opens _and_ normal runs. So for now,
-           !!! FIXME:  nothing to do here but pray this doesn't hang.
-           !!! FIXME:  (the TODO list: coreaudio, emscripten, nacl, haiku) */
-        SDL_FinalizeAudioDevice(device);
-    } else {
-        Uint32 delay = 0;
-
-        if (!device->iscapture) {
-            const SDL_AudioSpec *spec = &device->spec;
-            delay = ((spec->samples * 1000) / spec->freq) * 2;
-        }
-
-        /* Lock to make sure an audio callback doesn't fire after we return.
-           Presumably, if a device hangs, it'll not be holding this mutex,
-           since it should only be held during the app's audio callback. */
-        current_audio.impl.LockDevice(device);
-        SDL_AtomicSet(&device->shutdown, 1);  /* let the thread do it. */
-        SDL_AtomicSet(&device->enabled, 0);
-        current_audio.impl.UnlockDevice(device);
+    SDL_AtomicSet(&device->shutdown, 1);
+    SDL_AtomicSet(&device->enabled, 0);
+    if (device->thread != NULL) {
+        SDL_WaitThread(device->thread, NULL);
+    }
+    if (device->mixer_lock != NULL) {
+        SDL_DestroyMutex(device->mixer_lock);
+    }
+    SDL_free(device->fake_stream);
+    if (device->convert.needed) {
+        SDL_free(device->convert.buf);
+    }
+    if (device->hidden != NULL) {
+        current_audio.impl.CloseDevice(device);
+    }
 
-        /* device is no longer safe to touch at this point. */
+    free_audio_queue(device->buffer_queue_head);
+    free_audio_queue(device->buffer_queue_pool);
 
-        if (delay > 0) {
-            /* Block the amount that is roughly pending for playback, so we
-               don't drop audio if the process exits right after this call. */
-            SDL_Delay(delay);
-        }
-    }
+    SDL_free(device);
 }
 
 
@@ -1494,9 +1428,6 @@ open_audio_device(const char *devname, int iscapture,
             SDL_SetError("Couldn't create audio thread");
             return 0;
         }
-
-        /* don't ever join on this thread; it will clean itself up. */
-        SDL_DetachThread(device->thread);
     }
 
     return device->id;