Skip to content

Commit

Permalink
faudio: Fix deadlock in voice callbacks
Browse files Browse the repository at this point in the history
Deadlock was being caused by the fact that some private FAudio routines
hold internal mutexes while calling application callbacks. This may result
in a deadlock because app might have a huge global mutex that is locked
both by callbacks and by some code that e.g. submits new buffers to XAudio.

Should fix https://bugs.winehq.org/show_bug.cgi?id=54246
  • Loading branch information
xtsm authored and flibitijibibo committed Apr 2, 2024
1 parent 1eaf7ad commit a623edb
Showing 1 changed file with 63 additions and 3 deletions.
66 changes: 63 additions & 3 deletions src/FAudio_internal.c
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,12 @@ static void FAudio_INTERNAL_DecodeBuffers(
if ( voice->src.callback != NULL &&
voice->src.callback->OnBufferStart != NULL )
{
FAudio_PlatformUnlockMutex(voice->src.bufferLock);
LOG_MUTEX_UNLOCK(voice->audio, voice->src.bufferLock)

FAudio_PlatformUnlockMutex(voice->sendLock);
LOG_MUTEX_UNLOCK(voice->audio, voice->sendLock)

FAudio_PlatformUnlockMutex(voice->audio->sourceLock);
LOG_MUTEX_UNLOCK(voice->audio, voice->audio->sourceLock)

Expand All @@ -393,6 +399,12 @@ static void FAudio_INTERNAL_DecodeBuffers(

FAudio_PlatformLockMutex(voice->audio->sourceLock);
LOG_MUTEX_LOCK(voice->audio, voice->audio->sourceLock)

FAudio_PlatformLockMutex(voice->sendLock);
LOG_MUTEX_LOCK(voice->audio, voice->sendLock)

FAudio_PlatformLockMutex(voice->src.bufferLock);
LOG_MUTEX_LOCK(voice->audio, voice->src.bufferLock)
}
}

Expand Down Expand Up @@ -442,6 +454,12 @@ static void FAudio_INTERNAL_DecodeBuffers(
if ( voice->src.callback != NULL &&
voice->src.callback->OnLoopEnd != NULL )
{
FAudio_PlatformUnlockMutex(voice->src.bufferLock);
LOG_MUTEX_UNLOCK(voice->audio, voice->src.bufferLock)

FAudio_PlatformUnlockMutex(voice->sendLock);
LOG_MUTEX_UNLOCK(voice->audio, voice->sendLock)

FAudio_PlatformUnlockMutex(voice->audio->sourceLock);
LOG_MUTEX_UNLOCK(voice->audio, voice->audio->sourceLock)

Expand All @@ -452,6 +470,12 @@ static void FAudio_INTERNAL_DecodeBuffers(

FAudio_PlatformLockMutex(voice->audio->sourceLock);
LOG_MUTEX_LOCK(voice->audio, voice->audio->sourceLock)

FAudio_PlatformLockMutex(voice->sendLock);
LOG_MUTEX_LOCK(voice->audio, voice->sendLock)

FAudio_PlatformLockMutex(voice->src.bufferLock);
LOG_MUTEX_LOCK(voice->audio, voice->src.bufferLock)
}
}
else
Expand Down Expand Up @@ -504,6 +528,12 @@ static void FAudio_INTERNAL_DecodeBuffers(
/* Callbacks */
if (voice->src.callback != NULL)
{
FAudio_PlatformUnlockMutex(voice->src.bufferLock);
LOG_MUTEX_UNLOCK(voice->audio, voice->src.bufferLock)

FAudio_PlatformUnlockMutex(voice->sendLock);
LOG_MUTEX_UNLOCK(voice->audio, voice->sendLock)

FAudio_PlatformUnlockMutex(voice->audio->sourceLock);
LOG_MUTEX_UNLOCK(voice->audio, voice->audio->sourceLock)

Expand All @@ -522,6 +552,15 @@ static void FAudio_INTERNAL_DecodeBuffers(
);
}

FAudio_PlatformLockMutex(voice->audio->sourceLock);
LOG_MUTEX_LOCK(voice->audio, voice->audio->sourceLock)

FAudio_PlatformLockMutex(voice->sendLock);
LOG_MUTEX_LOCK(voice->audio, voice->sendLock)

FAudio_PlatformLockMutex(voice->src.bufferLock);
LOG_MUTEX_LOCK(voice->audio, voice->src.bufferLock)

/* One last chance at redemption */
if (buffer == NULL && voice->src.bufferList != NULL)
{
Expand All @@ -531,14 +570,29 @@ static void FAudio_INTERNAL_DecodeBuffers(

if (buffer != NULL && voice->src.callback->OnBufferStart != NULL)
{
FAudio_PlatformUnlockMutex(voice->src.bufferLock);
LOG_MUTEX_UNLOCK(voice->audio, voice->src.bufferLock)

FAudio_PlatformUnlockMutex(voice->sendLock);
LOG_MUTEX_UNLOCK(voice->audio, voice->sendLock)

FAudio_PlatformUnlockMutex(voice->audio->sourceLock);
LOG_MUTEX_UNLOCK(voice->audio, voice->audio->sourceLock)

voice->src.callback->OnBufferStart(
voice->src.callback,
buffer->pContext
);
}

FAudio_PlatformLockMutex(voice->audio->sourceLock);
LOG_MUTEX_LOCK(voice->audio, voice->audio->sourceLock)
FAudio_PlatformLockMutex(voice->audio->sourceLock);
LOG_MUTEX_LOCK(voice->audio, voice->audio->sourceLock)

FAudio_PlatformLockMutex(voice->sendLock);
LOG_MUTEX_LOCK(voice->audio, voice->sendLock)

FAudio_PlatformLockMutex(voice->src.bufferLock);
LOG_MUTEX_LOCK(voice->audio, voice->src.bufferLock)
}
}

voice->audio->pFree(toDelete);
Expand Down Expand Up @@ -1250,6 +1304,9 @@ static void FAudio_INTERNAL_FlushPendingBuffers(FAudioSourceVoice *voice)

if (voice->src.callback != NULL && voice->src.callback->OnBufferEnd != NULL)
{
FAudio_PlatformUnlockMutex(voice->src.bufferLock);
LOG_MUTEX_UNLOCK(voice->audio, voice->src.bufferLock)

FAudio_PlatformUnlockMutex(voice->audio->sourceLock);
LOG_MUTEX_UNLOCK(voice->audio, voice->audio->sourceLock)

Expand All @@ -1260,6 +1317,9 @@ static void FAudio_INTERNAL_FlushPendingBuffers(FAudioSourceVoice *voice)

FAudio_PlatformLockMutex(voice->audio->sourceLock);
LOG_MUTEX_LOCK(voice->audio, voice->audio->sourceLock)

FAudio_PlatformLockMutex(voice->src.bufferLock);
LOG_MUTEX_LOCK(voice->audio, voice->src.bufferLock)
}
voice->audio->pFree(entry);
}
Expand Down

0 comments on commit a623edb

Please sign in to comment.