winecoreaudio: Avoid a race between closing and opening the waveIn device.

This commit is contained in:
Ken Thomases 2009-04-11 07:18:30 -05:00 committed by Alexandre Julliard
parent 5c4ed3bcce
commit dff10db044
1 changed files with 46 additions and 28 deletions

View File

@ -1983,6 +1983,7 @@ static DWORD widClose(WORD wDevID)
{ {
DWORD ret = MMSYSERR_NOERROR; DWORD ret = MMSYSERR_NOERROR;
WINE_WAVEIN* wwi; WINE_WAVEIN* wwi;
OSStatus err;
TRACE("(%u);\n", wDevID); TRACE("(%u);\n", wDevID);
@ -1994,7 +1995,7 @@ static DWORD widClose(WORD wDevID)
wwi = &WInDev[wDevID]; wwi = &WInDev[wDevID];
OSSpinLockLock(&wwi->lock); OSSpinLockLock(&wwi->lock);
if (wwi->state == WINE_WS_CLOSED) if (wwi->state == WINE_WS_CLOSED || wwi->state == WINE_WS_CLOSING)
{ {
WARN("Device already closed.\n"); WARN("Device already closed.\n");
ret = MMSYSERR_INVALHANDLE; ret = MMSYSERR_INVALHANDLE;
@ -2006,14 +2007,21 @@ static DWORD widClose(WORD wDevID)
} }
else else
{ {
wwi->state = WINE_WS_CLOSED; wwi->state = WINE_WS_CLOSING;
} }
OSSpinLockUnlock(&wwi->lock); OSSpinLockUnlock(&wwi->lock);
if (ret == MMSYSERR_NOERROR) if (ret != MMSYSERR_NOERROR)
{ return ret;
OSStatus err = AudioUnitUninitialize(wwi->audioUnit);
/* Clean up and close the audio unit. This has to be done without
* wwi->lock being held to avoid deadlock. AudioUnitUninitialize will
* grab an internal Core Audio lock while waiting for the device work
* thread to exit. Meanwhile the device work thread may be holding
* that lock and trying to grab the wwi->lock in the callback. */
err = AudioUnitUninitialize(wwi->audioUnit);
if (err) if (err)
{ {
ERR("AudioUnitUninitialize return %c%c%c%c\n", (char) (err >> 24), ERR("AudioUnitUninitialize return %c%c%c%c\n", (char) (err >> 24),
@ -2027,14 +2035,21 @@ static DWORD widClose(WORD wDevID)
ERR("Can't close AudioUnit\n"); ERR("Can't close AudioUnit\n");
} }
OSSpinLockLock(&wwi->lock);
assert(wwi->state == WINE_WS_CLOSING);
/* Dellocate our audio buffers */ /* Dellocate our audio buffers */
widHelper_DestroyAudioBufferList(wwi->bufferList); widHelper_DestroyAudioBufferList(wwi->bufferList);
wwi->bufferList = NULL; wwi->bufferList = NULL;
HeapFree(GetProcessHeap(), 0, wwi->bufferListCopy); HeapFree(GetProcessHeap(), 0, wwi->bufferListCopy);
wwi->bufferListCopy = NULL; wwi->bufferListCopy = NULL;
wwi->audioUnit = NULL;
wwi->state = WINE_WS_CLOSED;
OSSpinLockUnlock(&wwi->lock);
ret = widNotifyClient(wwi, WIM_CLOSE, 0L, 0L); ret = widNotifyClient(wwi, WIM_CLOSE, 0L, 0L);
}
return ret; return ret;
} }
@ -2069,7 +2084,7 @@ static DWORD widAddBuffer(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
wwi = &WInDev[wDevID]; wwi = &WInDev[wDevID];
OSSpinLockLock(&wwi->lock); OSSpinLockLock(&wwi->lock);
if (wwi->state == WINE_WS_CLOSED) if (wwi->state == WINE_WS_CLOSED || wwi->state == WINE_WS_CLOSING)
{ {
WARN("Trying to add buffer to closed device.\n"); WARN("Trying to add buffer to closed device.\n");
ret = MMSYSERR_INVALHANDLE; ret = MMSYSERR_INVALHANDLE;
@ -2121,7 +2136,7 @@ static DWORD widStart(WORD wDevID)
wwi = &WInDev[wDevID]; wwi = &WInDev[wDevID];
OSSpinLockLock(&wwi->lock); OSSpinLockLock(&wwi->lock);
if (wwi->state == WINE_WS_CLOSED) if (wwi->state == WINE_WS_CLOSED || wwi->state == WINE_WS_CLOSING)
{ {
WARN("Trying to start closed device.\n"); WARN("Trying to start closed device.\n");
ret = MMSYSERR_INVALHANDLE; ret = MMSYSERR_INVALHANDLE;
@ -2180,7 +2195,7 @@ static DWORD widStop(WORD wDevID)
OSSpinLockLock(&wwi->lock); OSSpinLockLock(&wwi->lock);
if (wwi->state == WINE_WS_CLOSED) if (wwi->state == WINE_WS_CLOSED || wwi->state == WINE_WS_CLOSING)
{ {
WARN("Trying to stop closed device.\n"); WARN("Trying to stop closed device.\n");
ret = MMSYSERR_INVALHANDLE; ret = MMSYSERR_INVALHANDLE;
@ -2253,7 +2268,7 @@ static DWORD widReset(WORD wDevID)
wwi = &WInDev[wDevID]; wwi = &WInDev[wDevID];
OSSpinLockLock(&wwi->lock); OSSpinLockLock(&wwi->lock);
if (wwi->state == WINE_WS_CLOSED) if (wwi->state == WINE_WS_CLOSED || wwi->state == WINE_WS_CLOSING)
{ {
WARN("Trying to reset a closed device.\n"); WARN("Trying to reset a closed device.\n");
ret = MMSYSERR_INVALHANDLE; ret = MMSYSERR_INVALHANDLE;
@ -2441,6 +2456,9 @@ OSStatus CoreAudio_wiAudioUnitIOProc(void *inRefCon,
lpStorePtr = wwi->lpQueuePtr; lpStorePtr = wwi->lpQueuePtr;
/* We might have been called while the waveIn device is being closed in
* widClose. We have to do nothing in that case. The check of wwi->state
* below ensures that. */
while (dataToStore > 0 && wwi->state == WINE_WS_PLAYING && lpStorePtr) while (dataToStore > 0 && wwi->state == WINE_WS_PLAYING && lpStorePtr)
{ {
unsigned int room = lpStorePtr->dwBufferLength - lpStorePtr->dwBytesRecorded; unsigned int room = lpStorePtr->dwBufferLength - lpStorePtr->dwBytesRecorded;