From e51760e11166a81dd4ba504df559b9b16100815c Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Sun, 19 Nov 2023 12:25:13 -0500
Subject: [PATCH] audio: Wait for device thread to set `device->threadid`
before continuing.
This fixes a (likely harmless) race condition in `is_in_audio_device_thread`.
Reference Issue #7427.
---
src/audio/SDL_audio.c | 38 +++++++++++++++++++++++++++++++++-----
1 file changed, 33 insertions(+), 5 deletions(-)
diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c
index 1a864054cebe..b256c7b3ed36 100644
--- a/src/audio/SDL_audio.c
+++ b/src/audio/SDL_audio.c
@@ -31,6 +31,12 @@
#define _THIS SDL_AudioDevice *_this
+typedef struct AudioThreadStartupData
+{
+ SDL_AudioDevice *device;
+ SDL_sem *startup_semaphore;
+} AudioThreadStartupData;
+
static SDL_AudioDriver current_audio;
static SDL_AudioDevice *open_devices[16];
@@ -663,9 +669,10 @@ extern void Android_JNI_AudioSetThreadPriority(int, int);
#endif
/* The general mixing thread function */
-static int SDLCALL SDL_RunAudio(void *devicep)
+static int SDLCALL SDL_RunAudio(void *userdata)
{
- SDL_AudioDevice *device = (SDL_AudioDevice *)devicep;
+ const AudioThreadStartupData *startup_data = (const AudioThreadStartupData *) userdata;
+ SDL_AudioDevice *device = startup_data->device;
void *udata = device->callbackspec.userdata;
SDL_AudioCallback callback = device->callbackspec.callback;
int data_len = 0;
@@ -685,6 +692,9 @@ static int SDLCALL SDL_RunAudio(void *devicep)
/* Perform any thread setup */
device->threadid = SDL_ThreadID();
+
+ SDL_SemPost(startup_data->startup_semaphore); /* SDL_OpenAudioDevice may now continue. */
+
current_audio.impl.ThreadInit(device);
/* Loop, filling the audio buffers */
@@ -761,9 +771,10 @@ static int SDLCALL SDL_RunAudio(void *devicep)
/* !!! FIXME: this needs to deal with device spec changes. */
/* The general capture thread function */
-static int SDLCALL SDL_CaptureAudio(void *devicep)
+static int SDLCALL SDL_CaptureAudio(void *userdata)
{
- SDL_AudioDevice *device = (SDL_AudioDevice *)devicep;
+ const AudioThreadStartupData *startup_data = (const AudioThreadStartupData *) userdata;
+ SDL_AudioDevice *device = startup_data->device;
const int silence = (int)device->spec.silence;
const Uint32 delay = ((device->spec.samples * 1000) / device->spec.freq);
const int data_len = device->spec.size;
@@ -785,6 +796,9 @@ static int SDLCALL SDL_CaptureAudio(void *devicep)
/* Perform any thread setup */
device->threadid = SDL_ThreadID();
+
+ SDL_SemPost(startup_data->startup_semaphore); /* SDL_OpenAudioDevice may now continue. */
+
current_audio.impl.ThreadInit(device);
/* Loop, filling the audio buffers */
@@ -1500,16 +1514,30 @@ static SDL_AudioDeviceID open_audio_device(const char *devname, int iscapture,
if (!current_audio.impl.ProvidesOwnCallbackThread) {
/* Start the audio thread */
char threadname[64];
+ AudioThreadStartupData startup_data;
+
+ startup_data.device = device;
+ startup_data.startup_semaphore = SDL_CreateSemaphore(0);
+ if (!startup_data.startup_semaphore) {
+ close_audio_device(device);
+ SDL_SetError("Couldn't create audio thread startup semaphore");
+ SDL_UnlockMutex(current_audio.detectionLock);
+ return 0;
+ }
(void)SDL_snprintf(threadname, sizeof(threadname), "SDLAudio%c%" SDL_PRIu32, (iscapture) ? 'C' : 'P', device->id);
- device->thread = SDL_CreateThreadInternal(iscapture ? SDL_CaptureAudio : SDL_RunAudio, threadname, 0, device);
+ device->thread = SDL_CreateThreadInternal(iscapture ? SDL_CaptureAudio : SDL_RunAudio, threadname, 0, &startup_data);
if (device->thread == NULL) {
+ SDL_DestroySemaphore(startup_data.startup_semaphore);
close_audio_device(device);
SDL_SetError("Couldn't create audio thread");
SDL_UnlockMutex(current_audio.detectionLock);
return 0;
}
+
+ SDL_SemWait(startup_data.startup_semaphore);
+ SDL_DestroySemaphore(startup_data.startup_semaphore);
}
SDL_UnlockMutex(current_audio.detectionLock);