/*======================================================================================// | // |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====//