Team Fortress 2 Source Code as on 22/4/2020
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.

303 lines
7.4 KiB

  1. //========= Copyright 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 ( * ( const DWORD * ) m_pLockData != m_pObjs->m_dwCookie )
  97. {
  98. // Yes, this is our turn, set our cookie in that memory segment
  99. * ( DWORD * ) m_pLockData = m_pObjs->m_dwCookie;
  100. m_pMemory = ( ( byte * ) m_pLockData ) + 2 * sizeof( DWORD );
  101. return m_pMemory;
  102. }
  103. else
  104. {
  105. // We just acted, still waiting for result
  106. UnmapViewOfFile( m_pLockData );
  107. m_pLockData = NULL;
  108. SetEvent( m_pObjs->m_hEvent[ !m_pObjs->m_dwCookie ] );
  109. Sleep( 1 );
  110. continue;
  111. }
  112. }
  113. break;
  114. case WAIT_TIMEOUT:
  115. {
  116. char chMsg[0x100];
  117. sprintf( chMsg, "th%08X> WAIT_TIMEOUT in Memory::Lock (attempt %d).\n", GetCurrentThreadId(), iWaitAttempt );
  118. OutputDebugString( chMsg );
  119. }
  120. continue; // retry
  121. default:
  122. OutputDebugString( "WAIT failure in Memory::Lock\n" );
  123. SetLastError( ERROR_BAD_UNIT );
  124. return NULL;
  125. }
  126. }
  127. OutputDebugString( "Ran out of wait attempts in Memory::Lock\n" );
  128. SetLastError( ERROR_NOT_READY );
  129. return NULL;
  130. }
  131. BOOL SubProcessKernelObjects_Memory::Unlock( void )
  132. {
  133. if ( m_pLockData )
  134. {
  135. // Assert that the memory hasn't been spoiled
  136. Assert( m_pObjs->m_dwCookie == * ( const DWORD * ) m_pLockData );
  137. UnmapViewOfFile( m_pLockData );
  138. m_pMemory = NULL;
  139. m_pLockData = NULL;
  140. SetEvent( m_pObjs->m_hEvent[ !m_pObjs->m_dwCookie ] );
  141. Sleep( 1 );
  142. return TRUE;
  143. }
  144. return FALSE;
  145. }
  146. //////////////////////////////////////////////////////////////////////////
  147. //
  148. // Implementation of the command subprocess:
  149. //
  150. // MASTER ---- command -------> SUB
  151. // string - zero terminated command string.
  152. //
  153. //
  154. // MASTER <---- result -------- SUB
  155. // dword - 1 if succeeded, 0 if failed
  156. // dword - result buffer length, 0 if failed
  157. // <bytes> - result buffer data, none if result buffer length is 0
  158. // string - zero-terminated listing string
  159. //
  160. //////////////////////////////////////////////////////////////////////////
  161. CSubProcessResponse::CSubProcessResponse( void const *pvMemory ) :
  162. m_pvMemory( pvMemory )
  163. {
  164. byte const *pBytes = ( byte const * ) pvMemory;
  165. m_dwResult = * ( DWORD const * ) pBytes;
  166. pBytes += sizeof( DWORD );
  167. m_dwResultBufferLength = * ( DWORD const * ) pBytes;
  168. pBytes += sizeof( DWORD );
  169. m_pvResultBuffer = pBytes;
  170. pBytes += m_dwResultBufferLength;
  171. m_szListing = ( char const * ) ( *pBytes ? pBytes : NULL );
  172. }
  173. void ShaderCompile_Subprocess_ExceptionHandler( unsigned long exceptionCode, void *pvExceptionInfo )
  174. {
  175. // 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
  176. Assert( !"ShaderCompile_Subprocess_ExceptionHandler" );
  177. ::TerminateProcess( ::GetCurrentProcess(), exceptionCode );
  178. }
  179. int ShaderCompile_Subprocess_Main( char const *szSubProcessData )
  180. {
  181. // Set our crash handler
  182. SetupToolsMinidumpHandler( ShaderCompile_Subprocess_ExceptionHandler );
  183. // Get our kernel objects
  184. SubProcessKernelObjects_Open objs( szSubProcessData );
  185. if ( !objs.IsValid() )
  186. return -1;
  187. // Enter the command pumping loop
  188. SubProcessKernelObjects_Memory shrmem( &objs );
  189. for (
  190. void *pvMemory = NULL;
  191. NULL != ( pvMemory = shrmem.Lock() );
  192. shrmem.Unlock()
  193. )
  194. {
  195. // The memory is actually a command
  196. char const *szCommand = ( char const * ) pvMemory;
  197. if ( !stricmp( "keepalive", szCommand ) )
  198. {
  199. ZeroMemory( pvMemory, 4 * sizeof( DWORD ) );
  200. continue;
  201. }
  202. if ( !stricmp( "quit", szCommand ) )
  203. {
  204. ZeroMemory( pvMemory, 4 * sizeof( DWORD ) );
  205. return 0;
  206. }
  207. CmdSink::IResponse *pResponse = NULL;
  208. if ( InterceptFxc::TryExecuteCommand( szCommand, &pResponse ) )
  209. {
  210. byte *pBytes = ( byte * ) pvMemory;
  211. // Result
  212. DWORD dwSucceededResult = pResponse->Succeeded() ? 1 : 0;
  213. * ( DWORD * ) pBytes = dwSucceededResult;
  214. pBytes += sizeof( DWORD );
  215. // Result buffer len
  216. DWORD dwBufferLength = pResponse->GetResultBufferLen();
  217. * ( DWORD * ) pBytes = dwBufferLength;
  218. pBytes += sizeof( DWORD );
  219. // Result buffer
  220. const void *pvResultBuffer = pResponse->GetResultBuffer();
  221. memcpy( pBytes, pvResultBuffer, dwBufferLength );
  222. pBytes += dwBufferLength;
  223. // Listing - copy string
  224. const char *szListing = pResponse->GetListing();
  225. if ( szListing )
  226. {
  227. while ( 0 != ( * ( pBytes ++ ) = * ( szListing ++ ) ) )
  228. {
  229. NULL;
  230. }
  231. }
  232. else
  233. {
  234. * ( pBytes ++ ) = 0;
  235. }
  236. }
  237. else
  238. {
  239. ZeroMemory( pvMemory, 4 * sizeof( DWORD ) );
  240. }
  241. }
  242. return -2;
  243. }