@@ -78,6 +78,53 @@ extern "C"
7878};
7979
8080
81+ void __stdcall CdStreamShutdownSync_Stub ( CdStream* stream, size_t idx )
82+ {
83+ streaming->cdStreamSyncFuncs .Shutdown ( &stream[idx] );
84+ }
85+
86+ uint32_t CdStreamSync ( int32_t streamID )
87+ {
88+ static bool bInitFields = false ;
89+ static CdStream** ppStreams;
90+ static BOOL* streamingInitialized;
91+ static BOOL* overlappedIO;
92+
93+ if ( !bInitFields )
94+ {
95+ if ( gvm.IsSA () )
96+ {
97+ auto & cdinfo = *memory_pointer (0x8E3FE0 ).get <CdStreamInfoSA>();
98+ ppStreams = &cdinfo.pStreams ;
99+ streamingInitialized = &cdinfo.streamingInitialized ;
100+ overlappedIO = &cdinfo.overlappedIO ;
101+ }
102+ else if ( gvm.IsVC () || gvm.IsIII () )
103+ {
104+ ppStreams = memory_pointer (xVc (0x6F76FC )).get <CdStream*>();
105+ streamingInitialized = memory_pointer (xVc (0x6F7718 )).get <BOOL>();
106+ overlappedIO = memory_pointer (xVc (0x6F7714 )).get <BOOL>();
107+ }
108+
109+ bInitFields = true ;
110+ }
111+
112+ CdStream* stream = &((*ppStreams)[streamID]);
113+ if ( *streamingInitialized )
114+ {
115+ scoped_lock lock ( streaming->cdStreamSyncLock );
116+ streaming->cdStreamSyncFuncs .SleepCS ( stream, &streaming->cdStreamSyncLock );
117+ stream->bInUse = 0 ;
118+ return stream->status ;
119+ }
120+
121+ if ( *overlappedIO && stream->hFile != nullptr )
122+ {
123+ DWORD numBytesRead;
124+ return GetOverlappedResult ( stream->hFile , &stream->overlapped , &numBytesRead, TRUE ) != 0 ? 0 : 254 ;
125+ }
126+ return 0 ;
127+ }
81128
82129/*
83130 * Streaming thread
@@ -92,7 +139,7 @@ int __stdcall CdStreamThread()
92139 // Get reference to the addresses we'll use.
93140 if (gvm.IsSA ())
94141 {
95- auto & cdinfo = *memory_pointer (0x8E3FEC ).get <CdStreamInfoSA>();
142+ auto & cdinfo = *memory_pointer (0x8E3FE0 ).get <CdStreamInfoSA>();
96143 pSemaphore = &cdinfo.semaphore ;
97144 pQueue = &cdinfo.queue ;
98145 ppStreams = &cdinfo.pStreams ;
@@ -192,9 +239,14 @@ int __stdcall CdStreamThread()
192239
193240 // Cleanup
194241 if (bIsAbstract) streaming->CloseModel (sfile);
195- cd->nSectorsToRead = 0 ;
196- if (cd->bLocked ) ReleaseSemaphore (cd->semaphore , 1 , 0 );
197- cd->bInUse = false ;
242+ {
243+ // This critical section fixes a deadlock with CdStreamThread present in original code
244+ scoped_lock xlock (streaming->cdStreamSyncLock );
245+
246+ cd->nSectorsToRead = 0 ;
247+ streaming->cdStreamSyncFuncs .Wake (cd);
248+ cd->bInUse = false ;
249+ }
198250 }
199251 return 0 ;
200252}
@@ -442,6 +494,36 @@ void CAbstractStreaming::Patch()
442494 // Making our our code for the stream thread would make things so much better
443495 MakeJMP (0x406560 , raw_ptr (CdStreamThread));
444496
497+ // These are required so we can fix CdStream race condition
498+ MakeJMP ( 0x406460 , raw_ptr (CdStreamSync) );
499+ if ( gvm.IsSA () )
500+ {
501+ const uint8_t mem[] = { 0xFF , 0x15 };
502+ WriteMemoryRaw ( 0x406910 , mem, sizeof (mem), true );
503+ WriteMemory ( 0x406910 + 2 , &streaming->cdStreamSyncFuncs .Initialize , true );
504+ MakeNOP ( 0x406910 + 6 , 4 );
505+ MakeNOP ( 0x406910 + 0x16 , 2 );
506+ }
507+ else if ( gvm.IsVC () || gvm.IsIII () )
508+ {
509+ MakeNOP ( xVc (0x4088F7 ), 8 );
510+ WriteMemory ( xVc (0x4088F7 ) + 10 , &streaming->cdStreamSyncFuncs .Initialize , true );
511+ WriteMemory ( xVc (0x408919 ), uint8_t (0xEB ), true );
512+ }
513+
514+ if ( gvm.IsSA () )
515+ {
516+ const uint8_t mem[] = { 0x56 , 0x50 };
517+ WriteMemoryRaw ( 0x4063B5 , mem, sizeof (mem), true );
518+ MakeCALL ( 0x4063B5 + 2 , raw_ptr (CdStreamShutdownSync_Stub), true );
519+ }
520+ else if ( gvm.IsVC () || gvm.IsIII () )
521+ {
522+ const uint8_t mem[] = { 0x8D , 0x04 , 0x29 , 0x90 };
523+ WriteMemoryRaw ( xVc (0x4086B6 ), mem, sizeof (mem), true );
524+ WriteMemory ( xVc (0x4086B6 ) + 5 + 2 , &streaming->cdStreamSyncFuncs .Shutdown , true );
525+ }
526+
445527 // We need to know the next model to be read before the CdStreamRead call happens
446528 if (gvm.IsSA ())
447529 {
@@ -731,3 +813,12 @@ void CAbstractStreaming::Patch()
731813 }
732814}
733815
816+ /*
817+ * Export for SilentPatch so it knows that this ML version patches the race condition
818+ */
819+ extern " C" __declspec(dllexport)
820+ uint32_t CdStreamRaceConditionAware ()
821+ {
822+ return 1 ;
823+ }
824+
0 commit comments