diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /utils/hlfaceposer/fileloaderthread.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'utils/hlfaceposer/fileloaderthread.cpp')
| -rw-r--r-- | utils/hlfaceposer/fileloaderthread.cpp | 422 |
1 files changed, 422 insertions, 0 deletions
diff --git a/utils/hlfaceposer/fileloaderthread.cpp b/utils/hlfaceposer/fileloaderthread.cpp new file mode 100644 index 0000000..df70e31 --- /dev/null +++ b/utils/hlfaceposer/fileloaderthread.cpp @@ -0,0 +1,422 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// +#include "cbase.h" +#include "sentence.h" +#include "wavefile.h" +#include "tier2/riff.h" +#include "filesystem.h" +#include <io.h> +#include <fcntl.h> +#include <sys/types.h> +#include "IFileLoader.h" + +bool SceneManager_LoadSentenceFromWavFileUsingIO( char const *wavfile, CSentence& sentence, IFileReadBinary& io ); + +//----------------------------------------------------------------------------- +// Purpose: Implements the RIFF i/o interface on stdio +//----------------------------------------------------------------------------- +class ThreadIOReadBinary : public IFileReadBinary +{ +public: + int open( const char *pFileName ) + { + char filename[ 512 ]; + // POSSIBLE BUG: THIS MIGHT NOT BE THREAD SAFE!!! + filesystem->RelativePathToFullPath( pFileName, "GAME", filename, sizeof( filename ) ); + return (int)_open( filename, _O_BINARY | _O_RDONLY ); + } + + int read( void *pOutput, int size, int file ) + { + if ( !file ) + return 0; + + return _read( file, pOutput, size ); + } + + void seek( int file, int pos ) + { + if ( !file ) + return; + + _lseek( file, pos, SEEK_SET ); + } + + unsigned int tell( int file ) + { + if ( !file ) + return 0; + + return _tell( file ); + } + + unsigned int size( int file ) + { + if ( !file ) + return 0; + + long curpos = tell( file ); + _lseek( file, 0, SEEK_END ); + int s = tell( file ); + _lseek( file, curpos, SEEK_SET ); + + return s; + } + + void close( int file ) + { + if ( !file ) + return; + + _close( file ); + } +}; + +//----------------------------------------------------------------------------- +// Purpose: All wavefile I/O occurs on a thread +//----------------------------------------------------------------------------- +class CFileLoaderThread : public IFileLoader +{ +public: + struct SentenceRequest + { + SentenceRequest() + { + filename[ 0 ] = 0; + sentence.Reset(); + wavefile = NULL; + valid = false; + } + + bool valid; + char filename[ 256 ]; + CSentence sentence; + + CWaveFile *wavefile; + }; + + // Construction + CFileLoaderThread( void ); + virtual ~CFileLoaderThread( void ); + + // Sockets add/remove themselves via their constructor + virtual void AddWaveFilesToThread( CUtlVector< CWaveFile * >& wavefiles ); + + // Lock changes to wavefile list, etc. + virtual void Lock( void ); + // Unlock wavefile list, etc. + virtual void Unlock( void ); + + // Retrieve handle to shutdown event + virtual HANDLE GetShutdownHandle( void ); + + // Caller should call lock before accessing any of these methods and unlock afterwards!!! + virtual int ProcessCompleted(); + + int DoThreadWork(); + + virtual void Start(); + + virtual int GetPendingLoadCount(); +private: + // Critical section used for synchronizing access to wavefile list + CRITICAL_SECTION cs; + CRITICAL_SECTION m_CountCS; + + // List of wavefiles we are listening on + CUtlVector< SentenceRequest * > m_FileList; + + CUtlVector< SentenceRequest * > m_Pending; + CUtlVector< SentenceRequest * > m_Completed; + // Thread handle + HANDLE m_hThread; + // Thread id + DWORD m_nThreadId; + // Event to set when we want to tell the thread to shut itself down + HANDLE m_hShutdown; + + ThreadIOReadBinary m_ThreadIO; + bool m_bLocked; + + int m_nTotalAdds; + int m_nTotalPending; + int m_nTotalProcessed; + int m_nTotalCompleted; + + HANDLE m_hNewItems; +}; + +// Singleton handler +static CFileLoaderThread g_WaveLoader; +extern IFileLoader *fileloader = &g_WaveLoader; + +int CFileLoaderThread::DoThreadWork() +{ + int i; + // Check for shutdown event + if ( WAIT_OBJECT_0 == WaitForSingleObject( GetShutdownHandle(), 0 ) ) + { + return 0; + } + + // No changes to list right now + Lock(); + // Move new items to work list + int newItems = m_FileList.Count(); + for ( i = 0; i < newItems; i++ ) + { + // Move to pending and issue async i/o calls + m_Pending.AddToHead( m_FileList[ i ] ); + + EnterCriticalSection( &m_CountCS ); + m_nTotalPending++; + LeaveCriticalSection( &m_CountCS ); + } + m_FileList.RemoveAll(); + // Done adding new work items + Unlock(); + + int remaining = m_Pending.Count(); + if ( !remaining ) + return 1; + + int workitems = remaining; // min( remaining, 1000 ); + + CUtlVector< SentenceRequest * > transfer; + + for ( i = 0; i < workitems; i++ ) + { + SentenceRequest *r = m_Pending[ 0 ]; + m_Pending.Remove( 0 ); + + transfer.AddToTail( r ); + + // Do the work + EnterCriticalSection( &m_CountCS ); + m_nTotalProcessed++; + LeaveCriticalSection( &m_CountCS ); + + Lock(); + bool load = !r->wavefile->HasLoadedSentenceInfo(); + Unlock(); + + if ( load ) + { + r->valid = SceneManager_LoadSentenceFromWavFileUsingIO( r->filename, r->sentence, m_ThreadIO ); + } + else + { + r->valid = true; + } + + if ( WaitForSingleObject( m_hNewItems, 0 ) == WAIT_OBJECT_0 ) + { + ResetEvent( m_hNewItems ); + break; + } + } + + // Now move to completed list + Lock(); + int c = transfer.Count(); + + for ( i = 0; i < c; ++i ) + { + SentenceRequest *r = transfer[ i ]; + if ( r->valid ) + { + + m_nTotalCompleted++; + + + m_Completed.AddToTail( r ); + } + else + { + delete r; + } + } + Unlock(); + return 1; +} + +int CFileLoaderThread::ProcessCompleted() +{ + Lock(); + int c = m_Completed.Count(); + for ( int i = c - 1; i >= 0 ; i-- ) + { + SentenceRequest *r = m_Completed[ i ]; + + if ( !r->wavefile->HasLoadedSentenceInfo() ) + { + r->wavefile->SetThreadLoadedSentence( r->sentence ); + } + + delete r; + } + m_Completed.RemoveAll(); + Unlock(); + return c; +} + + +//----------------------------------------------------------------------------- +// Purpose: Main winsock processing thread +// Input : threadobject - +// Output : static DWORD WINAPI +//----------------------------------------------------------------------------- +static DWORD WINAPI FileLoaderThreadFunc( LPVOID threadobject ) +{ + // Get pointer to CFileLoaderThread object + CFileLoaderThread *wavefilethread = ( CFileLoaderThread * )threadobject; + Assert( wavefilethread ); + if ( !wavefilethread ) + { + return 0; + } + + // Keep looking for data until shutdown event is triggered + while ( 1 ) + { + if( !wavefilethread->DoThreadWork() ) + break; + + // Yield a small bit of time to main app + Sleep( 10 ); + } + + ExitThread( 0 ); + + return 0; +} + +//----------------------------------------------------------------------------- +// Purpose: Construction +//----------------------------------------------------------------------------- +CFileLoaderThread::CFileLoaderThread( void ) +{ + m_nTotalAdds = 0; + m_nTotalProcessed = 0; + m_nTotalCompleted = 0; + m_nTotalPending = 0; + + m_bLocked = false; + + InitializeCriticalSection( &cs ); + InitializeCriticalSection( &m_CountCS ); + + m_hShutdown = CreateEvent( NULL, TRUE, FALSE, NULL ); + Assert( m_hShutdown ); + + m_hThread = NULL; + + m_hNewItems = CreateEvent( NULL, TRUE, FALSE, NULL ); + + Start(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CFileLoaderThread::Start() +{ + m_hThread = CreateThread( NULL, 0, FileLoaderThreadFunc, (void *)this, 0, &m_nThreadId ); + Assert( m_hThread ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CFileLoaderThread::~CFileLoaderThread( void ) +{ + Lock(); + { + SetEvent( m_hShutdown ); + Sleep( 2 ); + TerminateThread( m_hThread, 0 ); + } + Unlock(); + + // Kill the wavefile +//!! need to validate this line +// Assert( !m_FileList ); + + CloseHandle( m_hThread ); + + CloseHandle( m_hShutdown ); + + DeleteCriticalSection( &cs ); + DeleteCriticalSection( &m_CountCS ); + + CloseHandle( m_hNewItems ); +} + +//----------------------------------------------------------------------------- +// Purpose: Returns handle of shutdown event +// Output : HANDLE +//----------------------------------------------------------------------------- +HANDLE CFileLoaderThread::GetShutdownHandle( void ) +{ + return m_hShutdown; +} + +//----------------------------------------------------------------------------- +// Purpose: Locks object and adds wavefile to thread +// Input : *wavefile - +//----------------------------------------------------------------------------- +void CFileLoaderThread::AddWaveFilesToThread( CUtlVector< CWaveFile * >& wavefiles ) +{ + Lock(); + int c = wavefiles.Count(); + for ( int i = 0; i < c; i++ ) + { + SentenceRequest *request = new SentenceRequest; + request->wavefile = wavefiles[ i ]; + Q_strncpy( request->filename, request->wavefile->GetFileName(), sizeof( request->filename ) ); + + m_FileList.AddToTail( request ); + + m_nTotalAdds++; + } + + SetEvent( m_hNewItems ); + Unlock(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CFileLoaderThread::Lock( void ) +{ + EnterCriticalSection( &cs ); + Assert( !m_bLocked ); + m_bLocked = true; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CFileLoaderThread::Unlock( void ) +{ + Assert( m_bLocked ); + m_bLocked = false; + LeaveCriticalSection( &cs ); +} + +int CFileLoaderThread::GetPendingLoadCount() +{ + int iret = 0; + + EnterCriticalSection( &m_CountCS ); + + iret = m_nTotalPending - m_nTotalProcessed; + + LeaveCriticalSection( &m_CountCS ); + + return iret; +}
\ No newline at end of file |