windows-nt/Source/XPSP1/NT/sdktools/proccon/service/cproccon.cpp

347 lines
17 KiB
C++
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*======================================================================================//
| //
|Copyright (c) 1998, 1999 Sequent Computer Systems, Incorporated. All rights reserved. //
| //
|Description: //
| //
|---------------------------------------------------------------------------------------//
| This file implements the CProcCon class methods defined in ProcConSvc.h //
|---------------------------------------------------------------------------------------//
| //
|Created: //
| //
| Jarl McDonald 07-98 //
| //
|Revision History: //
| //
|=======================================================================================*/
#include "ProcConSvc.h"
// CProcCon Constructor
// Note: this function runs as part of service start so keep it quick!
CProcCon::CProcCon( void ) : m_ready( FALSE ), m_shutEvent( NULL ), m_versionInfo( NULL ),
m_endEvent ( NULL ),
m_shutDown( FALSE )
{
memset( &m_context, 0, sizeof(m_context) );
m_hThread[USER_SERVER] = m_hThread[PROC_SERVER] = NULL;
SYSTEM_INFO si;
GetSystemInfo( &si );
m_NumberOfProcessors = si.dwNumberOfProcessors;
m_PageSize = si.dwPageSize;
m_versionInfo = new CVersion( GetModuleHandle( NULL ) );
PCBuildAdminSecAttr( m_secAttr );
m_context.cDB = new CProcConDB( m_PageSize );
if ( !m_context.cDB || !m_context.cDB->ReadyToRun() ||
!m_versionInfo || !m_secAttr.lpSecurityDescriptor ) {
PCLogMessage( PC_STARTUP_FAILED, EVENTLOG_ERROR_TYPE, 1, PROCCON_SVC_DISP_NAME );
return;
}
m_shutEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
m_endEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
m_context.mgrDoneEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
m_context.userDoneEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
m_context.mediatorEvent = CreateEvent( &m_secAttr, FALSE, FALSE, PC_MEDIATOR_EVENT );
if ( !m_shutEvent || !m_endEvent || !m_context.mgrDoneEvent || !m_context.userDoneEvent || !m_context.mediatorEvent ) {
PCLogUnExError( m_context.mediatorEvent? TEXT("PCEvent") : PC_MEDIATOR_EVENT, TEXT("CreateEvent") );
return;
}
// Allocate shared memory for mediator view of jobs...
m_context.mediatorTableHandle = CreateFileMapping( HANDLE_FF_64, &m_secAttr, PAGE_READWRITE,
0, sizeof(PCMediateHdr), PC_MEDIATOR_FILEMAP );
if ( !m_context.mediatorTableHandle ) {
PCLogUnExError( PC_MEDIATOR_FILEMAP, TEXT("CreateMediatorMapping") );
return;
}
m_context.mediatorTable = (PCMediateHdr *) MapViewOfFile( m_context.mediatorTableHandle,
FILE_MAP_WRITE, 0, 0, 0 );
if ( !m_context.mediatorTable ) {
CloseHandle( m_context.mediatorTableHandle );
m_context.mediatorTableHandle = NULL;
PCLogUnExError( PC_MEDIATOR_FILEMAP, TEXT("MapMediatorJobData") );
return;
}
m_context.mediatorTable->svcEventHandle = m_context.mediatorEvent;
m_context.mediatorTable->svcPID = GetCurrentProcessId();
// If mediator is not running, init shared memory, set up completion port, and start mediator...
if ( !PCTestIsRunning( PC_MEDIATOR_EXCLUSION ) ) {
memset( &m_context.mediatorTable->groupBlock, 0, sizeof(m_context.mediatorTable->groupBlock) );
m_context.mediatorTable->lastCompKey = 0;
m_context.completionPort = CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, NULL, 0 );
if ( !m_context.completionPort )
PCLogUnExError( TEXT("PCInit"), TEXT("CreateIoCompletionPort") );
m_context.mediatorTable->svcPortHandle = m_context.completionPort;
StartMediator();
}
// If mediator is already running...
// recover our completion port by duplicating the handle...
else {
// Open mediator process so we can duplicate handles...
m_context.mediatorTable->medProcessInfo.hProcess =
OpenProcess( PROCESS_DUP_HANDLE, FALSE, m_context.mediatorTable->medProcessInfo.dwProcessId );
// Recover our completion port by duplicating the handle...
if ( !DuplicateHandle( m_context.mediatorTable->medProcessInfo.hProcess,
m_context.mediatorTable->medPortHandle,
GetCurrentProcess(),
&m_context.mediatorTable->svcPortHandle,
NULL,
FALSE,
DUPLICATE_SAME_ACCESS ) )
PCLogUnExError( TEXT("PCInit"), TEXT("DupMediatorPortHandle") );
m_context.completionPort = m_context.mediatorTable->svcPortHandle;
// Map all job table blocks by duplicating the handles...
m_context.mediatorTable->SvcChainBlocks();
}
CloseHandle( m_context.mediatorTable->medProcessInfo.hProcess );
m_context.cPC = this;
LaunchProcServer();
LaunchUserServer();
if (!ReadyToRun() )
HardStop();
}
// CProcCon Destructor
CProcCon::~CProcCon( void )
{
if ( m_context.cUser ) {
WaitForSingleObject( m_context.userDoneEvent, 5000 );
delete m_context.cUser;
m_context.cUser = NULL;
}
if ( m_context.cMgr ) {
WaitForSingleObject( m_context.mgrDoneEvent, 5000 );
delete m_context.cMgr;
m_context.cMgr = NULL;
}
if ( m_context.cDB ) {
delete m_context.cDB;
m_context.cDB = NULL;
}
if ( m_shutEvent ) {
CloseHandle( m_shutEvent );
m_shutEvent = NULL;
}
if ( m_endEvent ) {
CloseHandle( m_endEvent );
m_endEvent = NULL;
}
if ( m_versionInfo ) {
delete m_versionInfo;
m_versionInfo = NULL;
}
CloseHandle( m_context.mgrDoneEvent );
CloseHandle( m_context.userDoneEvent );
CloseHandle( m_context.mediatorEvent );
CloseHandle( m_context.mediatorTableHandle );
PCFreeSecAttr( m_secAttr );
}
//--------------------------------------------------------------------------------------------//
// Function to determine if all CProcCon initial conditions have been met //
// Input: None //
// Returns: TRUE if ready, FALSE if not //
//--------------------------------------------------------------------------------------------//
BOOL CProcCon::ReadyToRun( void )
{
return m_context.cDB &&
m_hThread[PROC_SERVER] &&
m_hThread[USER_SERVER] &&
m_secAttr.lpSecurityDescriptor;
}
//--------------------------------------------------------------------------------------------//
// Function to start the ProcCon Mediator Process //
// Input: None //
// Returns: NT or ProcCon Error code //
//--------------------------------------------------------------------------------------------//
PCULONG32 CProcCon::StartMediator( void )
{
// Don't start if already running...
if ( PCTestIsRunning( PC_MEDIATOR_EXCLUSION ) )
return PCERROR_MEDIATOR_ALREADY_RUNNING;
// Get our module name then replace base name with mediator base name...
// (Thus mediator exe must be in the same location as the service exe).
TCHAR path[MAX_PATH];
if ( !GetModuleFileName( NULL, path, MAX_PATH ) ) {
PCLogUnExError( TEXT("PCMediator"), TEXT("GetMediatorPath") );
path[0] = 0;
}
for ( int i = _tcslen( path ); i; --i ) {
if ( path[i] == TEXT('\\') ) { path[i + 1] = 0; break; }
}
_tcscat( path, PC_MEDIATOR_BASE_NAME );
// Start mediator process -- don't quit if this fails...
STARTUPINFO strtInfo;
memset( &strtInfo, 0, sizeof(strtInfo) );
strtInfo.cb = sizeof(strtInfo);
if ( !CreateProcess( path, NULL, &m_secAttr, &m_secAttr, FALSE,
CREATE_NEW_PROCESS_GROUP + CREATE_NO_WINDOW,
NULL, NULL, &strtInfo, &m_context.mediatorTable->medProcessInfo ) ) {
DWORD rc = GetLastError();
PCLogUnExError( TEXT("PCMediator"), TEXT("CreateMediator") );
return rc;
}
return ERROR_SUCCESS;
}
//--------------------------------------------------------------------------------------------//
// Function to stop (kill) the ProcCon Mediator Process //
// Input: None //
// Returns: NT or ProcCon Error code //
//--------------------------------------------------------------------------------------------//
PCULONG32 CProcCon::StopMediator ( void )
{
DWORD rc = ERROR_SUCCESS;
HANDLE hProc = OpenProcess( PROCESS_TERMINATE, FALSE, m_context.mediatorTable->medProcessInfo.dwProcessId );
m_context.mediatorTable->medProcessInfo.hProcess = hProc;
if ( !hProc ) {
rc = GetLastError();
if (rc == ERROR_INVALID_PARAMETER) rc = PCERROR_MEDIATOR_NOT_RUNNING;
}
else if ( !TerminateProcess( m_context.mediatorTable->medProcessInfo.hProcess, PCERROR_KILLED_BY_REQUEST ) )
rc = GetLastError();
if ( hProc )
CloseHandle( hProc );
return rc;
}
//--------------------------------------------------------------------------------------------//
// Function to return system information //
// Input: Buffer for information, locations for size and count (always 1) //
// Returns: TRUE if shutdown requested, FALSE if not //
//--------------------------------------------------------------------------------------------//
void CProcCon::GetPCSystemInfo( PCSystemInfo *data, PCINT16 *itemLen, PCINT16 *itemCount )
{
*itemLen = sizeof(PCSystemInfo);
*itemCount = 1;
memset( data, 0, *itemLen );
_tcsncpy( data->fileVersion, m_versionInfo->GetFileVersion(), VERSION_STRING_LEN );
_tcsncpy( data->productVersion, m_versionInfo->GetProductVersion(), VERSION_STRING_LEN );
_tcsncpy( data->fileFlags, m_versionInfo->GetFileFlags(), VERSION_STRING_LEN );
_tcsncpy( data->medFileVersion, m_context.mediatorTable->medFileVersion, VERSION_STRING_LEN );
_tcsncpy( data->medProductVersion, m_context.mediatorTable->medProductVersion, VERSION_STRING_LEN );
_tcsncpy( data->medFileFlags, m_context.mediatorTable->medFileFlags, VERSION_STRING_LEN );
data->fixedSignature = m_versionInfo->GetFixedSignature();
data->fixedFileVersionMS = m_versionInfo->GetFixedFileVersionMS();
data->fixedFileVersionLS = m_versionInfo->GetFixedFileVersionLS();
data->fixedProductVersionMS = m_versionInfo->GetFixedProductVersionMS();
data->fixedProductVersionLS = m_versionInfo->GetFixedProductVersionLS();
data->fixedFileFlags = m_versionInfo->GetFixedFileFlags();
data->fixedFileOS = m_versionInfo->GetFixedFileOS();
data->fixedFileType = m_versionInfo->GetFixedFileType();
data->fixedFileSubtype = m_versionInfo->GetFixedFileSubtype();
data->fixedFileDateMS = m_versionInfo->GetFixedFileDateMS();
data->fixedFileDateLS = m_versionInfo->GetFixedFileDateLS();
data->sysParms.manageIntervalSeconds = m_context.cDB->GetPollDelaySeconds();
data->sysParms.timeoutValueMs = m_context.cUser->GetTimeout();
data->sysParms.numberOfProcessors = m_NumberOfProcessors;
data->sysParms.memoryPageSize = m_PageSize;
data->sysParms.processorMask = m_context.cMgr->GetSystemMask();
}
//--------------------------------------------------------------------------------------------//
// CProcCon thread function -- this function runs in its own thread //
// Input: None //
// Returns: Nothing //
// Note: All ProcCon work is done in the user communication and process management //
// threads so this fcn has only an oversight role. //
//--------------------------------------------------------------------------------------------//
void CProcCon::Run( void )
{
ResumeThread(m_hThread[USER_SERVER] );
ResumeThread(m_hThread[PROC_SERVER] );
WaitForSingleObject( m_endEvent, INFINITE );
}
//--------------------------------------------------------------------------------------------//
// CProcCon function to handle 'hard' stop: failure before threads are released //
// Input: Optional Thread Exit Code //
// Returns: Nothing //
// Note: This function forcefully close the user communication and process management //
// threads. //
//--------------------------------------------------------------------------------------------//
void CProcCon::HardStop( PCULONG32 ExitCode )
{
if ( m_hThread[USER_SERVER] ) {
TerminateThread(m_hThread[USER_SERVER], ExitCode );
m_hThread[USER_SERVER] = NULL;
}
if ( m_hThread[PROC_SERVER] ) {
TerminateThread(m_hThread[PROC_SERVER], ExitCode );
m_hThread[PROC_SERVER] = NULL;
}
}
//--------------------------------------------------------------------------------------------//
// Function called by service stop when stop requested //
// Input: None //
// Returns: Nothing //
// Note: this function runs as part of service stop //
//--------------------------------------------------------------------------------------------//
void CProcCon::Stop( void )
{
if ( m_shutEvent ) {
m_shutDown = TRUE;
SetEvent( m_shutEvent );
WaitForMultipleObjects( ENTRY_COUNT(m_hThread), m_hThread, TRUE, 30000 );
SetEvent( m_endEvent );
}
}
//--------------------------------------------------------------------------------------------//
// Function to start the Process Management thread //
// Input: None //
// Returns: Nothing //
// Note: this function runs as part of service start so it must be quick. //
//--------------------------------------------------------------------------------------------//
void CProcCon::LaunchProcServer( void )
{
m_hThread[PROC_SERVER] = CreateThread( NULL, 0, &PCProcServer, &m_context, CREATE_SUSPENDED, NULL );
if ( !m_hThread[PROC_SERVER] )
PCLogUnExError( TEXT("PCProcServer"), TEXT("CreateThread") );
}
//--------------------------------------------------------------------------------------------//
// Function to start the User Communication thread //
// Input: None //
// Returns: Nothing //
// Note: this function runs as part of service start so it must be quick. //
//--------------------------------------------------------------------------------------------//
void CProcCon::LaunchUserServer( void )
{
m_hThread[USER_SERVER] = CreateThread( NULL, 0, &PCUserServer, &m_context, CREATE_SUSPENDED, NULL );
if ( !m_hThread[USER_SERVER] )
PCLogUnExError( TEXT("PCUserServer"), TEXT("CreateThread") );
}
// End of CProcCon.cpp
//============================================================================J McDonald fecit====//