Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

378 lines
8.4 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //===========================================================================//
  7. #include "tier0/platform.h"
  8. #include "cbase.h"
  9. #include "sentence.h"
  10. #include "wavefile.h"
  11. #include "tier2/riff.h"
  12. #include "filesystem.h"
  13. #include <io.h>
  14. #include <fcntl.h>
  15. #include <sys/types.h>
  16. #include "IFileLoader.h"
  17. bool SceneManager_LoadSentenceFromWavFileUsingIO( char const *wavfile, CSentence& sentence, IFileReadBinary& io );
  18. //-----------------------------------------------------------------------------
  19. // Purpose: Implements the RIFF i/o interface on stdio
  20. //-----------------------------------------------------------------------------
  21. class ThreadIOReadBinary : public IFileReadBinary
  22. {
  23. public:
  24. FileHandle_t open( const char *pFileName )
  25. {
  26. char filename[ 512 ];
  27. // POSSIBLE BUG: THIS MIGHT NOT BE THREAD SAFE!!!
  28. filesystem->RelativePathToFullPath( pFileName, "GAME", filename, sizeof( filename ) );
  29. return (FileHandle_t)_open( filename, _O_BINARY | _O_RDONLY );
  30. }
  31. int read( void *pOutput, int size, FileHandle_t file )
  32. {
  33. if ( !file )
  34. return 0;
  35. return _read( (int)(intp)file, pOutput, size );
  36. }
  37. void seek( FileHandle_t file, int pos )
  38. {
  39. if ( !file )
  40. return;
  41. _lseek( (int)(intp)file, pos, SEEK_SET );
  42. }
  43. unsigned int tell( FileHandle_t file )
  44. {
  45. if ( !file )
  46. return 0;
  47. return _tell( (int)(intp)file );
  48. }
  49. unsigned int size( FileHandle_t file )
  50. {
  51. if ( !file )
  52. return 0;
  53. long curpos = this->tell( file );
  54. _lseek( (int)(intp)file, 0, SEEK_END );
  55. int s = this->tell( file );
  56. _lseek( (int)(intp)file, curpos, SEEK_SET );
  57. return s;
  58. }
  59. void close( FileHandle_t file )
  60. {
  61. if ( !file )
  62. return;
  63. _close( (int)(intp)file );
  64. }
  65. };
  66. //-----------------------------------------------------------------------------
  67. // Purpose: All wavefile I/O occurs on a thread
  68. //-----------------------------------------------------------------------------
  69. class CFileLoaderThread : public IFileLoader
  70. {
  71. public:
  72. struct SentenceRequest
  73. {
  74. SentenceRequest()
  75. {
  76. filename[ 0 ] = 0;
  77. sentence.Reset();
  78. wavefile = NULL;
  79. valid = false;
  80. }
  81. bool valid;
  82. char filename[ 256 ];
  83. CSentence sentence;
  84. CWaveFile *wavefile;
  85. };
  86. // Construction
  87. CFileLoaderThread( void );
  88. virtual ~CFileLoaderThread( void );
  89. // Sockets add/remove themselves via their constructor
  90. virtual void AddWaveFilesToThread( CUtlVector< CWaveFile * >& wavefiles );
  91. // Retrieve handle to shutdown event
  92. virtual HANDLE GetShutdownHandle( void );
  93. // Caller should call lock before accessing any of these methods and unlock afterwards!!!
  94. virtual int ProcessCompleted();
  95. int DoThreadWork();
  96. virtual void Start();
  97. virtual int GetPendingLoadCount();
  98. private:
  99. // Critical section used for synchronizing access to wavefile list
  100. CThreadFastMutex m_Mutex;
  101. // List of wavefiles we are listening on
  102. CUtlVector< SentenceRequest * > m_FileList;
  103. CUtlVector< SentenceRequest * > m_Pending;
  104. CUtlVector< SentenceRequest * > m_Completed;
  105. // Thread handle
  106. HANDLE m_hThread;
  107. // Thread id
  108. DWORD m_nThreadId;
  109. // Event to set when we want to tell the thread to shut itself down
  110. HANDLE m_hShutdown;
  111. ThreadIOReadBinary m_ThreadIO;
  112. int m_nTotalAdds;
  113. int m_nTotalCompleted;
  114. CInterlockedInt m_nTotalPending;
  115. CInterlockedInt m_nTotalProcessed;
  116. HANDLE m_hNewItems;
  117. };
  118. // Singleton handler
  119. static CFileLoaderThread g_WaveLoader;
  120. extern IFileLoader *fileloader = &g_WaveLoader;
  121. int CFileLoaderThread::DoThreadWork()
  122. {
  123. int i;
  124. // Check for shutdown event
  125. if ( WAIT_OBJECT_0 == WaitForSingleObject( GetShutdownHandle(), 0 ) )
  126. {
  127. return 0;
  128. }
  129. // No changes to list right now
  130. {
  131. AUTO_LOCK_FM( m_Mutex );
  132. // Move new items to work list
  133. int newItems = m_FileList.Count();
  134. for ( i = 0; i < newItems; i++ )
  135. {
  136. // Move to pending and issue async i/o calls
  137. m_Pending.AddToHead( m_FileList[ i ] );
  138. m_nTotalPending++;
  139. }
  140. m_FileList.RemoveAll();
  141. // Done adding new work items
  142. }
  143. int remaining = m_Pending.Count();
  144. if ( !remaining )
  145. return 1;
  146. int workitems = remaining; // min( remaining, 1000 );
  147. CUtlVector< SentenceRequest * > transfer;
  148. for ( i = 0; i < workitems; i++ )
  149. {
  150. SentenceRequest *r = m_Pending[ 0 ];
  151. m_Pending.Remove( 0 );
  152. transfer.AddToTail( r );
  153. // Do the work
  154. m_nTotalProcessed++;
  155. bool load = false;
  156. {
  157. AUTO_LOCK_FM( m_Mutex );
  158. load = !r->wavefile->HasLoadedSentenceInfo();
  159. }
  160. if ( load )
  161. {
  162. r->valid = SceneManager_LoadSentenceFromWavFileUsingIO( r->filename, r->sentence, m_ThreadIO );
  163. }
  164. else
  165. {
  166. r->valid = true;
  167. }
  168. if ( WaitForSingleObject( m_hNewItems, 0 ) == WAIT_OBJECT_0 )
  169. {
  170. ResetEvent( m_hNewItems );
  171. break;
  172. }
  173. }
  174. // Now move to completed list
  175. {
  176. AUTO_LOCK_FM( m_Mutex );
  177. int c = transfer.Count();
  178. for ( i = 0; i < c; ++i )
  179. {
  180. SentenceRequest *r = transfer[ i ];
  181. if ( r->valid )
  182. {
  183. m_nTotalCompleted++;
  184. m_Completed.AddToTail( r );
  185. }
  186. else
  187. {
  188. delete r;
  189. }
  190. }
  191. }
  192. return 1;
  193. }
  194. int CFileLoaderThread::ProcessCompleted()
  195. {
  196. AUTO_LOCK_FM( m_Mutex );
  197. int c = m_Completed.Count();
  198. for ( int i = c - 1; i >= 0 ; i-- )
  199. {
  200. SentenceRequest *r = m_Completed[ i ];
  201. if ( !r->wavefile->HasLoadedSentenceInfo() )
  202. {
  203. r->wavefile->SetThreadLoadedSentence( r->sentence );
  204. }
  205. delete r;
  206. }
  207. m_Completed.RemoveAll();
  208. return c;
  209. }
  210. //-----------------------------------------------------------------------------
  211. // Purpose: Main winsock processing thread
  212. // Input : threadobject -
  213. // Output : static DWORD WINAPI
  214. //-----------------------------------------------------------------------------
  215. static DWORD WINAPI FileLoaderThreadFunc( LPVOID threadobject )
  216. {
  217. // Get pointer to CFileLoaderThread object
  218. CFileLoaderThread *wavefilethread = ( CFileLoaderThread * )threadobject;
  219. Assert( wavefilethread );
  220. if ( !wavefilethread )
  221. {
  222. return 0;
  223. }
  224. // Keep looking for data until shutdown event is triggered
  225. while ( 1 )
  226. {
  227. if( !wavefilethread->DoThreadWork() )
  228. break;
  229. // Yield a small bit of time to main app
  230. Sleep( 10 );
  231. }
  232. ExitThread( 0 );
  233. return 0;
  234. }
  235. //-----------------------------------------------------------------------------
  236. // Purpose: Construction
  237. //-----------------------------------------------------------------------------
  238. CFileLoaderThread::CFileLoaderThread( void )
  239. {
  240. m_nTotalAdds = 0;
  241. m_nTotalProcessed = 0;
  242. m_nTotalCompleted = 0;
  243. m_nTotalPending = 0;
  244. m_hShutdown = CreateEvent( NULL, TRUE, FALSE, NULL );
  245. Assert( m_hShutdown );
  246. m_hThread = NULL;
  247. m_hNewItems = CreateEvent( NULL, TRUE, FALSE, NULL );
  248. Start();
  249. }
  250. //-----------------------------------------------------------------------------
  251. // Purpose:
  252. //-----------------------------------------------------------------------------
  253. void CFileLoaderThread::Start()
  254. {
  255. m_hThread = CreateThread( NULL, 0, FileLoaderThreadFunc, (void *)this, 0, &m_nThreadId );
  256. Assert( m_hThread );
  257. }
  258. //-----------------------------------------------------------------------------
  259. // Purpose:
  260. //-----------------------------------------------------------------------------
  261. CFileLoaderThread::~CFileLoaderThread( void )
  262. {
  263. {
  264. AUTO_LOCK_FM( m_Mutex );
  265. SetEvent( m_hShutdown );
  266. Sleep( 2 );
  267. TerminateThread( m_hThread, 0 );
  268. }
  269. // Kill the wavefile
  270. //!! need to validate this line
  271. // Assert( !m_FileList );
  272. CloseHandle( m_hThread );
  273. CloseHandle( m_hShutdown );
  274. CloseHandle( m_hNewItems );
  275. }
  276. //-----------------------------------------------------------------------------
  277. // Purpose: Returns handle of shutdown event
  278. // Output : HANDLE
  279. //-----------------------------------------------------------------------------
  280. HANDLE CFileLoaderThread::GetShutdownHandle( void )
  281. {
  282. return m_hShutdown;
  283. }
  284. //-----------------------------------------------------------------------------
  285. // Purpose: Locks object and adds wavefile to thread
  286. // Input : *wavefile -
  287. //-----------------------------------------------------------------------------
  288. void CFileLoaderThread::AddWaveFilesToThread( CUtlVector< CWaveFile * >& wavefiles )
  289. {
  290. AUTO_LOCK_FM( m_Mutex );
  291. int c = wavefiles.Count();
  292. for ( int i = 0; i < c; i++ )
  293. {
  294. SentenceRequest *request = new SentenceRequest;
  295. request->wavefile = wavefiles[ i ];
  296. Q_strncpy( request->filename, request->wavefile->GetFileName(), sizeof( request->filename ) );
  297. m_FileList.AddToTail( request );
  298. m_nTotalAdds++;
  299. }
  300. SetEvent( m_hNewItems );
  301. }
  302. int CFileLoaderThread::GetPendingLoadCount()
  303. {
  304. return m_nTotalPending - m_nTotalProcessed;
  305. }