Fix rare stream deadlock on Windows

This commit is contained in:
erorcun 2021-02-16 17:11:12 +03:00
parent 179b11151e
commit 49fd99119d

View File

@ -14,9 +14,9 @@ struct CdReadInfo
void *pBuffer; void *pBuffer;
char field_C; char field_C;
bool bLocked; bool bLocked;
bool bInUse; bool bReading;
int32 nStatus; int32 nStatus;
HANDLE hSemaphore; // used for CdStreamSync HANDLE pDoneSemaphore; // used for CdStreamSync
HANDLE hFile; HANDLE hFile;
OVERLAPPED Overlapped; OVERLAPPED Overlapped;
}; };
@ -53,9 +53,9 @@ CdStreamInitThread(void)
{ {
for ( int32 i = 0; i < gNumChannels; i++ ) for ( int32 i = 0; i < gNumChannels; i++ )
{ {
gpReadInfo[i].hSemaphore = CreateSemaphore(nil, 0, 2, nil); gpReadInfo[i].pDoneSemaphore = CreateSemaphore(nil, 0, 2, nil);
if ( gpReadInfo[i].hSemaphore == nil ) if ( gpReadInfo[i].pDoneSemaphore == nil )
{ {
printf("%s: failed to create sync semaphore\n", "cdvd_stream"); printf("%s: failed to create sync semaphore\n", "cdvd_stream");
ASSERT(0); ASSERT(0);
@ -183,7 +183,7 @@ CdStreamShutdown(void)
CloseHandle(_gCdStreamThread); CloseHandle(_gCdStreamThread);
for ( int32 i = 0; i < gNumChannels; i++ ) for ( int32 i = 0; i < gNumChannels; i++ )
CloseHandle(gpReadInfo[i].hSemaphore); CloseHandle(gpReadInfo[i].pDoneSemaphore);
} }
LocalFree(gpReadInfo); LocalFree(gpReadInfo);
@ -213,7 +213,7 @@ CdStreamRead(int32 channel, void *buffer, uint32 offset, uint32 size)
if ( _gbCdStreamAsync ) if ( _gbCdStreamAsync )
{ {
if ( pChannel->nSectorsToRead != 0 || pChannel->bInUse ) if ( pChannel->nSectorsToRead != 0 || pChannel->bReading )
return STREAM_NONE; return STREAM_NONE;
pChannel->nStatus = STREAM_NONE; pChannel->nStatus = STREAM_NONE;
@ -271,7 +271,7 @@ CdStreamGetStatus(int32 channel)
if ( _gbCdStreamAsync ) if ( _gbCdStreamAsync )
{ {
if ( pChannel->bInUse ) if ( pChannel->bReading )
return STREAM_READING; return STREAM_READING;
if ( pChannel->nSectorsToRead != 0 ) if ( pChannel->nSectorsToRead != 0 )
@ -321,12 +321,21 @@ CdStreamSync(int32 channel)
{ {
pChannel->bLocked = true; pChannel->bLocked = true;
ASSERT( pChannel->hSemaphore != nil ); ASSERT( pChannel->pDoneSemaphore != nil );
WaitForSingleObject(pChannel->hSemaphore, INFINITE); // Deadlock fix 1
#ifdef FIX_BUGS
// This is while loop on Posix streamer, for spurious wakeups
if (pChannel->bLocked && pChannel->nSectorsToRead != 0){
WaitForSingleObject(pChannel->pDoneSemaphore, INFINITE);
}
pChannel->bLocked = false;
#else
WaitForSingleObject(pChannel->pDoneSemaphore, INFINITE);
#endif
} }
pChannel->bInUse = false; pChannel->bReading = false;
return pChannel->nStatus; return pChannel->nStatus;
} }
@ -398,7 +407,7 @@ WINAPI CdStreamThread(LPVOID lpThreadParameter)
CdReadInfo *pChannel = &gpReadInfo[channel]; CdReadInfo *pChannel = &gpReadInfo[channel];
ASSERT( pChannel != nil ); ASSERT( pChannel != nil );
pChannel->bInUse = true; pChannel->bReading = true;
if ( pChannel->nStatus == STREAM_NONE ) if ( pChannel->nStatus == STREAM_NONE )
{ {
@ -455,11 +464,15 @@ WINAPI CdStreamThread(LPVOID lpThreadParameter)
if ( pChannel->bLocked ) if ( pChannel->bLocked )
{ {
ASSERT( pChannel->hSemaphore != nil ); ASSERT( pChannel->pDoneSemaphore != nil );
ReleaseSemaphore(pChannel->hSemaphore, 1, NULL); // Deadlock fix 2
#ifdef FIX_BUGS
pChannel->bLocked = 0;
#endif
ReleaseSemaphore(pChannel->pDoneSemaphore, 1, NULL);
} }
pChannel->bInUse = false; pChannel->bReading = false;
} }
} }