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
303 lines
7.4 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
// |
|
//=============================================================================// |
|
|
|
#include <windows.h> |
|
|
|
#include "cmdsink.h" |
|
|
|
#include "subprocess.h" |
|
|
|
#include "d3dxfxc.h" |
|
|
|
#include "tools_minidump.h" |
|
|
|
////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Base implementation of the shaderd kernel objects |
|
// |
|
////////////////////////////////////////////////////////////////////////// |
|
|
|
SubProcessKernelObjects::SubProcessKernelObjects( void ) : |
|
m_hMemorySection( NULL ), |
|
m_hMutex( NULL ) |
|
{ |
|
ZeroMemory( m_hEvent, sizeof( m_hEvent ) ); |
|
} |
|
|
|
SubProcessKernelObjects::~SubProcessKernelObjects( void ) |
|
{ |
|
Close(); |
|
} |
|
|
|
BOOL SubProcessKernelObjects::Create( char const *szBaseName ) |
|
{ |
|
char chBufferName[0x100] = { 0 }; |
|
|
|
sprintf( chBufferName, "%s_msec", szBaseName ); |
|
m_hMemorySection = CreateFileMapping( INVALID_HANDLE_VALUE, NULL, |
|
PAGE_READWRITE, 0, 4 * 1024 * 1024, chBufferName ); // 4Mb for a piece |
|
if ( NULL != m_hMemorySection ) |
|
{ |
|
if ( ERROR_ALREADY_EXISTS == GetLastError() ) |
|
{ |
|
CloseHandle( m_hMemorySection ); |
|
m_hMemorySection = NULL; |
|
|
|
Assert( 0 && "CreateFileMapping - already exists!\n" ); |
|
} |
|
} |
|
|
|
sprintf( chBufferName, "%s_mtx", szBaseName ); |
|
m_hMutex = CreateMutex( NULL, FALSE, chBufferName ); |
|
|
|
for ( int k = 0; k < 2; ++ k ) |
|
{ |
|
sprintf( chBufferName, "%s_evt%d", szBaseName, k ); |
|
m_hEvent[k] = CreateEvent( NULL, FALSE, ( k ? TRUE /* = master */ : FALSE ), chBufferName ); |
|
} |
|
|
|
return IsValid(); |
|
} |
|
|
|
BOOL SubProcessKernelObjects::Open( char const *szBaseName ) |
|
{ |
|
char chBufferName[0x100] = { 0 }; |
|
|
|
sprintf( chBufferName, "%s_msec", szBaseName ); |
|
m_hMemorySection = OpenFileMapping( FILE_MAP_ALL_ACCESS, FALSE, chBufferName ); |
|
|
|
sprintf( chBufferName, "%s_mtx", szBaseName ); |
|
m_hMutex = OpenMutex( MUTEX_ALL_ACCESS, FALSE, chBufferName ); |
|
|
|
for ( int k = 0; k < 2; ++ k ) |
|
{ |
|
sprintf( chBufferName, "%s_evt%d", szBaseName, k ); |
|
m_hEvent[k] = OpenEvent( EVENT_ALL_ACCESS, FALSE, chBufferName ); |
|
} |
|
|
|
return IsValid(); |
|
} |
|
|
|
BOOL SubProcessKernelObjects::IsValid( void ) const |
|
{ |
|
return m_hMemorySection && m_hMutex && m_hEvent; |
|
} |
|
|
|
void SubProcessKernelObjects::Close( void ) |
|
{ |
|
if ( m_hMemorySection ) |
|
CloseHandle( m_hMemorySection ); |
|
|
|
if ( m_hMutex ) |
|
CloseHandle( m_hMutex ); |
|
|
|
for ( int k = 0; k < 2; ++ k ) |
|
if ( m_hEvent[k] ) |
|
CloseHandle( m_hEvent[k] ); |
|
} |
|
|
|
////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Helper class to send data back and forth |
|
// |
|
////////////////////////////////////////////////////////////////////////// |
|
|
|
void * SubProcessKernelObjects_Memory::Lock( void ) |
|
{ |
|
// Wait for our turn to act |
|
for ( unsigned iWaitAttempt = 0; iWaitAttempt < 13u; ++ iWaitAttempt ) |
|
{ |
|
DWORD dwWait = ::WaitForSingleObject( m_pObjs->m_hEvent[ m_pObjs->m_dwCookie ], 10000 ); |
|
switch ( dwWait ) |
|
{ |
|
case WAIT_OBJECT_0: |
|
{ |
|
m_pLockData = MapViewOfFile( m_pObjs->m_hMemorySection, FILE_MAP_ALL_ACCESS, 0, 0, 0 ); |
|
|
|
if ( * ( const DWORD * ) m_pLockData != m_pObjs->m_dwCookie ) |
|
{ |
|
// Yes, this is our turn, set our cookie in that memory segment |
|
* ( DWORD * ) m_pLockData = m_pObjs->m_dwCookie; |
|
m_pMemory = ( ( byte * ) m_pLockData ) + 2 * sizeof( DWORD ); |
|
|
|
return m_pMemory; |
|
} |
|
else |
|
{ |
|
// We just acted, still waiting for result |
|
UnmapViewOfFile( m_pLockData ); |
|
m_pLockData = NULL; |
|
|
|
SetEvent( m_pObjs->m_hEvent[ !m_pObjs->m_dwCookie ] ); |
|
Sleep( 1 ); |
|
|
|
continue; |
|
} |
|
} |
|
break; |
|
|
|
case WAIT_TIMEOUT: |
|
{ |
|
char chMsg[0x100]; |
|
sprintf( chMsg, "th%08X> WAIT_TIMEOUT in Memory::Lock (attempt %d).\n", GetCurrentThreadId(), iWaitAttempt ); |
|
OutputDebugString( chMsg ); |
|
} |
|
continue; // retry |
|
|
|
default: |
|
OutputDebugString( "WAIT failure in Memory::Lock\n" ); |
|
SetLastError( ERROR_BAD_UNIT ); |
|
return NULL; |
|
} |
|
} |
|
|
|
OutputDebugString( "Ran out of wait attempts in Memory::Lock\n" ); |
|
SetLastError( ERROR_NOT_READY ); |
|
return NULL; |
|
} |
|
|
|
BOOL SubProcessKernelObjects_Memory::Unlock( void ) |
|
{ |
|
if ( m_pLockData ) |
|
{ |
|
// Assert that the memory hasn't been spoiled |
|
Assert( m_pObjs->m_dwCookie == * ( const DWORD * ) m_pLockData ); |
|
|
|
UnmapViewOfFile( m_pLockData ); |
|
m_pMemory = NULL; |
|
m_pLockData = NULL; |
|
|
|
SetEvent( m_pObjs->m_hEvent[ !m_pObjs->m_dwCookie ] ); |
|
Sleep( 1 ); |
|
|
|
return TRUE; |
|
} |
|
|
|
return FALSE; |
|
} |
|
|
|
|
|
////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Implementation of the command subprocess: |
|
// |
|
// MASTER ---- command -------> SUB |
|
// string - zero terminated command string. |
|
// |
|
// |
|
// MASTER <---- result -------- SUB |
|
// dword - 1 if succeeded, 0 if failed |
|
// dword - result buffer length, 0 if failed |
|
// <bytes> - result buffer data, none if result buffer length is 0 |
|
// string - zero-terminated listing string |
|
// |
|
////////////////////////////////////////////////////////////////////////// |
|
|
|
|
|
CSubProcessResponse::CSubProcessResponse( void const *pvMemory ) : |
|
m_pvMemory( pvMemory ) |
|
{ |
|
byte const *pBytes = ( byte const * ) pvMemory; |
|
|
|
m_dwResult = * ( DWORD const * ) pBytes; |
|
pBytes += sizeof( DWORD ); |
|
|
|
m_dwResultBufferLength = * ( DWORD const * ) pBytes; |
|
pBytes += sizeof( DWORD ); |
|
|
|
m_pvResultBuffer = pBytes; |
|
pBytes += m_dwResultBufferLength; |
|
|
|
m_szListing = ( char const * ) ( *pBytes ? pBytes : NULL ); |
|
} |
|
|
|
|
|
void ShaderCompile_Subprocess_ExceptionHandler( unsigned long exceptionCode, void *pvExceptionInfo ) |
|
{ |
|
// 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 |
|
Assert( !"ShaderCompile_Subprocess_ExceptionHandler" ); |
|
::TerminateProcess( ::GetCurrentProcess(), exceptionCode ); |
|
} |
|
|
|
|
|
int ShaderCompile_Subprocess_Main( char const *szSubProcessData ) |
|
{ |
|
// Set our crash handler |
|
SetupToolsMinidumpHandler( ShaderCompile_Subprocess_ExceptionHandler ); |
|
|
|
// Get our kernel objects |
|
SubProcessKernelObjects_Open objs( szSubProcessData ); |
|
|
|
if ( !objs.IsValid() ) |
|
return -1; |
|
|
|
// Enter the command pumping loop |
|
SubProcessKernelObjects_Memory shrmem( &objs ); |
|
for ( |
|
void *pvMemory = NULL; |
|
NULL != ( pvMemory = shrmem.Lock() ); |
|
shrmem.Unlock() |
|
) |
|
{ |
|
// The memory is actually a command |
|
char const *szCommand = ( char const * ) pvMemory; |
|
|
|
if ( !stricmp( "keepalive", szCommand ) ) |
|
{ |
|
ZeroMemory( pvMemory, 4 * sizeof( DWORD ) ); |
|
continue; |
|
} |
|
|
|
if ( !stricmp( "quit", szCommand ) ) |
|
{ |
|
ZeroMemory( pvMemory, 4 * sizeof( DWORD ) ); |
|
return 0; |
|
} |
|
|
|
CmdSink::IResponse *pResponse = NULL; |
|
if ( InterceptFxc::TryExecuteCommand( szCommand, &pResponse ) ) |
|
{ |
|
byte *pBytes = ( byte * ) pvMemory; |
|
|
|
// Result |
|
DWORD dwSucceededResult = pResponse->Succeeded() ? 1 : 0; |
|
* ( DWORD * ) pBytes = dwSucceededResult; |
|
pBytes += sizeof( DWORD ); |
|
|
|
// Result buffer len |
|
DWORD dwBufferLength = pResponse->GetResultBufferLen(); |
|
* ( DWORD * ) pBytes = dwBufferLength; |
|
pBytes += sizeof( DWORD ); |
|
|
|
// Result buffer |
|
const void *pvResultBuffer = pResponse->GetResultBuffer(); |
|
memcpy( pBytes, pvResultBuffer, dwBufferLength ); |
|
pBytes += dwBufferLength; |
|
|
|
// Listing - copy string |
|
const char *szListing = pResponse->GetListing(); |
|
if ( szListing ) |
|
{ |
|
while ( 0 != ( * ( pBytes ++ ) = * ( szListing ++ ) ) ) |
|
{ |
|
NULL; |
|
} |
|
} |
|
else |
|
{ |
|
* ( pBytes ++ ) = 0; |
|
} |
|
} |
|
else |
|
{ |
|
ZeroMemory( pvMemory, 4 * sizeof( DWORD ) ); |
|
} |
|
} |
|
|
|
return -2; |
|
}
|
|
|