aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2012-01-20 03:02:21 -0800
committerChris Robinson <[email protected]>2012-01-20 03:02:21 -0800
commit47c8c15878fbe66f8c3f20588c807388f53dd847 (patch)
tree5cba7c025ab1e6b38c3ce711eed2de95350b92c3
parentfa364352905d4e0ea012bace40872c84daabc8e2 (diff)
Fix a possible race condition when shutting down WinMM devices
If the processing threads are interrupted between the shutdown check and re- adding the buffer back to the device, the device can be left with a buffer that will get unprepared and freed while in use.
-rw-r--r--Alc/backends/winmm.c44
1 files changed, 21 insertions, 23 deletions
diff --git a/Alc/backends/winmm.c b/Alc/backends/winmm.c
index 265dfc83..4b5941b1 100644
--- a/Alc/backends/winmm.c
+++ b/Alc/backends/winmm.c
@@ -42,7 +42,7 @@ typedef struct {
HANDLE hWaveThreadEvent;
HANDLE hWaveThread;
DWORD ulWaveThreadID;
- LONG lWaveBuffersCommitted;
+ volatile LONG lWaveBuffersCommitted;
WAVEHDR WaveBuffer[4];
union {
@@ -162,20 +162,11 @@ static void CALLBACK WaveOutProc(HWAVEOUT hDevice,UINT uMsg,DWORD_PTR dwInstance
// Decrement number of buffers in use
InterlockedDecrement(&pData->lWaveBuffersCommitted);
-
if(pData->bWaveShutdown == AL_FALSE)
{
// Notify Wave Processor Thread that a Wave Header has returned
PostThreadMessage(pData->ulWaveThreadID, uMsg, 0, dwParam1);
}
- else
- {
- if(pData->lWaveBuffersCommitted == 0)
- {
- // Post 'Quit' Message to WaveOut Processor Thread
- PostThreadMessage(pData->ulWaveThreadID, WM_QUIT, 0, 0);
- }
- }
}
/*
@@ -198,9 +189,16 @@ static DWORD WINAPI PlaybackThreadProc(LPVOID lpParameter)
while(GetMessage(&msg, NULL, 0, 0))
{
- if(msg.message != WOM_DONE || pData->bWaveShutdown)
+ if(msg.message != WOM_DONE)
continue;
+ if(pData->bWaveShutdown)
+ {
+ if(pData->lWaveBuffersCommitted == 0)
+ break;
+ continue;
+ }
+
pWaveHdr = ((LPWAVEHDR)msg.lParam);
aluMixData(pDevice, pWaveHdr->lpData, pWaveHdr->dwBufferLength/FrameSize);
@@ -238,20 +236,11 @@ static void CALLBACK WaveInProc(HWAVEIN hDevice,UINT uMsg,DWORD_PTR dwInstance,D
// Decrement number of buffers in use
InterlockedDecrement(&pData->lWaveBuffersCommitted);
-
if(pData->bWaveShutdown == AL_FALSE)
{
// Notify Wave Processor Thread that a Wave Header has returned
PostThreadMessage(pData->ulWaveThreadID,uMsg,0,dwParam1);
}
- else
- {
- if(pData->lWaveBuffersCommitted == 0)
- {
- // Post 'Quit' Message to WaveIn Processor Thread
- PostThreadMessage(pData->ulWaveThreadID,WM_QUIT,0,0);
- }
- }
}
/*
@@ -272,9 +261,16 @@ static DWORD WINAPI CaptureThreadProc(LPVOID lpParameter)
while(GetMessage(&msg, NULL, 0, 0))
{
- if(msg.message != WIM_DATA || pData->bWaveShutdown)
+ if(msg.message != WIM_DATA)
continue;
+ if(pData->bWaveShutdown)
+ {
+ if(pData->lWaveBuffersCommitted == 0)
+ break;
+ continue;
+ }
+
pWaveHdr = ((LPWAVEHDR)msg.lParam);
WriteRingBuffer(pData->pRing, (ALubyte*)pWaveHdr->lpData,
@@ -638,9 +634,11 @@ static void WinMMCloseCapture(ALCdevice *pDevice)
void *buffer = NULL;
int i;
- // Call waveOutReset to shutdown wave device
+ /* Unintuitively.. call waveInStart to make sure WinMM keeps processing
+ * buffers so the processing thread can drop them and exit when it reaches
+ * 0. */
pData->bWaveShutdown = AL_TRUE;
- waveInReset(pData->hWaveHandle.In);
+ waveInStart(pData->hWaveHandle.In);
// Wait for signal that Wave Thread has been destroyed
WaitForSingleObjectEx(pData->hWaveThreadEvent, 5000, FALSE);