diff options
author | Chris Robinson <[email protected]> | 2012-01-20 03:02:21 -0800 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2012-01-20 03:02:21 -0800 |
commit | 47c8c15878fbe66f8c3f20588c807388f53dd847 (patch) | |
tree | 5cba7c025ab1e6b38c3ce711eed2de95350b92c3 | |
parent | fa364352905d4e0ea012bace40872c84daabc8e2 (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.c | 44 |
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); |