mirror of
https://github.com/nillerusr/source-engine.git
synced 2026-08-08 01:39:36 +00:00
1
This commit is contained in:
@@ -0,0 +1,303 @@
|
||||
//========= 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;
|
||||
}
|
||||
Reference in New Issue
Block a user