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.

314 lines
7.6 KiB

  1. //====== Copyright c 1996-2007, Valve Corporation, All rights reserved. =======//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include <windows.h>
  9. #include "cmdsink.h"
  10. #include "subprocess.h"
  11. #include "d3dxfxc.h"
  12. #include "tools_minidump.h"
  13. //////////////////////////////////////////////////////////////////////////
  14. //
  15. // Base implementation of the shaderd kernel objects
  16. //
  17. //////////////////////////////////////////////////////////////////////////
  18. SubProcessKernelObjects::SubProcessKernelObjects( void ) :
  19. m_hMemorySection( NULL ),
  20. m_hMutex( NULL )
  21. {
  22. ZeroMemory( m_hEvent, sizeof( m_hEvent ) );
  23. }
  24. SubProcessKernelObjects::~SubProcessKernelObjects( void )
  25. {
  26. Close();
  27. }
  28. BOOL SubProcessKernelObjects::Create( char const *szBaseName )
  29. {
  30. char chBufferName[0x100] = { 0 };
  31. sprintf( chBufferName, "%s_msec", szBaseName );
  32. m_hMemorySection = CreateFileMapping( INVALID_HANDLE_VALUE, NULL,
  33. PAGE_READWRITE, 0, 4 * 1024 * 1024, chBufferName ); // 4Mb for a piece
  34. if ( NULL != m_hMemorySection )
  35. {
  36. if ( ERROR_ALREADY_EXISTS == GetLastError() )
  37. {
  38. CloseHandle( m_hMemorySection );
  39. m_hMemorySection = NULL;
  40. Assert( 0 && "CreateFileMapping - already exists!\n" );
  41. }
  42. }
  43. sprintf( chBufferName, "%s_mtx", szBaseName );
  44. m_hMutex = CreateMutex( NULL, FALSE, chBufferName );
  45. for ( int k = 0; k < 2; ++ k )
  46. {
  47. sprintf( chBufferName, "%s_evt%d", szBaseName, k );
  48. m_hEvent[k] = CreateEvent( NULL, FALSE, ( k ? TRUE /* = master */ : FALSE ), chBufferName );
  49. }
  50. return IsValid();
  51. }
  52. BOOL SubProcessKernelObjects::Open( char const *szBaseName )
  53. {
  54. char chBufferName[0x100] = { 0 };
  55. sprintf( chBufferName, "%s_msec", szBaseName );
  56. m_hMemorySection = OpenFileMapping( FILE_MAP_ALL_ACCESS, FALSE, chBufferName );
  57. sprintf( chBufferName, "%s_mtx", szBaseName );
  58. m_hMutex = OpenMutex( MUTEX_ALL_ACCESS, FALSE, chBufferName );
  59. for ( int k = 0; k < 2; ++ k )
  60. {
  61. sprintf( chBufferName, "%s_evt%d", szBaseName, k );
  62. m_hEvent[k] = OpenEvent( EVENT_ALL_ACCESS, FALSE, chBufferName );
  63. }
  64. return IsValid();
  65. }
  66. BOOL SubProcessKernelObjects::IsValid( void ) const
  67. {
  68. return m_hMemorySection && m_hMutex && m_hEvent;
  69. }
  70. void SubProcessKernelObjects::Close( void )
  71. {
  72. if ( m_hMemorySection )
  73. CloseHandle( m_hMemorySection );
  74. if ( m_hMutex )
  75. CloseHandle( m_hMutex );
  76. for ( int k = 0; k < 2; ++ k )
  77. if ( m_hEvent[k] )
  78. CloseHandle( m_hEvent[k] );
  79. }
  80. //////////////////////////////////////////////////////////////////////////
  81. //
  82. // Helper class to send data back and forth
  83. //
  84. //////////////////////////////////////////////////////////////////////////
  85. void * SubProcessKernelObjects_Memory::Lock( void )
  86. {
  87. // Wait for our turn to act
  88. for ( unsigned iWaitAttempt = 0; iWaitAttempt < 13u; ++ iWaitAttempt )
  89. {
  90. DWORD dwWait = ::WaitForSingleObject( m_pObjs->m_hEvent[ m_pObjs->m_dwCookie ], 10000 );
  91. switch ( dwWait )
  92. {
  93. case WAIT_OBJECT_0:
  94. {
  95. m_pLockData = MapViewOfFile( m_pObjs->m_hMemorySection, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
  96. if ( !m_pLockData )
  97. {
  98. DWORD err = GetLastError();
  99. Msg( "MapViewOfFile failed with error %d\n", err );
  100. }
  101. if ( m_pLockData && * ( const DWORD * ) m_pLockData != m_pObjs->m_dwCookie )
  102. {
  103. // Yes, this is our turn, set our cookie in that memory segment
  104. * ( DWORD * ) m_pLockData = m_pObjs->m_dwCookie;
  105. m_pMemory = ( ( byte * ) m_pLockData ) + 2 * sizeof( DWORD );
  106. return m_pMemory;
  107. }
  108. else
  109. {
  110. // We just acted, still waiting for result
  111. UnmapViewOfFile( m_pLockData );
  112. m_pLockData = NULL;
  113. SetEvent( m_pObjs->m_hEvent[ !m_pObjs->m_dwCookie ] );
  114. Sleep( 1 );
  115. continue;
  116. }
  117. }
  118. break;
  119. case WAIT_TIMEOUT:
  120. {
  121. char chMsg[0x100];
  122. sprintf( chMsg, "th%08X> WAIT_TIMEOUT in Memory::Lock (attempt %d).\n", GetCurrentThreadId(), iWaitAttempt );
  123. OutputDebugString( chMsg );
  124. }
  125. continue; // retry
  126. default:
  127. OutputDebugString( "WAIT failure in Memory::Lock\n" );
  128. SetLastError( ERROR_BAD_UNIT );
  129. return NULL;
  130. }
  131. }
  132. OutputDebugString( "Ran out of wait attempts in Memory::Lock\n" );
  133. SetLastError( ERROR_NOT_READY );
  134. return NULL;
  135. }
  136. BOOL SubProcessKernelObjects_Memory::Unlock( void )
  137. {
  138. if ( m_pLockData )
  139. {
  140. // Assert that the memory hasn't been spoiled
  141. Assert( m_pObjs->m_dwCookie == * ( const DWORD * ) m_pLockData );
  142. DWORD ret = UnmapViewOfFile( m_pLockData );
  143. if ( ret == 0 )
  144. {
  145. DWORD err = GetLastError();
  146. Msg( "UnmapViewOfFile failed with error %d\n", err );
  147. }
  148. m_pMemory = NULL;
  149. m_pLockData = NULL;
  150. SetEvent( m_pObjs->m_hEvent[ !m_pObjs->m_dwCookie ] );
  151. Sleep( 1 );
  152. return TRUE;
  153. }
  154. return FALSE;
  155. }
  156. //////////////////////////////////////////////////////////////////////////
  157. //
  158. // Implementation of the command subprocess:
  159. //
  160. // MASTER ---- command -------> SUB
  161. // string - zero terminated command string.
  162. //
  163. //
  164. // MASTER <---- result -------- SUB
  165. // dword - 1 if succeeded, 0 if failed
  166. // dword - result buffer length, 0 if failed
  167. // <bytes> - result buffer data, none if result buffer length is 0
  168. // string - zero-terminated listing string
  169. //
  170. //////////////////////////////////////////////////////////////////////////
  171. CSubProcessResponse::CSubProcessResponse( void const *pvMemory ) :
  172. m_pvMemory( pvMemory )
  173. {
  174. byte const *pBytes = ( byte const * ) pvMemory;
  175. m_dwResult = * ( DWORD const * ) pBytes;
  176. pBytes += sizeof( DWORD );
  177. m_dwResultBufferLength = * ( DWORD const * ) pBytes;
  178. pBytes += sizeof( DWORD );
  179. m_pvResultBuffer = pBytes;
  180. pBytes += m_dwResultBufferLength;
  181. m_szListing = ( char const * ) ( *pBytes ? pBytes : NULL );
  182. }
  183. void ShaderCompile_Subprocess_ExceptionHandler( unsigned long exceptionCode, void *pvExceptionInfo )
  184. {
  185. // Subprocesses just silently die in our case, then this case will be detected by the worker process and an error code will be passed to the master
  186. Assert( !"ShaderCompile_Subprocess_ExceptionHandler" );
  187. ::TerminateProcess( ::GetCurrentProcess(), exceptionCode );
  188. }
  189. int ShaderCompile_Subprocess_Main( char const *szSubProcessData )
  190. {
  191. // Set our crash handler
  192. SetupToolsMinidumpHandler( ShaderCompile_Subprocess_ExceptionHandler );
  193. // Get our kernel objects
  194. SubProcessKernelObjects_Open objs( szSubProcessData );
  195. if ( !objs.IsValid() )
  196. return -1;
  197. // Enter the command pumping loop
  198. SubProcessKernelObjects_Memory shrmem( &objs );
  199. for (
  200. void *pvMemory = NULL;
  201. NULL != ( pvMemory = shrmem.Lock() );
  202. shrmem.Unlock()
  203. )
  204. {
  205. // The memory is actually a command
  206. char const *szCommand = ( char const * ) pvMemory;
  207. if ( !stricmp( "keepalive", szCommand ) )
  208. {
  209. ZeroMemory( pvMemory, 4 * sizeof( DWORD ) );
  210. continue;
  211. }
  212. if ( !stricmp( "quit", szCommand ) )
  213. {
  214. ZeroMemory( pvMemory, 4 * sizeof( DWORD ) );
  215. return 0;
  216. }
  217. CmdSink::IResponse *pResponse = NULL;
  218. if ( InterceptFxc::TryExecuteCommand( szCommand, &pResponse ) )
  219. {
  220. byte *pBytes = ( byte * ) pvMemory;
  221. // Result
  222. DWORD dwSucceededResult = pResponse->Succeeded() ? 1 : 0;
  223. * ( DWORD * ) pBytes = dwSucceededResult;
  224. pBytes += sizeof( DWORD );
  225. // Result buffer len
  226. DWORD dwBufferLength = pResponse->GetResultBufferLen();
  227. * ( DWORD * ) pBytes = dwBufferLength;
  228. pBytes += sizeof( DWORD );
  229. // Result buffer
  230. const void *pvResultBuffer = pResponse->GetResultBuffer();
  231. memcpy( pBytes, pvResultBuffer, dwBufferLength );
  232. pBytes += dwBufferLength;
  233. // Listing - copy string
  234. const char *szListing = pResponse->GetListing();
  235. if ( szListing )
  236. {
  237. while ( 0 != ( * ( pBytes ++ ) = * ( szListing ++ ) ) )
  238. {
  239. NULL;
  240. }
  241. }
  242. else
  243. {
  244. * ( pBytes ++ ) = 0;
  245. }
  246. }
  247. else
  248. {
  249. ZeroMemory( pvMemory, 4 * sizeof( DWORD ) );
  250. }
  251. }
  252. return -2;
  253. }