Source code of Windows XP (NT5)
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.

346 lines
17 KiB

  1. /*======================================================================================//
  2. | //
  3. |Copyright (c) 1998, 1999 Sequent Computer Systems, Incorporated. All rights reserved. //
  4. | //
  5. |Description: //
  6. | //
  7. |---------------------------------------------------------------------------------------//
  8. | This file implements the CProcCon class methods defined in ProcConSvc.h //
  9. |---------------------------------------------------------------------------------------//
  10. | //
  11. |Created: //
  12. | //
  13. | Jarl McDonald 07-98 //
  14. | //
  15. |Revision History: //
  16. | //
  17. |=======================================================================================*/
  18. #include "ProcConSvc.h"
  19. // CProcCon Constructor
  20. // Note: this function runs as part of service start so keep it quick!
  21. CProcCon::CProcCon( void ) : m_ready( FALSE ), m_shutEvent( NULL ), m_versionInfo( NULL ),
  22. m_endEvent ( NULL ),
  23. m_shutDown( FALSE )
  24. {
  25. memset( &m_context, 0, sizeof(m_context) );
  26. m_hThread[USER_SERVER] = m_hThread[PROC_SERVER] = NULL;
  27. SYSTEM_INFO si;
  28. GetSystemInfo( &si );
  29. m_NumberOfProcessors = si.dwNumberOfProcessors;
  30. m_PageSize = si.dwPageSize;
  31. m_versionInfo = new CVersion( GetModuleHandle( NULL ) );
  32. PCBuildAdminSecAttr( m_secAttr );
  33. m_context.cDB = new CProcConDB( m_PageSize );
  34. if ( !m_context.cDB || !m_context.cDB->ReadyToRun() ||
  35. !m_versionInfo || !m_secAttr.lpSecurityDescriptor ) {
  36. PCLogMessage( PC_STARTUP_FAILED, EVENTLOG_ERROR_TYPE, 1, PROCCON_SVC_DISP_NAME );
  37. return;
  38. }
  39. m_shutEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
  40. m_endEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
  41. m_context.mgrDoneEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
  42. m_context.userDoneEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
  43. m_context.mediatorEvent = CreateEvent( &m_secAttr, FALSE, FALSE, PC_MEDIATOR_EVENT );
  44. if ( !m_shutEvent || !m_endEvent || !m_context.mgrDoneEvent || !m_context.userDoneEvent || !m_context.mediatorEvent ) {
  45. PCLogUnExError( m_context.mediatorEvent? TEXT("PCEvent") : PC_MEDIATOR_EVENT, TEXT("CreateEvent") );
  46. return;
  47. }
  48. // Allocate shared memory for mediator view of jobs...
  49. m_context.mediatorTableHandle = CreateFileMapping( HANDLE_FF_64, &m_secAttr, PAGE_READWRITE,
  50. 0, sizeof(PCMediateHdr), PC_MEDIATOR_FILEMAP );
  51. if ( !m_context.mediatorTableHandle ) {
  52. PCLogUnExError( PC_MEDIATOR_FILEMAP, TEXT("CreateMediatorMapping") );
  53. return;
  54. }
  55. m_context.mediatorTable = (PCMediateHdr *) MapViewOfFile( m_context.mediatorTableHandle,
  56. FILE_MAP_WRITE, 0, 0, 0 );
  57. if ( !m_context.mediatorTable ) {
  58. CloseHandle( m_context.mediatorTableHandle );
  59. m_context.mediatorTableHandle = NULL;
  60. PCLogUnExError( PC_MEDIATOR_FILEMAP, TEXT("MapMediatorJobData") );
  61. return;
  62. }
  63. m_context.mediatorTable->svcEventHandle = m_context.mediatorEvent;
  64. m_context.mediatorTable->svcPID = GetCurrentProcessId();
  65. // If mediator is not running, init shared memory, set up completion port, and start mediator...
  66. if ( !PCTestIsRunning( PC_MEDIATOR_EXCLUSION ) ) {
  67. memset( &m_context.mediatorTable->groupBlock, 0, sizeof(m_context.mediatorTable->groupBlock) );
  68. m_context.mediatorTable->lastCompKey = 0;
  69. m_context.completionPort = CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, NULL, 0 );
  70. if ( !m_context.completionPort )
  71. PCLogUnExError( TEXT("PCInit"), TEXT("CreateIoCompletionPort") );
  72. m_context.mediatorTable->svcPortHandle = m_context.completionPort;
  73. StartMediator();
  74. }
  75. // If mediator is already running...
  76. // recover our completion port by duplicating the handle...
  77. else {
  78. // Open mediator process so we can duplicate handles...
  79. m_context.mediatorTable->medProcessInfo.hProcess =
  80. OpenProcess( PROCESS_DUP_HANDLE, FALSE, m_context.mediatorTable->medProcessInfo.dwProcessId );
  81. // Recover our completion port by duplicating the handle...
  82. if ( !DuplicateHandle( m_context.mediatorTable->medProcessInfo.hProcess,
  83. m_context.mediatorTable->medPortHandle,
  84. GetCurrentProcess(),
  85. &m_context.mediatorTable->svcPortHandle,
  86. NULL,
  87. FALSE,
  88. DUPLICATE_SAME_ACCESS ) )
  89. PCLogUnExError( TEXT("PCInit"), TEXT("DupMediatorPortHandle") );
  90. m_context.completionPort = m_context.mediatorTable->svcPortHandle;
  91. // Map all job table blocks by duplicating the handles...
  92. m_context.mediatorTable->SvcChainBlocks();
  93. }
  94. CloseHandle( m_context.mediatorTable->medProcessInfo.hProcess );
  95. m_context.cPC = this;
  96. LaunchProcServer();
  97. LaunchUserServer();
  98. if (!ReadyToRun() )
  99. HardStop();
  100. }
  101. // CProcCon Destructor
  102. CProcCon::~CProcCon( void )
  103. {
  104. if ( m_context.cUser ) {
  105. WaitForSingleObject( m_context.userDoneEvent, 5000 );
  106. delete m_context.cUser;
  107. m_context.cUser = NULL;
  108. }
  109. if ( m_context.cMgr ) {
  110. WaitForSingleObject( m_context.mgrDoneEvent, 5000 );
  111. delete m_context.cMgr;
  112. m_context.cMgr = NULL;
  113. }
  114. if ( m_context.cDB ) {
  115. delete m_context.cDB;
  116. m_context.cDB = NULL;
  117. }
  118. if ( m_shutEvent ) {
  119. CloseHandle( m_shutEvent );
  120. m_shutEvent = NULL;
  121. }
  122. if ( m_endEvent ) {
  123. CloseHandle( m_endEvent );
  124. m_endEvent = NULL;
  125. }
  126. if ( m_versionInfo ) {
  127. delete m_versionInfo;
  128. m_versionInfo = NULL;
  129. }
  130. CloseHandle( m_context.mgrDoneEvent );
  131. CloseHandle( m_context.userDoneEvent );
  132. CloseHandle( m_context.mediatorEvent );
  133. CloseHandle( m_context.mediatorTableHandle );
  134. PCFreeSecAttr( m_secAttr );
  135. }
  136. //--------------------------------------------------------------------------------------------//
  137. // Function to determine if all CProcCon initial conditions have been met //
  138. // Input: None //
  139. // Returns: TRUE if ready, FALSE if not //
  140. //--------------------------------------------------------------------------------------------//
  141. BOOL CProcCon::ReadyToRun( void )
  142. {
  143. return m_context.cDB &&
  144. m_hThread[PROC_SERVER] &&
  145. m_hThread[USER_SERVER] &&
  146. m_secAttr.lpSecurityDescriptor;
  147. }
  148. //--------------------------------------------------------------------------------------------//
  149. // Function to start the ProcCon Mediator Process //
  150. // Input: None //
  151. // Returns: NT or ProcCon Error code //
  152. //--------------------------------------------------------------------------------------------//
  153. PCULONG32 CProcCon::StartMediator( void )
  154. {
  155. // Don't start if already running...
  156. if ( PCTestIsRunning( PC_MEDIATOR_EXCLUSION ) )
  157. return PCERROR_MEDIATOR_ALREADY_RUNNING;
  158. // Get our module name then replace base name with mediator base name...
  159. // (Thus mediator exe must be in the same location as the service exe).
  160. TCHAR path[MAX_PATH];
  161. if ( !GetModuleFileName( NULL, path, MAX_PATH ) ) {
  162. PCLogUnExError( TEXT("PCMediator"), TEXT("GetMediatorPath") );
  163. path[0] = 0;
  164. }
  165. for ( int i = _tcslen( path ); i; --i ) {
  166. if ( path[i] == TEXT('\\') ) { path[i + 1] = 0; break; }
  167. }
  168. _tcscat( path, PC_MEDIATOR_BASE_NAME );
  169. // Start mediator process -- don't quit if this fails...
  170. STARTUPINFO strtInfo;
  171. memset( &strtInfo, 0, sizeof(strtInfo) );
  172. strtInfo.cb = sizeof(strtInfo);
  173. if ( !CreateProcess( path, NULL, &m_secAttr, &m_secAttr, FALSE,
  174. CREATE_NEW_PROCESS_GROUP + CREATE_NO_WINDOW,
  175. NULL, NULL, &strtInfo, &m_context.mediatorTable->medProcessInfo ) ) {
  176. DWORD rc = GetLastError();
  177. PCLogUnExError( TEXT("PCMediator"), TEXT("CreateMediator") );
  178. return rc;
  179. }
  180. return ERROR_SUCCESS;
  181. }
  182. //--------------------------------------------------------------------------------------------//
  183. // Function to stop (kill) the ProcCon Mediator Process //
  184. // Input: None //
  185. // Returns: NT or ProcCon Error code //
  186. //--------------------------------------------------------------------------------------------//
  187. PCULONG32 CProcCon::StopMediator ( void )
  188. {
  189. DWORD rc = ERROR_SUCCESS;
  190. HANDLE hProc = OpenProcess( PROCESS_TERMINATE, FALSE, m_context.mediatorTable->medProcessInfo.dwProcessId );
  191. m_context.mediatorTable->medProcessInfo.hProcess = hProc;
  192. if ( !hProc ) {
  193. rc = GetLastError();
  194. if (rc == ERROR_INVALID_PARAMETER) rc = PCERROR_MEDIATOR_NOT_RUNNING;
  195. }
  196. else if ( !TerminateProcess( m_context.mediatorTable->medProcessInfo.hProcess, PCERROR_KILLED_BY_REQUEST ) )
  197. rc = GetLastError();
  198. if ( hProc )
  199. CloseHandle( hProc );
  200. return rc;
  201. }
  202. //--------------------------------------------------------------------------------------------//
  203. // Function to return system information //
  204. // Input: Buffer for information, locations for size and count (always 1) //
  205. // Returns: TRUE if shutdown requested, FALSE if not //
  206. //--------------------------------------------------------------------------------------------//
  207. void CProcCon::GetPCSystemInfo( PCSystemInfo *data, PCINT16 *itemLen, PCINT16 *itemCount )
  208. {
  209. *itemLen = sizeof(PCSystemInfo);
  210. *itemCount = 1;
  211. memset( data, 0, *itemLen );
  212. _tcsncpy( data->fileVersion, m_versionInfo->GetFileVersion(), VERSION_STRING_LEN );
  213. _tcsncpy( data->productVersion, m_versionInfo->GetProductVersion(), VERSION_STRING_LEN );
  214. _tcsncpy( data->fileFlags, m_versionInfo->GetFileFlags(), VERSION_STRING_LEN );
  215. _tcsncpy( data->medFileVersion, m_context.mediatorTable->medFileVersion, VERSION_STRING_LEN );
  216. _tcsncpy( data->medProductVersion, m_context.mediatorTable->medProductVersion, VERSION_STRING_LEN );
  217. _tcsncpy( data->medFileFlags, m_context.mediatorTable->medFileFlags, VERSION_STRING_LEN );
  218. data->fixedSignature = m_versionInfo->GetFixedSignature();
  219. data->fixedFileVersionMS = m_versionInfo->GetFixedFileVersionMS();
  220. data->fixedFileVersionLS = m_versionInfo->GetFixedFileVersionLS();
  221. data->fixedProductVersionMS = m_versionInfo->GetFixedProductVersionMS();
  222. data->fixedProductVersionLS = m_versionInfo->GetFixedProductVersionLS();
  223. data->fixedFileFlags = m_versionInfo->GetFixedFileFlags();
  224. data->fixedFileOS = m_versionInfo->GetFixedFileOS();
  225. data->fixedFileType = m_versionInfo->GetFixedFileType();
  226. data->fixedFileSubtype = m_versionInfo->GetFixedFileSubtype();
  227. data->fixedFileDateMS = m_versionInfo->GetFixedFileDateMS();
  228. data->fixedFileDateLS = m_versionInfo->GetFixedFileDateLS();
  229. data->sysParms.manageIntervalSeconds = m_context.cDB->GetPollDelaySeconds();
  230. data->sysParms.timeoutValueMs = m_context.cUser->GetTimeout();
  231. data->sysParms.numberOfProcessors = m_NumberOfProcessors;
  232. data->sysParms.memoryPageSize = m_PageSize;
  233. data->sysParms.processorMask = m_context.cMgr->GetSystemMask();
  234. }
  235. //--------------------------------------------------------------------------------------------//
  236. // CProcCon thread function -- this function runs in its own thread //
  237. // Input: None //
  238. // Returns: Nothing //
  239. // Note: All ProcCon work is done in the user communication and process management //
  240. // threads so this fcn has only an oversight role. //
  241. //--------------------------------------------------------------------------------------------//
  242. void CProcCon::Run( void )
  243. {
  244. ResumeThread(m_hThread[USER_SERVER] );
  245. ResumeThread(m_hThread[PROC_SERVER] );
  246. WaitForSingleObject( m_endEvent, INFINITE );
  247. }
  248. //--------------------------------------------------------------------------------------------//
  249. // CProcCon function to handle 'hard' stop: failure before threads are released //
  250. // Input: Optional Thread Exit Code //
  251. // Returns: Nothing //
  252. // Note: This function forcefully close the user communication and process management //
  253. // threads. //
  254. //--------------------------------------------------------------------------------------------//
  255. void CProcCon::HardStop( PCULONG32 ExitCode )
  256. {
  257. if ( m_hThread[USER_SERVER] ) {
  258. TerminateThread(m_hThread[USER_SERVER], ExitCode );
  259. m_hThread[USER_SERVER] = NULL;
  260. }
  261. if ( m_hThread[PROC_SERVER] ) {
  262. TerminateThread(m_hThread[PROC_SERVER], ExitCode );
  263. m_hThread[PROC_SERVER] = NULL;
  264. }
  265. }
  266. //--------------------------------------------------------------------------------------------//
  267. // Function called by service stop when stop requested //
  268. // Input: None //
  269. // Returns: Nothing //
  270. // Note: this function runs as part of service stop //
  271. //--------------------------------------------------------------------------------------------//
  272. void CProcCon::Stop( void )
  273. {
  274. if ( m_shutEvent ) {
  275. m_shutDown = TRUE;
  276. SetEvent( m_shutEvent );
  277. WaitForMultipleObjects( ENTRY_COUNT(m_hThread), m_hThread, TRUE, 30000 );
  278. SetEvent( m_endEvent );
  279. }
  280. }
  281. //--------------------------------------------------------------------------------------------//
  282. // Function to start the Process Management thread //
  283. // Input: None //
  284. // Returns: Nothing //
  285. // Note: this function runs as part of service start so it must be quick. //
  286. //--------------------------------------------------------------------------------------------//
  287. void CProcCon::LaunchProcServer( void )
  288. {
  289. m_hThread[PROC_SERVER] = CreateThread( NULL, 0, &PCProcServer, &m_context, CREATE_SUSPENDED, NULL );
  290. if ( !m_hThread[PROC_SERVER] )
  291. PCLogUnExError( TEXT("PCProcServer"), TEXT("CreateThread") );
  292. }
  293. //--------------------------------------------------------------------------------------------//
  294. // Function to start the User Communication thread //
  295. // Input: None //
  296. // Returns: Nothing //
  297. // Note: this function runs as part of service start so it must be quick. //
  298. //--------------------------------------------------------------------------------------------//
  299. void CProcCon::LaunchUserServer( void )
  300. {
  301. m_hThread[USER_SERVER] = CreateThread( NULL, 0, &PCUserServer, &m_context, CREATE_SUSPENDED, NULL );
  302. if ( !m_hThread[USER_SERVER] )
  303. PCLogUnExError( TEXT("PCUserServer"), TEXT("CreateThread") );
  304. }
  305. // End of CProcCon.cpp
  306. //============================================================================J McDonald fecit====//