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.

1788 lines
89 KiB

  1. /*======================================================================================//
  2. | //
  3. |Copyright (c) 1998, 1999 Sequent Computer Systems, Incorporated //
  4. | //
  5. |Description: //
  6. | //
  7. |---------------------------------------------------------------------------------------//
  8. | This file implements the CProcConMgr 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. #include <psapi.h>
  20. // Constructor
  21. // Note: this function runs as part of service start so keep it quick!
  22. CProcConMgr::CProcConMgr( PCContext *ctxt ) :
  23. m_mediatorEvent( ctxt->mediatorEvent ),
  24. m_mediatorTable( ctxt->mediatorTable ),
  25. m_cPC( *ctxt->cPC ), m_cDB( *ctxt->cDB ),
  26. m_rawProcList( NULL ), m_rawProcCount( 0 ),
  27. m_procManagedCount( 0 ), m_jobManagedCount( 0 ),
  28. m_procAnchor( NULL ), m_jobAnchor( NULL ),
  29. m_reportThread( NULL ),
  30. m_systemMask( 1 ), m_sequencer( 1 )
  31. {
  32. ULONG_PTR mask;
  33. InitializeCriticalSection( &m_mgCSMgrLists );
  34. PCBuildAdminSecAttr( m_secAttr );
  35. GetProcessAffinityMask( GetCurrentProcess(), &mask, &m_systemMask );
  36. m_assocPort.CompletionPort = ctxt->completionPort;
  37. if ( m_assocPort.CompletionPort ) {
  38. m_reportThread = CreateThread( NULL, 10000, &JobReporter, this, 0, NULL );
  39. if ( !m_reportThread ) {
  40. PCLogUnExError( TEXT("JobReporter"), TEXT("CreateThread") );
  41. CloseHandle( m_assocPort.CompletionPort );
  42. m_assocPort.CompletionPort = NULL;
  43. }
  44. }
  45. }
  46. // Destructor
  47. CProcConMgr::~CProcConMgr( void )
  48. {
  49. EnterCriticalSection( &m_mgCSMgrLists );
  50. if ( m_rawProcList ) delete [] m_rawProcList;
  51. for ( ManagedProc *nextProc, *proc = m_procAnchor; proc; proc = nextProc ) {
  52. nextProc = proc->next;
  53. delete proc;
  54. }
  55. for ( ManagedJob *nextJob, *job = m_jobAnchor; job; job = nextJob ) {
  56. nextJob = job->next;
  57. delete job;
  58. }
  59. m_jobAnchor = NULL;
  60. m_procAnchor = NULL;
  61. m_jobManagedCount = m_procManagedCount = 0;
  62. PCFreeSecAttr( m_secAttr );
  63. LeaveCriticalSection( &m_mgCSMgrLists );
  64. DeleteCriticalSection( &m_mgCSMgrLists );
  65. }
  66. //--------------------------------------------------------------------------------------------//
  67. // Function to determine if all CProcConMgr initial conditions have been met //
  68. // Input: None //
  69. // Returns: TRUE if ready, FALSE if not //
  70. //--------------------------------------------------------------------------------------------//
  71. BOOL CProcConMgr::ReadyToRun( void )
  72. {
  73. return m_secAttr.lpSecurityDescriptor != NULL;
  74. }
  75. //--------------------------------------------------------------------------------------------//
  76. // The Process Management thread //
  77. // Input: nothing //
  78. // Returns: 0 if successful, 1 if not //
  79. //--------------------------------------------------------------------------------------------//
  80. PCULONG32 CProcConMgr::Run( void )
  81. {
  82. HANDLE objList[] = { m_cPC.GetShutEvent(), m_cDB.GetDbEvent() };
  83. // Trigger database load...
  84. if ( m_cDB.LoadRules( m_cDB.LOADFLAG_ALL_RULES ) != ERROR_SUCCESS )
  85. return 1;
  86. // ProcCon main process loop...
  87. for ( ;; ) {
  88. // Discover all running processes/jobs...
  89. Discover();
  90. // Apply management rules...
  91. Manage();
  92. PCULONG32 event = WaitForMultipleObjects( ENTRY_COUNT(objList), objList, FALSE, m_cDB.GetPollDelay() );
  93. if ( event == WAIT_FAILED ) {
  94. PCLogUnExError( TEXT("PCManager"), TEXT("Wait") );
  95. break;
  96. }
  97. // if wait ended due to db update or timeout we loop, for shutdown we stop looping...
  98. if ( event - WAIT_OBJECT_0 == 0 ) { // we got shutdown event
  99. if ( m_assocPort.CompletionPort )
  100. PostQueuedCompletionStatus( m_assocPort.CompletionPort, 0, 0, NULL );
  101. Sleep( 1000 );
  102. break;
  103. }
  104. } // end for
  105. return 0;
  106. }
  107. //--------------------------------------------------------------------------------------------//
  108. // Job Object Completion Port: function to listen to the job completion port and handle msgs. //
  109. // Input: pointer to CProcConMgr class (function is static) //
  110. // Returns: nothing -- runs until shutdown requested //
  111. // Note: this is a static member function and thus does not have a 'this' context. //
  112. //--------------------------------------------------------------------------------------------//
  113. PCULONG32 __stdcall CProcConMgr::JobReporter( void *inPtr ) {
  114. CProcConMgr &cMgr = *((CProcConMgr *) inPtr);
  115. OVERLAPPED *data;
  116. DWORD msgId;
  117. ULONG_PTR compKey;
  118. while ( GetQueuedCompletionStatus( cMgr.GetComplPort(), &msgId, &compKey, &data, INFINITE ) ) {
  119. if ( !compKey ) break; // shutdown requested
  120. EnterCriticalSection( cMgr.GetListCSPtr() );
  121. for ( ManagedJob *job = cMgr.GetJobAnchor(); job && compKey != job->compKey; job = job->next ) ;
  122. // If we found the job, proceed to handle the event...
  123. if ( job ) {
  124. TCHAR value[24], pid[24];
  125. const TCHAR *msgs[] = { PROCCON_SVC_DISP_NAME, job->fullJobName, value, pid };
  126. // Make sure we have the latest job definition...
  127. PCJobDef *jobDef;
  128. if ( cMgr.m_cDB.GetJobMgmtDefs( &jobDef, &job->jName ) ) { // Returns 0 if job definition not found
  129. cMgr.UpdateJobEntry( *job, jobDef );
  130. delete [] jobDef;
  131. }
  132. // Make sure we have the latest job stats...
  133. cMgr.UpdateJobObjInfo( *job );
  134. switch ( msgId ) {
  135. //******** job time limit hit, data is NULL
  136. case JOB_OBJECT_MSG_END_OF_JOB_TIME: {
  137. _i64tot( PCLargeIntToInt64( job->JOExtendedLimitInfo.BasicLimitInformation.PerJobUserTimeLimit ) / 10000, value, 10 );
  138. // Check for termination or just post...
  139. DWORD rc = WaitForSingleObject( job->jobHandle, 0 );
  140. // If we're only posting the limit exceeded, issue msg, suppress future msgs...
  141. if ( rc == WAIT_TIMEOUT ) {
  142. PCLogMessage( PC_SERVICE_JOB_HIT_TIME_LIMIT_NOTERM, EVENTLOG_INFORMATION_TYPE,
  143. ENTRY_COUNT(msgs), msgs );
  144. job->timeExceededReported = TRUE; // suppress additional reports
  145. }
  146. // If we're posting the limit exceeded with all procs terminated, issue msg, clear state...
  147. else {
  148. PCLogMessage( PC_SERVICE_JOB_HIT_TIME_LIMIT_TERMINATED, EVENTLOG_INFORMATION_TYPE,
  149. ENTRY_COUNT(msgs), msgs );
  150. job->curJobTimeLimitCNS = 0; // clear limit to force update
  151. cMgr.ApplyJobMgmt( *job ); // go re-apply time limit to reset
  152. }
  153. break;
  154. }
  155. //******** proc time limit hit, proc already being terminated, data = PID
  156. case JOB_OBJECT_MSG_END_OF_PROCESS_TIME:
  157. _i64tot( (ULONG_PTR) data, pid, 10 );
  158. _i64tot( PCLargeIntToInt64( job->JOExtendedLimitInfo.BasicLimitInformation.PerProcessUserTimeLimit ) / 10000, value, 10 );
  159. PCLogMessage( PC_SERVICE_PROC_HIT_TIME_LIMIT, EVENTLOG_INFORMATION_TYPE,
  160. ENTRY_COUNT(msgs), msgs );
  161. break;
  162. //******** proc count limit hit, data = NULL
  163. case JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT:
  164. _ltot( job->JOExtendedLimitInfo.BasicLimitInformation.ActiveProcessLimit, value, 10 );
  165. PCLogMessage( PC_SERVICE_JOB_HIT_COUNT_LIMIT, EVENTLOG_INFORMATION_TYPE,
  166. ENTRY_COUNT(msgs), msgs );
  167. break;
  168. //******** proc count hit 0, data = NULL
  169. case JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO:
  170. if ( job->jobParms.mFlags & PCMFLAG_END_JOB_WHEN_EMPTY )
  171. cMgr.JobIsEmpty( job ); // job should be deleted after this call!
  172. break;
  173. //******** process created in job or added to job, data = PID
  174. case JOB_OBJECT_MSG_NEW_PROCESS: {
  175. PID_VALUE newPid = (ULONG_PTR) data;
  176. // See if the proc is one of our managed procs (will be if entry is for adding, not creating)...
  177. for ( ManagedProc *Proc = cMgr.GetProcAnchor();
  178. Proc && Proc->pStats.pid != newPid;
  179. Proc = Proc->next ) ;
  180. // if not found, not in a job, or not in this job report on its creation...
  181. if ( !Proc || !Proc->reportAdd ) {
  182. TCHAR procName[PROC_NAME_LEN + 1], imageName[IMAGE_NAME_LEN + 1], pid[32];
  183. const TCHAR *pmsgs[] = { PROCCON_SVC_DISP_NAME, job->fullJobName, procName, pid, imageName };
  184. _i64tot( (ULONG_PTR) data, pid, 10 );
  185. // Make sure new proc is in our raw proc list...
  186. cMgr.Discover();
  187. // Now locate the proc by PID...
  188. for ( PCULONG32 i = 0;
  189. i < cMgr.GetRawProcCount() && newPid != cMgr.GetRawProcEntry( i ).pId;
  190. ++i ) ;
  191. // If found, extract process and image names...
  192. if ( i < cMgr.GetRawProcCount() ) {
  193. _tcscpy( procName, cMgr.GetRawProcEntry( i ).pName );
  194. _tcscpy( imageName, cMgr.GetRawProcEntry( i ).imageName );
  195. }
  196. // If not found (process that terminated already), use "unknown" (not localized)...
  197. else {
  198. _tcscpy( procName, PROCCON_UNKNOWN_PROCESS );
  199. _tcscpy( imageName, PROCCON_UNKNOWN_PROCESS );
  200. }
  201. // Now report that this proc was created in ths job...
  202. PCLogMessage( PC_SERVICE_ADD_NONPC_PROC_TO_JOB, EVENTLOG_INFORMATION_TYPE,
  203. ENTRY_COUNT(pmsgs), pmsgs );
  204. }
  205. else if ( Proc->reportAdd ) {
  206. const TCHAR *msgs[] = { PROCCON_SVC_DISP_NAME, Proc->pName, Proc->pidAsString,
  207. Proc->imageName, job->fullJobName };
  208. PCLogMessage( PC_SERVICE_ADD_PROC_TO_JOB, EVENTLOG_INFORMATION_TYPE, ENTRY_COUNT(msgs), msgs );
  209. }
  210. break;
  211. }
  212. //******** process exiting job, data = PID of exiting process
  213. case JOB_OBJECT_MSG_EXIT_PROCESS:
  214. break;
  215. //******** process exiting job, data = PID of exiting process
  216. case JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS:
  217. break;
  218. //******** proc memory limit hit, data = PID
  219. case JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT:
  220. if ( cMgr.NotTooSoon( job, MEM_REJECT_REPORT_LIMIT ) ) {
  221. _i64tot( (ULONG_PTR) data, pid, 10 );
  222. _i64tot( job->JOExtendedLimitInfo.ProcessMemoryLimit, value, 10 );
  223. PCLogMessage( PC_SERVICE_PROC_HIT_MEMORY_LIMIT, EVENTLOG_INFORMATION_TYPE,
  224. ENTRY_COUNT(msgs), msgs );
  225. }
  226. break;
  227. //******** job memory limit hit, data = PID of process that attempted to exceed limit
  228. case JOB_OBJECT_MSG_JOB_MEMORY_LIMIT:
  229. if ( cMgr.NotTooSoon( job, MEM_REJECT_REPORT_LIMIT ) ) {
  230. _i64tot( (ULONG_PTR) data, pid, 10 );
  231. _i64tot( job->JOExtendedLimitInfo.JobMemoryLimit, value, 10 );
  232. PCLogMessage( PC_SERVICE_JOB_HIT_MEMORY_LIMIT, EVENTLOG_INFORMATION_TYPE,
  233. ENTRY_COUNT(msgs), msgs );
  234. }
  235. break;
  236. default:
  237. break;
  238. } // end switch
  239. }
  240. LeaveCriticalSection( cMgr.GetListCSPtr() );
  241. }
  242. if ( !cMgr.m_cPC.GotShutdown() )
  243. PCLogUnExError( TEXT("JobReporter"), TEXT("GetQueuedCompletionStatus") );
  244. CloseHandle( cMgr.GetComplPort() );
  245. return 0;
  246. }
  247. //--------------------------------------------------------------------------------------------//
  248. // function to test memory exceeded reporting inteval is within limit seconds //
  249. // Input: pointer to managed job structure, limit seconds //
  250. // Returns: TRUE if not too soon (interval exceeds limit), FALSE otherwise //
  251. // Note: if the tick ctr has wrapped, we simply treat it is as 'not too soon' and unwrap //
  252. //--------------------------------------------------------------------------------------------//
  253. BOOL CProcConMgr::NotTooSoon( ManagedJob *job, PCULONG32 limit ) {
  254. PCULONG32 now = GetTickCount();
  255. BOOL rc = FALSE;
  256. if ( now < job->memRejectReportTime || ((now - job->memRejectReportTime) / 1000 >= limit) ) {
  257. rc = TRUE;
  258. job->memRejectReportTime = now;
  259. }
  260. return rc;
  261. }
  262. //--------------------------------------------------------------------------------------------//
  263. // function to close a job object when no longer in use //
  264. // Input: pointer to managed job structure //
  265. // Returns: nothing //
  266. // Note: Caller must hold manager list critical section. //
  267. //--------------------------------------------------------------------------------------------//
  268. void CProcConMgr::JobIsEmpty( ManagedJob *job ) {
  269. UpdateJobObjInfo( *job ); // Update stats incl proc count
  270. if ( job->JOBasicAndIoAcctInfo.BasicInfo.ActiveProcesses ) return; // done - no longer empty!
  271. m_mediatorTable->SvcCloseEntry( job->fullJobName );
  272. ManagedJob *lastJob, *thisJob;
  273. for ( lastJob = thisJob = m_jobAnchor; thisJob; lastJob = thisJob, thisJob = thisJob->next ) {
  274. if ( thisJob == job ) {
  275. if ( lastJob == m_jobAnchor ) m_jobAnchor = thisJob->next;
  276. else lastJob->next = thisJob->next;
  277. delete job;
  278. --m_jobManagedCount;
  279. break;
  280. }
  281. }
  282. }
  283. #define HIGHEST_SYSTEM_PID 31
  284. //--------------------------------------------------------------------------------------------//
  285. // function to discover all running processes and build a 'raw' list of them //
  286. // Input: none //
  287. // Returns: nothing -- the current raw process list is deleted and rebuilt //
  288. // Note: A 'raw' list simply consists of an entry per process containing at least the PID //
  289. // and the ProcCon process name. This list is used by the management fcns. //
  290. // Note 2: There are several choices for discovering what processes are running: //
  291. // Performance data registry interface (NT 3 and beyond), //
  292. // Performance data helper (NT 3 and beyond), //
  293. // PSAPI (NT 4 and beyond), //
  294. // Tool help library (NT 5). //
  295. // //
  296. // This function uses the PSAPI. Originally toolhelp32 was used but was too buggy. //
  297. //--------------------------------------------------------------------------------------------//
  298. void CProcConMgr::Discover( void ) {
  299. DWORD bytesListed, count, listCount = 512; // first pass is double this count
  300. DWORD *procList = NULL; // must track type used in EnumProcesses
  301. // Loop allocating (increasingly larger) buffer and enumerating processes until we see them all...
  302. do {
  303. // Free previous buffer, if any
  304. if ( procList ) delete [] procList;
  305. // Get a buffer we hope will be big enough (double previous size)...
  306. listCount *= 2;
  307. procList = new DWORD[listCount];
  308. // If complete failure, skip process enumeration...
  309. if ( !procList ) {
  310. PCLogNoMemory( TEXT("AllocTempRawProcList"), listCount * sizeof(*procList) ); // 7/28/2000 bugfix to report correct size
  311. return;
  312. }
  313. // Snapshot the process space...
  314. if ( !EnumProcesses( procList, listCount * sizeof(*procList), &bytesListed ) ) {
  315. PCLogUnExError( TEXT("PCDiscover"), TEXT("EnumProcesses") );
  316. delete [] procList;
  317. return;
  318. }
  319. count = bytesListed / sizeof(*procList);
  320. } while ( count == listCount );
  321. // Reset old process info...
  322. EnterCriticalSection( &m_mgCSMgrLists );
  323. if ( m_rawProcList ) delete [] m_rawProcList;
  324. m_rawProcCount = 0;
  325. // Allocate new raw process info list...
  326. m_rawProcList = new RawProcList[count];
  327. if ( !m_rawProcList ) {
  328. PCLogNoMemory( _T("AllocRawProcList"), sizeof(RawProcList) * count );
  329. LeaveCriticalSection( &m_mgCSMgrLists );
  330. delete [] procList;
  331. return;
  332. }
  333. memset( m_rawProcList, 0, sizeof(RawProcList) * count );
  334. // Walk the snapshot to extract data and determine process names from path names...
  335. TCHAR pathAndFile[MAX_PATH] = _T("");
  336. for ( DWORD proc = 0; proc < count; ++proc ) {
  337. HANDLE hProc = NULL;
  338. if (procList[proc] == 0) {
  339. _tcscpy( pathAndFile, PROCCON_SYSTEM_IDLE );
  340. }
  341. else if (procList[proc] <= HIGHEST_SYSTEM_PID) {
  342. _tcscpy( pathAndFile, PROCCON_SYSTEM_PROCESS );
  343. }
  344. else {
  345. hProc = OpenProcess( PROCESS_QUERY_INFORMATION // to get counters, aff, prio, etc.
  346. + PROCESS_VM_READ, // to get module information
  347. FALSE, procList[proc] );
  348. if ( hProc ) {
  349. if ( !GetModuleFileNameEx( hProc, NULL, pathAndFile, ENTRY_COUNT( pathAndFile ) ) &&
  350. !GetModuleBaseName( hProc, NULL, pathAndFile, ENTRY_COUNT( pathAndFile ) ) ) {
  351. PCLogUnExError( procList[proc], _T("GetModuleFile/BaseName") );
  352. }
  353. }
  354. else continue;
  355. }
  356. // Save process data and assign process name (alias)...
  357. RawProcList &le = m_rawProcList[m_rawProcCount];
  358. le.pId = procList[proc];
  359. m_cDB.AssignProcName( pathAndFile, &le.pName, &le.imageName );
  360. // If name assigned (not hidden or unretrievable) include this in result...
  361. if ( *le.pName ) ++m_rawProcCount;
  362. // If we have an open handle, retrieve additional information, then close
  363. if (hProc) {
  364. GetProcessTimes( hProc, &le.createTime, &le.exitTime, &le.kernelTime, &le.userTime );
  365. le.actualPriority = PCMapPriorityToPC( GetPriorityClass( hProc ) );
  366. ULONG_PTR aff;
  367. if ( !GetProcessAffinityMask( hProc, &aff, &m_systemMask ) )
  368. PCLogUnExError( procList[proc], TEXT("GetAffinityMask") );
  369. le.actualAffinity = aff;
  370. CloseHandle( hProc );
  371. }
  372. }
  373. delete [] procList;
  374. // Sort the raw process list...
  375. qsort( m_rawProcList, m_rawProcCount, sizeof(RawProcList), CompareRawProcList );
  376. // Update job information...
  377. for ( ManagedJob *job = m_jobAnchor; job; job = job->next )
  378. UpdateJobObjInfo( *job );
  379. LeaveCriticalSection( &m_mgCSMgrLists );
  380. }
  381. //--------------------------------------------------------------------------------------------//
  382. // function to apply ProcCon management rules to the system //
  383. // Input: nothing //
  384. // Returns: nothing -- process rules are applied as appropriate //
  385. // Note: entry conditions: //
  386. // o Running processes are listed in m_rawProcList (unless NULL), sorted by PID. //
  387. // o Managed processes from last pass are listed in m_procManagedList, unless NULL. //
  388. // o Managed jobs from last pass are listed in m_jobManagedList, unless NULL. //
  389. // o Defined jobs and processes are available from the DB component. //
  390. // o Counts of entries are in m_rawProcCount, m_procManagedCount, m_jobManagedCount. //
  391. // o No critical sections are held. //
  392. //--------------------------------------------------------------------------------------------//
  393. void CProcConMgr::Manage( void ) {
  394. // Step 1 -- get the current management definitions we are to work from...
  395. PCJobDef *jobDefs = NULL, *jHit;
  396. PCProcDef *procDefs = NULL, *pHit;
  397. PCULONG32 numJobDefs = m_cDB.GetJobMgmtDefs( &jobDefs );
  398. PCULONG32 numProcDefs = m_cDB.GetProcMgmtDefs( &procDefs );
  399. EnterCriticalSection( &m_mgCSMgrLists );
  400. // Step 2 -- allocate max possible space for a list of procs to be managed...
  401. ManagedProcItem *doProc = new ManagedProcItem[m_rawProcCount];
  402. PCULONG32 numProc = 0;
  403. if ( !doProc ) {
  404. PCLogNoMemory( TEXT("AllocManagedProcList"), sizeof(ManagedProcItem) * m_rawProcCount );
  405. delete [] jobDefs;
  406. delete [] procDefs;
  407. LeaveCriticalSection( &m_mgCSMgrLists );
  408. return;
  409. }
  410. // Step 3 -- locate processes in the current proc list needing management, place in managed list...
  411. PCULONG32 proc;
  412. if ( numProcDefs ) {
  413. for ( proc = 0; proc < m_rawProcCount; ++proc ) {
  414. // see if we have a definition for this proc name...
  415. pHit = (PCProcDef *) bsearch( m_rawProcList[proc].pName,
  416. procDefs,
  417. numProcDefs,
  418. sizeof(PCProcDef),
  419. CompareProcName );
  420. // A definition exists so save in our list...
  421. if ( pHit ) {
  422. doProc[numProc].pStats.pid = m_rawProcList[proc].pId;
  423. doProc[numProc].pStats.createTime = PCFileTimeToInt64( m_rawProcList[proc].createTime );
  424. doProc[numProc].pStats.TotalUserTime = PCFileTimeToInt64( m_rawProcList[proc].userTime );
  425. doProc[numProc].pStats.TotalKernelTime = PCFileTimeToInt64( m_rawProcList[proc].kernelTime );
  426. doProc[numProc].pDef = pHit;
  427. memcpy( doProc[numProc].imageName, m_rawProcList[proc].imageName, sizeof(doProc[0].imageName) );
  428. ++numProc;
  429. }
  430. }
  431. }
  432. // Step 4 -- For each proc to be managed:
  433. // a. Open process handle,
  434. // b. Get process create time to determine if process is 'new' or 'old',
  435. // c. If 'old', locate existing ManagedProc and re-apply management if needed.
  436. // d. If 'new', create ManagedProc/ManagedJob apply management rules.
  437. // e. Close handle(s).
  438. //
  439. // Note: At this point we have snapshots of all data we need and hold no critical sections.
  440. // This will permit API calls, etc. to proceed without delay.
  441. // Bump sequencer so we can tell which entries have gone away...
  442. ++m_sequencer;
  443. // For each proc to manage -- do it...
  444. HANDLE hProc = NULL;
  445. for ( proc = 0; proc < numProc; ++proc ) {
  446. BOOL isManaged = FALSE;
  447. if ( hProc ) CloseHandle( hProc );
  448. PID_VALUE pid = doProc[proc].pStats.pid;
  449. PCProcDef *def = doProc[proc].pDef;
  450. // Open process so we can manipulate it...
  451. hProc = OpenProcess( PROCESS_SET_QUOTA | PROCESS_TERMINATE | PROCESS_SET_INFORMATION | PROCESS_QUERY_INFORMATION,
  452. TRUE, (DWORD) pid ); // OpenProcess always uses 32-bit PID, even in Win64. May change!
  453. // If we can't open it, report error unless process is simply gone, then ignore entry...
  454. if ( !hProc ) {
  455. if ( GetLastError() != ERROR_INVALID_PARAMETER )
  456. PCLogUnExError( pid, TEXT("OpenProcess") );
  457. continue;
  458. }
  459. // We were able to open the process -- find or allocate a tracking entry for it.
  460. // The process is the same only if the pid and create time are the same...
  461. ManagedProc *pMProc = FindProcEntry( pid, doProc[proc].pStats.createTime );
  462. BOOL newProc = pMProc == NULL;
  463. if ( newProc ) {
  464. pMProc = new ManagedProc( def->procName, pid, doProc[proc].pStats.createTime );
  465. if ( !pMProc ) {
  466. PCLogNoMemory( TEXT("AllocManagedProc"), sizeof(ManagedProc) );
  467. continue;
  468. }
  469. }
  470. pMProc->pStats.TotalUserTime = doProc[proc].pStats.TotalUserTime;
  471. pMProc->pStats.TotalKernelTime = doProc[proc].pStats.TotalKernelTime;
  472. // Get actual priority, affinity, and image name...
  473. pMProc->actualPriority = PCMapPriorityToPC( GetPriorityClass( hProc ) );
  474. ULONG_PTR aff;
  475. GetProcessAffinityMask( hProc, &aff, &m_systemMask );
  476. pMProc->actualAffinity = aff;
  477. memcpy( pMProc->imageName, doProc[proc].imageName, sizeof(pMProc->imageName) );
  478. // Update our tracking entry for this process...
  479. UpdateProcEntry( *pMProc, *def, newProc );
  480. // If process is to be part of a job...
  481. TCHAR *job = def->memberOfJob;
  482. if ( def->mFlags & PCMFLAG_APPLY_JOB_MEMBERSHIP && *job ) {
  483. // Locate job definition...
  484. jHit = (PCJobDef *) bsearch( job, jobDefs, numJobDefs, sizeof(PCJobDef), CompareJobName );
  485. // Locate job tracking entry if it exists...
  486. ManagedJob *pMJob = FindJobEntry( job );
  487. BOOL newJob = pMJob == NULL;
  488. // If no entry found and we have a job definition, create new entry...
  489. if ( newJob && jHit ) {
  490. pMJob = new ManagedJob( job, m_mediatorTable );
  491. if ( !pMJob )
  492. PCLogNoMemory( TEXT("AllocManagedJob"), sizeof(ManagedJob) );
  493. }
  494. // If we now have a job entry, proceed to manage the process via the job......
  495. if ( pMJob ) {
  496. // If Proc is already in a job...
  497. if ( pMProc->isInJob ) {
  498. // if not in this job, say we can't move it (but only say it once)...
  499. if ( pMJob != pMProc->pMJob ) {
  500. if ( pMProc->pMJob && CompareJobName(pMJob->fullJobName, pMProc->lastAlreadyInJobErr) ) {
  501. const TCHAR *msgs[] = { PROCCON_SVC_DISP_NAME,
  502. pMProc->pName, pMProc->pidAsString, pMProc->imageName,
  503. pMJob->fullJobName, pMProc->pMJob->fullJobName };
  504. PCLogMessage( PC_SERVICE_ALREADY_IN_JOB, EVENTLOG_ERROR_TYPE, ENTRY_COUNT(msgs), msgs );
  505. memcpy( pMProc->lastAlreadyInJobErr, pMJob->fullJobName, sizeof(pMProc->lastAlreadyInJobErr) );
  506. }
  507. }
  508. // if in this job and job not updated this pass, just (re)set mgmt behavior...
  509. else if ( pMJob->sequence != m_sequencer ) { // this just prevents multiple calls for the same job
  510. UpdateJobEntry( *pMJob, jHit, newJob );
  511. UpdateJobObjInfo( *pMJob );
  512. ApplyJobMgmt( *pMJob );
  513. }
  514. isManaged = TRUE;
  515. }
  516. // Proc not already in any job...
  517. else {
  518. // If job object does not exist -- create it...
  519. if ( !pMJob->jobHandle ) {
  520. pMJob->jobHandle = CreateJobObject( &m_secAttr, pMJob->fullJobName );
  521. if ( pMJob->jobHandle && GetLastError() != ERROR_ALREADY_EXISTS ) {
  522. const TCHAR *msgs[] = { PROCCON_SVC_DISP_NAME, pMJob->fullJobName };
  523. PCLogMessage( PC_SERVICE_CREATE_JOB, EVENTLOG_INFORMATION_TYPE, ENTRY_COUNT(msgs), msgs );
  524. }
  525. m_mediatorTable->SvcAddEntry( pMJob->fullJobName, pMJob->compKey, m_secAttr ); // adds or updates
  526. }
  527. if ( !pMJob->jobHandle )
  528. PCLogUnExError( pMJob->fullJobName, TEXT("CreateJobObj") );
  529. else {
  530. // Update management parms with definition if any, apply mgmt to job obj, put proc in job...
  531. UpdateJobEntry( *pMJob, jHit, newJob );
  532. UpdateJobObjInfo( *pMJob );
  533. ApplyJobMgmt( *pMJob );
  534. if ( AssignProcessToJobObject( pMJob->jobHandle, hProc ) ) {
  535. pMProc->pMJob = pMJob;
  536. pMProc->isInJob = TRUE;
  537. pMProc->reportAdd = TRUE;
  538. isManaged = TRUE;
  539. }
  540. else if ( GetLastError() == ERROR_ACCESS_DENIED ) { // failed due to already in some other job
  541. FULL_JOB_NAME errName = TEXT("-unknown-");
  542. pMProc->pMJob = NULL; // set the job as 'unknown'
  543. pMProc->isInJob = TRUE; // we assume it is in some job
  544. // See if this proc is in a job of ours by matching pids...
  545. for ( ManagedJob *tstJob = m_jobAnchor; tstJob; tstJob = tstJob->next ) {
  546. if ( GetProcListForJob( *tstJob ) ) {
  547. for ( PCUINT32 pndx = 0;
  548. pndx < tstJob->JOProcListInfo->NumberOfProcessIdsInList;
  549. ++pndx ) {
  550. if ( pMProc->pStats.pid == (PID_VALUE) tstJob->JOProcListInfo->ProcessIdList[pndx] ) {
  551. memcpy( errName, tstJob->fullJobName, sizeof(errName) );
  552. pMProc->pMJob = tstJob;
  553. isManaged = TRUE;
  554. break;
  555. }
  556. }
  557. delete [] ((UCHAR *) tstJob->JOProcListInfo);
  558. tstJob->JOProcListInfo = NULL;
  559. }
  560. if ( isManaged ) break;
  561. }
  562. // If the job was not found or is not the job we expect, then report...
  563. if ( pMProc->pMJob != pMJob &&
  564. CompareJobName( pMJob->fullJobName, pMProc->lastAlreadyInJobErr ) ) {
  565. const TCHAR *msgs[] = { PROCCON_SVC_DISP_NAME,
  566. pMProc->pName, pMProc->pidAsString, pMProc->imageName,
  567. pMJob->fullJobName, errName };
  568. PCLogMessage( PC_SERVICE_ALREADY_IN_JOB, EVENTLOG_ERROR_TYPE, ENTRY_COUNT(msgs), msgs );
  569. memcpy( pMProc->lastAlreadyInJobErr, pMJob->fullJobName, sizeof(pMProc->lastAlreadyInJobErr) );
  570. }
  571. }
  572. else if ( GetLastError() != ERROR_NOT_ENOUGH_QUOTA ) // this will be reported via Compl Port
  573. PCLogUnExError( pid, TEXT("AssignProcToJobObj") );
  574. }
  575. }
  576. }
  577. }
  578. // If not managed as a job member for any reason, apply proc management rules...
  579. if ( !isManaged )
  580. ApplyProcMgmt( *pMProc, hProc );
  581. }
  582. // Clean up any open handles and delete jobs and procs that no longer exist...
  583. if ( hProc ) CloseHandle( hProc );
  584. DeleteOrphanProcEntries();
  585. DeleteOrphanJobEntries();
  586. LeaveCriticalSection( &m_mgCSMgrLists );
  587. delete [] doProc;
  588. delete [] jobDefs;
  589. delete [] procDefs;
  590. }
  591. //--------------------------------------------------------------------------------------------//
  592. // function to find a process entry in our list of currently managed processes //
  593. // Input: PID and create time of process to find //
  594. // Returns: pointer to found process entry or NULL if not found //
  595. // Note: A process muct match PID and create time to be a match. //
  596. // If just the PID matches, the PID has been reused and the old proc is gone. //
  597. //--------------------------------------------------------------------------------------------//
  598. CProcConMgr::ManagedProc *CProcConMgr::FindProcEntry( PID_VALUE pid, __int64 &createTime ) {
  599. for ( ManagedProc *p = m_procAnchor;
  600. p && p->pStats.pid != pid;
  601. p = p->next ) ;
  602. if ( p && memcmp( &p->pStats.createTime, &createTime, sizeof(createTime) ) ) p = NULL;
  603. return p;
  604. }
  605. //--------------------------------------------------------------------------------------------//
  606. // function to find a job entry in our list of currently managed jobs //
  607. // Input: job name of job to find //
  608. // Returns: pointer to found job entry or NULL if not found //
  609. //--------------------------------------------------------------------------------------------//
  610. CProcConMgr::ManagedJob *CProcConMgr::FindJobEntry( TCHAR *job, ManagedJob **plast ) {
  611. for ( ManagedJob *p = m_jobAnchor, *lst = m_jobAnchor;
  612. p && CompareJobName( p->jName, job );
  613. lst = p, p = p->next ) ;
  614. if ( plast ) *plast = lst;
  615. return p;
  616. }
  617. //--------------------------------------------------------------------------------------------//
  618. // function to update a process entry in our list of currently managed processes //
  619. // Input: pointer to list entry being updated, pointer to definition data, new flag //
  620. // Returns: nothing -- cannot fail //
  621. //--------------------------------------------------------------------------------------------//
  622. void CProcConMgr::UpdateProcEntry( ManagedProc &proc, PCProcDef &item, BOOL newProc ) {
  623. if ( newProc ) {
  624. proc.next = m_procAnchor;
  625. m_procAnchor = &proc;
  626. ++m_procManagedCount;
  627. }
  628. if ( memcmp( &proc.procParms, &item, sizeof(proc.procParms) ) ) {
  629. memcpy( &proc.procParms, &item, sizeof(proc.procParms) );
  630. proc.passSkipFlags = 0;
  631. }
  632. proc.sequence = m_sequencer;
  633. }
  634. //--------------------------------------------------------------------------------------------//
  635. // function to update a job entry in our list of currently managed jobs //
  636. // Input: pointer to list entry being updated, pointer to definition data, new flag //
  637. // Returns: nothing -- cannot fail //
  638. //--------------------------------------------------------------------------------------------//
  639. void CProcConMgr::UpdateJobEntry( ManagedJob &job, PCJobDef *item, BOOL newJob ) {
  640. if ( newJob ) {
  641. job.next = m_jobAnchor;
  642. m_jobAnchor = &job;
  643. ++m_jobManagedCount;
  644. }
  645. if ( item && memcmp( &job.jobParms, item, sizeof(job.jobParms) ) ) {
  646. memcpy( &job.jobParms, item, sizeof(job.jobParms) );
  647. job.dataErrorFlags = job.timeExceededReported = 0;
  648. }
  649. job.sequence = m_sequencer;
  650. }
  651. //--------------------------------------------------------------------------------------------//
  652. // function to allocate and build a job object process list and hang it on the ManagedJob //
  653. // Input: ptr to managed job //
  654. // Returns: TRUE if successful, FALSE if not (error issued) //
  655. //--------------------------------------------------------------------------------------------//
  656. BOOL CProcConMgr::GetProcListForJob( ManagedJob &job ) {
  657. DWORD actual, size, entryCount = 16;
  658. for ( ;; ) {
  659. delete [] ((UCHAR *) job.JOProcListInfo);
  660. size = sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST) + (entryCount - 1) * sizeof(job.JOProcListInfo->ProcessIdList[0]);
  661. job.JOProcListInfo = (JOBOBJECT_BASIC_PROCESS_ID_LIST *) new UCHAR[size];
  662. if ( !job.JOProcListInfo ) {
  663. PCLogNoMemory( TEXT("AllocJobProcList"), size );
  664. job.lastError = ERROR_NOT_ENOUGH_MEMORY;
  665. return FALSE;
  666. }
  667. if ( !QueryInformationJobObject( job.jobHandle, JobObjectBasicProcessIdList,
  668. job.JOProcListInfo, size, &actual )
  669. && GetLastError() != ERROR_MORE_DATA ) {
  670. job.lastError = GetLastError();
  671. PCLogUnExError( job.fullJobName, TEXT("GetJobObjProcListInfo") );
  672. memset( job.JOProcListInfo, 0, sizeof(*job.JOProcListInfo) );
  673. return FALSE;
  674. }
  675. if ( job.JOProcListInfo->NumberOfAssignedProcesses > job.JOProcListInfo->NumberOfProcessIdsInList )
  676. entryCount = job.JOProcListInfo->NumberOfAssignedProcesses + 2;
  677. else break;
  678. }
  679. return TRUE;
  680. }
  681. //--------------------------------------------------------------------------------------------//
  682. // function to populate a managed job structure with job object information //
  683. // Input: ptr to managed job //
  684. // Returns: nothing //
  685. //--------------------------------------------------------------------------------------------//
  686. void CProcConMgr::UpdateJobObjInfo( ManagedJob &job ) {
  687. PCULONG32 actual;
  688. if ( !QueryInformationJobObject( job.jobHandle, JobObjectExtendedLimitInformation,
  689. &job.JOExtendedLimitInfo, sizeof(job.JOExtendedLimitInfo), &actual ) ) {
  690. job.lastError = GetLastError();
  691. PCLogUnExError( job.fullJobName, TEXT("GetJobObjExtLimitInfo") );
  692. memset( &job.JOExtendedLimitInfo, 0, sizeof(job.JOExtendedLimitInfo) );
  693. }
  694. else if ( !QueryInformationJobObject( job.jobHandle, JobObjectBasicAndIoAccountingInformation,
  695. &job.JOBasicAndIoAcctInfo, sizeof(job.JOBasicAndIoAcctInfo), &actual ) ) {
  696. job.lastError = GetLastError();
  697. PCLogUnExError( job.fullJobName, TEXT("GetBasicAndIoAcctInfo") );
  698. memset( &job.JOBasicAndIoAcctInfo, 0, sizeof(job.JOBasicAndIoAcctInfo) );
  699. }
  700. else if ( GetProcListForJob( job ) ) {
  701. for ( PCULONG32 i = 0; i < job.JOProcListInfo->NumberOfProcessIdsInList; ++i ) {
  702. for ( PCULONG32 p = 0; p < m_rawProcCount; ++p ) {
  703. if ( m_rawProcList[p].pId == job.JOProcListInfo->ProcessIdList[i] ) {
  704. m_rawProcList[p].pMJob = &job;
  705. break;
  706. }
  707. }
  708. }
  709. delete [] ((UCHAR *) job.JOProcListInfo);
  710. job.JOProcListInfo = NULL;
  711. }
  712. }
  713. //--------------------------------------------------------------------------------------------//
  714. // function to delete process entries orphaned in our list of currently managed processes //
  715. // Input: none //
  716. // Returns: nothing //
  717. // Note: Caller must hold the CS that protects the list hanging off m_procAnchor //
  718. //--------------------------------------------------------------------------------------------//
  719. void CProcConMgr::DeleteOrphanProcEntries( void ) {
  720. for ( BOOL done = FALSE; !done; ) {
  721. done = TRUE;
  722. for ( ManagedProc *p = m_procAnchor, *plast = NULL; p; plast = p, p = p->next ) {
  723. if ( p->sequence != m_sequencer ) {
  724. if ( p == m_procAnchor ) m_procAnchor = p->next;
  725. else plast->next = p->next;
  726. delete p;
  727. --m_procManagedCount;
  728. done = FALSE;
  729. break;
  730. }
  731. }
  732. }
  733. }
  734. //--------------------------------------------------------------------------------------------//
  735. // function to delete job entries that have gone empty when 'close on empty' is set //
  736. // Input: none //
  737. // Returns: nothing //
  738. // Note: Caller must hold the CS that protects the list hanging off m_jobAnchor //
  739. //--------------------------------------------------------------------------------------------//
  740. void CProcConMgr::DeleteOrphanJobEntries( void ) {
  741. for ( BOOL done = FALSE; !done; ) {
  742. done = TRUE;
  743. for ( ManagedJob *p = m_jobAnchor; p; p = p->next ) {
  744. if ( p->sequence != m_sequencer ) { // job was not visited during last proc scan
  745. PCJobDef *jobDef;
  746. if ( m_cDB.GetJobMgmtDefs( &jobDef, &p->jName ) ) {// Returns 0 if job definition not found
  747. UpdateJobEntry( *p, jobDef );
  748. delete [] jobDef;
  749. }
  750. if ( p->jobParms.mFlags & PCMFLAG_END_JOB_WHEN_EMPTY ) {
  751. JobIsEmpty( p ); // job should be deleted after this call!
  752. done = FALSE;
  753. break;
  754. }
  755. }
  756. }
  757. }
  758. }
  759. //--------------------------------------------------------------------------------------------//
  760. // function to apply requested management behavior to the job in question //
  761. // Input: reference to managed job definition //
  762. // Returns: TRUE if requested behavior was assigned to the job, else FALSE //
  763. // Note: Assigning a process to a job cannot be undone. Thus, when this function returns //
  764. // TRUE the process is always associated with the job until the process ends. //
  765. //--------------------------------------------------------------------------------------------//
  766. BOOL CProcConMgr::ApplyJobMgmt( ManagedJob &job ) {
  767. BOOL applied = FALSE, change = FALSE, wantON, isON;
  768. // Establish flags to show what changes were made this pass...
  769. int doAff = 0, doPri = 0, doSch = 0, doWS = 0, doProcTime = 0, doJobTime = 0, doProcCount = 0,
  770. doProcMemory = 0, doJobMemory = 0, brkAwayOKAct = 0, silentBrkAwayAct = 0, dieUHExcept = 0;
  771. // Next prepare any updates needed to get where we want...
  772. // for all PC management flags,
  773. // o if management is requested and is either not in place or a different limit is requested:
  774. // turn on job object management flag and set limit value (if applicable)
  775. // o if management is not requested but is currently in place:
  776. // turn off job object management flag (leave limit alone)
  777. // Process Breakaway flag (if requested by CreateProcess, process is outside job if flag is set)
  778. // (if flag is not set, CreateProcess will fail)...
  779. brkAwayOKAct = PCTestSetUnset( job.jobParms.mFlags, PCMFLAG_SET_PROC_BREAKAWAY_OK,
  780. job.JOExtendedLimitInfo.BasicLimitInformation.LimitFlags,
  781. JOB_OBJECT_LIMIT_BREAKAWAY_OK );
  782. if ( brkAwayOKAct ) change = TRUE;
  783. if ( brkAwayOKAct > 0 )
  784. job.JOExtendedLimitInfo.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_BREAKAWAY_OK;
  785. else if ( brkAwayOKAct < 0 )
  786. job.JOExtendedLimitInfo.BasicLimitInformation.LimitFlags &= ~JOB_OBJECT_LIMIT_BREAKAWAY_OK;
  787. // Process Silent Breakaway flag (flag on means processes created in job are always outside job)...
  788. silentBrkAwayAct = PCTestSetUnset( job.jobParms.mFlags, PCMFLAG_SET_SILENT_BREAKAWAY,
  789. job.JOExtendedLimitInfo.BasicLimitInformation.LimitFlags,
  790. JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK );
  791. if ( silentBrkAwayAct ) change = TRUE;
  792. if ( silentBrkAwayAct > 0 )
  793. job.JOExtendedLimitInfo.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK;
  794. else if ( silentBrkAwayAct < 0 )
  795. job.JOExtendedLimitInfo.BasicLimitInformation.LimitFlags &= ~JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK;
  796. // Process die on UH Execption flag (flag on means suppress GPF message box)...
  797. dieUHExcept = PCTestSetUnset( job.jobParms.mFlags, PCMFLAG_SET_DIE_ON_UH_EXCEPTION,
  798. job.JOExtendedLimitInfo.BasicLimitInformation.LimitFlags,
  799. JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION );
  800. if ( dieUHExcept ) change = TRUE;
  801. if ( dieUHExcept > 0 )
  802. job.JOExtendedLimitInfo.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION;
  803. else if ( dieUHExcept < 0 )
  804. job.JOExtendedLimitInfo.BasicLimitInformation.LimitFlags &= ~JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION;
  805. // Process process memory limit flag...
  806. PCUINT32 pageSize = m_cPC.GetPageSize();
  807. MEMORY_VALUE oldProcMemory = job.JOExtendedLimitInfo.ProcessMemoryLimit,
  808. newProcMemory = ((job.jobParms.procMemoryLimit + pageSize - 1) / pageSize) * pageSize;
  809. // Ensure that process memory limit is not larger than API can handle...
  810. if ( sizeof(SIZE_T) == 4 && newProcMemory > ((MAXDWORD / pageSize) * pageSize) ) newProcMemory = ((MAXDWORD / pageSize) * pageSize);
  811. wantON = job.jobParms.mFlags & PCMFLAG_APPLY_PROC_MEMORY_LIMIT;
  812. isON = job.JOExtendedLimitInfo.BasicLimitInformation.LimitFlags & JOB_OBJECT_LIMIT_PROCESS_MEMORY;
  813. if ( wantON && (!isON || newProcMemory != oldProcMemory) ) {
  814. if ( !newProcMemory ) {
  815. if ( !(job.dataErrorFlags & PCMFLAG_APPLY_PROC_MEMORY_LIMIT) ) {
  816. const TCHAR *msgs[] = { PROCCON_SVC_DISP_NAME, job.fullJobName };
  817. PCLogMessage( PC_SERVICE_APPLY_PROC_MEMORY_REJECT, EVENTLOG_ERROR_TYPE,
  818. ENTRY_COUNT(msgs), msgs );
  819. }
  820. job.dataErrorFlags |= PCMFLAG_APPLY_PROC_MEMORY_LIMIT;
  821. }
  822. else {
  823. job.JOExtendedLimitInfo.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_PROCESS_MEMORY;
  824. job.JOExtendedLimitInfo.ProcessMemoryLimit = (SIZE_T) newProcMemory;
  825. doProcMemory = 1;
  826. change = TRUE;
  827. }
  828. }
  829. else if ( !wantON && isON ) {
  830. job.JOExtendedLimitInfo.BasicLimitInformation.LimitFlags &= ~JOB_OBJECT_LIMIT_PROCESS_MEMORY;
  831. doProcMemory = -1;
  832. change = TRUE;
  833. }
  834. // Process job memory limit flag...
  835. MEMORY_VALUE oldJobMemory = job.JOExtendedLimitInfo.JobMemoryLimit,
  836. newJobMemory = ((job.jobParms.jobMemoryLimit + pageSize - 1) / pageSize) * pageSize;
  837. // Ensure that requested job memory limit is not larger than API can handle...
  838. if ( sizeof(SIZE_T) == 4 && newJobMemory > ((MAXDWORD / pageSize) * pageSize) ) newJobMemory = ((MAXDWORD / pageSize) * pageSize);
  839. wantON = job.jobParms.mFlags & PCMFLAG_APPLY_JOB_MEMORY_LIMIT;
  840. isON = job.JOExtendedLimitInfo.BasicLimitInformation.LimitFlags & JOB_OBJECT_LIMIT_JOB_MEMORY;
  841. if ( wantON && (!isON || newJobMemory != oldJobMemory) ) {
  842. if ( !newJobMemory ) {
  843. if ( !(job.dataErrorFlags & PCMFLAG_APPLY_JOB_MEMORY_LIMIT) ) {
  844. const TCHAR *msgs[] = { PROCCON_SVC_DISP_NAME, job.fullJobName };
  845. PCLogMessage( PC_SERVICE_APPLY_JOB_MEMORY_REJECT, EVENTLOG_ERROR_TYPE,
  846. ENTRY_COUNT(msgs), msgs );
  847. }
  848. job.dataErrorFlags |= PCMFLAG_APPLY_JOB_MEMORY_LIMIT;
  849. }
  850. else {
  851. job.JOExtendedLimitInfo.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_JOB_MEMORY;
  852. job.JOExtendedLimitInfo.JobMemoryLimit = (SIZE_T) newJobMemory;
  853. doJobMemory = 1;
  854. change = TRUE;
  855. }
  856. }
  857. else if ( !wantON && isON ) {
  858. job.JOExtendedLimitInfo.BasicLimitInformation.LimitFlags &= ~JOB_OBJECT_LIMIT_JOB_MEMORY;
  859. doJobMemory = -1;
  860. change = TRUE;
  861. }
  862. // Process affinity flag...
  863. AFFINITY oldAff = job.JOExtendedLimitInfo.BasicLimitInformation.Affinity,
  864. newAff = job.jobParms.affinity & m_systemMask;
  865. wantON = job.jobParms.mFlags & PCMFLAG_APPLY_AFFINITY;
  866. isON = job.JOExtendedLimitInfo.BasicLimitInformation.LimitFlags & JOB_OBJECT_LIMIT_AFFINITY;
  867. if ( wantON && (!isON || newAff != oldAff) ) {
  868. if ( !newAff ) {
  869. if ( !(job.dataErrorFlags & PCMFLAG_APPLY_AFFINITY) ) {
  870. const TCHAR *msgs[] = { PROCCON_SVC_DISP_NAME, job.fullJobName };
  871. PCLogMessage( PC_SERVICE_APPLY_JOB_AFFINITY_REJECT, EVENTLOG_ERROR_TYPE,
  872. ENTRY_COUNT(msgs), msgs );
  873. }
  874. job.dataErrorFlags |= PCMFLAG_APPLY_AFFINITY;
  875. }
  876. else {
  877. job.JOExtendedLimitInfo.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_AFFINITY;
  878. job.JOExtendedLimitInfo.BasicLimitInformation.Affinity = (ULONG_PTR) newAff;
  879. doAff = 1;
  880. change = TRUE;
  881. }
  882. }
  883. else if ( !wantON && isON ) {
  884. job.JOExtendedLimitInfo.BasicLimitInformation.LimitFlags &= ~JOB_OBJECT_LIMIT_AFFINITY;
  885. doAff = -1;
  886. change = TRUE;
  887. }
  888. // Process priority flag...
  889. PRIORITY oldPri = job.JOExtendedLimitInfo.BasicLimitInformation.PriorityClass,
  890. newPri = PCMapPriorityToNT( job.jobParms.priority );
  891. wantON = job.jobParms.mFlags & PCMFLAG_APPLY_PRIORITY;
  892. isON = job.JOExtendedLimitInfo.BasicLimitInformation.LimitFlags & JOB_OBJECT_LIMIT_PRIORITY_CLASS;
  893. if ( wantON && (!isON || newPri != oldPri) ) {
  894. if ( !newPri ) {
  895. if ( !(job.dataErrorFlags & PCMFLAG_APPLY_PRIORITY) ) {
  896. const TCHAR *msgs[] = { PROCCON_SVC_DISP_NAME, job.fullJobName };
  897. PCLogMessage( PC_SERVICE_APPLY_JOB_PRIORITY_REJECT, EVENTLOG_ERROR_TYPE,
  898. ENTRY_COUNT(msgs), msgs );
  899. }
  900. job.dataErrorFlags |= PCMFLAG_APPLY_PRIORITY;
  901. }
  902. else {
  903. job.JOExtendedLimitInfo.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_PRIORITY_CLASS;
  904. job.JOExtendedLimitInfo.BasicLimitInformation.PriorityClass = newPri;
  905. doPri = 1;
  906. change = TRUE;
  907. }
  908. }
  909. else if ( !wantON && isON ) {
  910. job.JOExtendedLimitInfo.BasicLimitInformation.LimitFlags &= ~JOB_OBJECT_LIMIT_PRIORITY_CLASS;
  911. doPri = -1;
  912. change = TRUE;
  913. }
  914. // Process scheduling class flag...
  915. SCHEDULING_CLASS oldSch = job.JOExtendedLimitInfo.BasicLimitInformation.SchedulingClass,
  916. newSch = job.jobParms.schedClass;
  917. wantON = job.jobParms.mFlags & PCMFLAG_APPLY_SCHEDULING_CLASS;
  918. isON = job.JOExtendedLimitInfo.BasicLimitInformation.LimitFlags & JOB_OBJECT_LIMIT_SCHEDULING_CLASS;
  919. if ( wantON && (!isON || newSch != oldSch) ) {
  920. if ( newSch > 9 ) {
  921. if ( !(job.dataErrorFlags & PCMFLAG_APPLY_SCHEDULING_CLASS) ) {
  922. const TCHAR *msgs[] = { PROCCON_SVC_DISP_NAME, job.fullJobName };
  923. PCLogMessage( PC_SERVICE_APPLY_JOB_SCHEDULING_CLASS_REJECT, EVENTLOG_ERROR_TYPE,
  924. ENTRY_COUNT(msgs), msgs );
  925. }
  926. job.dataErrorFlags |= PCMFLAG_APPLY_SCHEDULING_CLASS;
  927. }
  928. else {
  929. job.JOExtendedLimitInfo.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_SCHEDULING_CLASS;
  930. job.JOExtendedLimitInfo.BasicLimitInformation.SchedulingClass = newSch;
  931. doSch = 1;
  932. change = TRUE;
  933. }
  934. }
  935. else if ( !wantON && isON ) {
  936. job.JOExtendedLimitInfo.BasicLimitInformation.LimitFlags &= ~JOB_OBJECT_LIMIT_SCHEDULING_CLASS;
  937. doSch = -1;
  938. change = TRUE;
  939. }
  940. // Process working set flag...
  941. MEMORY_VALUE oldMinWS = job.JOExtendedLimitInfo.BasicLimitInformation.MinimumWorkingSetSize,
  942. oldMaxWS = job.JOExtendedLimitInfo.BasicLimitInformation.MaximumWorkingSetSize;
  943. MEMORY_VALUE newMinWS = (job.jobParms.minWS + pageSize - 1) / pageSize * pageSize,
  944. newMaxWS = (job.jobParms.maxWS + pageSize - 1) / pageSize * pageSize;
  945. // Ensure that requested working set limits are not larger than API can handle...
  946. if ( sizeof(SIZE_T) == 4 && newMaxWS > ((MAXDWORD / pageSize) * pageSize) ) { // exceeds largest 32 bit value that is page size multiple
  947. newMaxWS = ((MAXDWORD / pageSize) * pageSize);
  948. if ( newMinWS >= newMaxWS )
  949. newMinWS = newMaxWS - 4 * pageSize;
  950. }
  951. wantON = job.jobParms.mFlags & PCMFLAG_APPLY_WS_MINMAX;
  952. isON = job.JOExtendedLimitInfo.BasicLimitInformation.LimitFlags & JOB_OBJECT_LIMIT_WORKINGSET;
  953. if ( wantON && (!isON || oldMinWS != newMinWS || oldMaxWS != newMaxWS) ) {
  954. if ( !newMinWS || newMaxWS <= newMinWS ) {
  955. if ( !(job.dataErrorFlags & PCMFLAG_APPLY_WS_MINMAX) ) {
  956. const TCHAR *msgs[] = { PROCCON_SVC_DISP_NAME, job.fullJobName };
  957. PCLogMessage( PC_SERVICE_APPLY_JOB_WORKING_SET_REJECT, EVENTLOG_ERROR_TYPE,
  958. ENTRY_COUNT(msgs), msgs );
  959. }
  960. job.dataErrorFlags |= PCMFLAG_APPLY_WS_MINMAX;
  961. }
  962. else {
  963. job.JOExtendedLimitInfo.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_WORKINGSET;
  964. job.JOExtendedLimitInfo.BasicLimitInformation.MinimumWorkingSetSize = (SIZE_T) newMinWS;
  965. job.JOExtendedLimitInfo.BasicLimitInformation.MaximumWorkingSetSize = (SIZE_T) newMaxWS;
  966. doWS = 1;
  967. change = TRUE;
  968. }
  969. }
  970. else if ( !wantON && isON ) {
  971. job.JOExtendedLimitInfo.BasicLimitInformation.LimitFlags &= ~JOB_OBJECT_LIMIT_WORKINGSET;
  972. doWS = -1;
  973. change = TRUE;
  974. }
  975. // Process process count limit flag...
  976. PCULONG32 oldProcCount = job.JOExtendedLimitInfo.BasicLimitInformation.ActiveProcessLimit,
  977. newProcCount = job.jobParms.procCountLimit;
  978. wantON = job.jobParms.mFlags & PCMFLAG_APPLY_PROC_COUNT_LIMIT;
  979. isON = job.JOExtendedLimitInfo.BasicLimitInformation.LimitFlags & JOB_OBJECT_LIMIT_ACTIVE_PROCESS;
  980. if ( wantON && (!isON || newProcCount != oldProcCount) ) {
  981. job.JOExtendedLimitInfo.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_ACTIVE_PROCESS;
  982. job.JOExtendedLimitInfo.BasicLimitInformation.ActiveProcessLimit = newProcCount;
  983. doProcCount = 1;
  984. change = TRUE;
  985. }
  986. else if ( !wantON && isON ) {
  987. job.JOExtendedLimitInfo.BasicLimitInformation.LimitFlags &= ~JOB_OBJECT_LIMIT_ACTIVE_PROCESS;
  988. doProcCount = -1;
  989. change = TRUE;
  990. }
  991. // Process process time limit flag...
  992. TIME_VALUE oldProcTime = PCLargeIntToInt64( job.JOExtendedLimitInfo.BasicLimitInformation.PerProcessUserTimeLimit ),
  993. newProcTime = job.jobParms.procTimeLimitCNS;
  994. wantON = job.jobParms.mFlags & PCMFLAG_APPLY_PROC_TIME_LIMIT;
  995. isON = job.JOExtendedLimitInfo.BasicLimitInformation.LimitFlags & JOB_OBJECT_LIMIT_PROCESS_TIME;
  996. if ( wantON && (!isON || newProcTime != oldProcTime) ) {
  997. if ( newProcTime < PC_MIN_TIME_LIMIT ) {
  998. if ( !(job.dataErrorFlags & PCMFLAG_APPLY_PROC_TIME_LIMIT) ) {
  999. const TCHAR *msgs[] = { PROCCON_SVC_DISP_NAME, job.fullJobName };
  1000. PCLogMessage( PC_SERVICE_APPLY_PROC_TIME_REJECT, EVENTLOG_ERROR_TYPE,
  1001. ENTRY_COUNT(msgs), msgs );
  1002. }
  1003. job.dataErrorFlags |= PCMFLAG_APPLY_PROC_TIME_LIMIT;
  1004. }
  1005. else {
  1006. job.JOExtendedLimitInfo.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_PROCESS_TIME;
  1007. job.JOExtendedLimitInfo.BasicLimitInformation.PerProcessUserTimeLimit.QuadPart = newProcTime;
  1008. doProcTime = 1;
  1009. change = TRUE;
  1010. }
  1011. }
  1012. else if ( !wantON && isON ) {
  1013. job.JOExtendedLimitInfo.BasicLimitInformation.LimitFlags &= ~JOB_OBJECT_LIMIT_PROCESS_TIME;
  1014. doProcTime = -1;
  1015. change = TRUE;
  1016. }
  1017. // Process job time limit flag...
  1018. TIME_VALUE oldJobTime = job.curJobTimeLimitCNS,
  1019. newJobTime = job.jobParms.jobTimeLimitCNS;
  1020. wantON = job.jobParms.mFlags & PCMFLAG_APPLY_JOB_TIME_LIMIT;
  1021. isON = job.JOExtendedLimitInfo.BasicLimitInformation.LimitFlags & JOB_OBJECT_LIMIT_JOB_TIME;
  1022. if ( wantON && ( (!isON && !job.timeExceededReported) || newJobTime != oldJobTime ) ) {
  1023. if ( newJobTime < PC_MIN_TIME_LIMIT ) {
  1024. if ( !(job.dataErrorFlags & PCMFLAG_APPLY_JOB_TIME_LIMIT) ) {
  1025. const TCHAR *msgs[] = { PROCCON_SVC_DISP_NAME, job.fullJobName };
  1026. PCLogMessage( PC_SERVICE_APPLY_JOB_TIME_REJECT, EVENTLOG_ERROR_TYPE,
  1027. ENTRY_COUNT(msgs), msgs );
  1028. }
  1029. job.dataErrorFlags |= PCMFLAG_APPLY_JOB_TIME_LIMIT;
  1030. }
  1031. else {
  1032. job.JOExtendedLimitInfo.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_JOB_TIME;
  1033. job.JOExtendedLimitInfo.BasicLimitInformation.PerJobUserTimeLimit.QuadPart = newJobTime;
  1034. doJobTime = 1;
  1035. change = TRUE;
  1036. job.curJobTimeLimitCNS = newJobTime;
  1037. }
  1038. }
  1039. else if ( !wantON && isON ) {
  1040. job.JOExtendedLimitInfo.BasicLimitInformation.LimitFlags &= ~JOB_OBJECT_LIMIT_JOB_TIME;
  1041. doJobTime = -1;
  1042. change = TRUE;
  1043. job.curJobTimeLimitCNS = 0;
  1044. }
  1045. // If we are about to change things other than job timing, set preserve job time...
  1046. if ( change && !doJobTime )
  1047. job.JOExtendedLimitInfo.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_PRESERVE_JOB_TIME;
  1048. // Now apply the updates needed and report if unsuccessful...
  1049. if ( change && !SetInformationJobObject( job.jobHandle, JobObjectExtendedLimitInformation,
  1050. &job.JOExtendedLimitInfo, sizeof(job.JOExtendedLimitInfo) ) )
  1051. PCLogUnExError( job.fullJobName, TEXT("SetJobObjLimitInfo") );
  1052. // The job object has been updated. Now do any completion port processing needed and report on changes.
  1053. else {
  1054. // First determine if we need to associate a completion port...
  1055. if ( !job.hasComplPort && m_assocPort.CompletionPort ) {
  1056. m_assocPort.CompletionKey = (void *) job.compKey;
  1057. if ( !SetInformationJobObject( job.jobHandle, JobObjectAssociateCompletionPortInformation,
  1058. &m_assocPort, sizeof(m_assocPort) ) && GetLastError() != ERROR_INVALID_PARAMETER )
  1059. PCLogUnExError( job.fullJobName, TEXT("SetJobObjComplPortInfo") );
  1060. else job.hasComplPort = TRUE;
  1061. }
  1062. // Next determine if we need to set end-of-job time time handling...
  1063. if ( job.hasComplPort ) {
  1064. JOBOBJECT_END_OF_JOB_TIME_INFORMATION eojData;
  1065. eojData.EndOfJobTimeAction = job.jobParms.mFlags & PCMFLAG_MSG_ON_JOB_TIME_LIMIT_HIT?
  1066. JOB_OBJECT_POST_AT_END_OF_JOB : JOB_OBJECT_TERMINATE_AT_END_OF_JOB;
  1067. if ( eojData.EndOfJobTimeAction != job.lastEojAction &&
  1068. !SetInformationJobObject( job.jobHandle, JobObjectEndOfJobTimeInformation,
  1069. &eojData, sizeof(eojData) ) )
  1070. PCLogUnExError( job.fullJobName, TEXT("SetJobObjEndOfJobInfo") );
  1071. else job.lastEojAction = eojData.EndOfJobTimeAction;
  1072. }
  1073. // Report on breakaway OK flag change, if any...
  1074. if ( brkAwayOKAct ) {
  1075. const TCHAR *msgs[] = { PROCCON_SVC_DISP_NAME, job.fullJobName };
  1076. if ( brkAwayOKAct > 0 )
  1077. PCLogMessage( PC_SERVICE_SET_BREAKAWAY_ALLOWED, EVENTLOG_INFORMATION_TYPE,
  1078. ENTRY_COUNT(msgs), msgs );
  1079. else
  1080. PCLogMessage( PC_SERVICE_UNSET_BREAKAWAY_ALLOWED, EVENTLOG_INFORMATION_TYPE,
  1081. ENTRY_COUNT(msgs), msgs );
  1082. }
  1083. // Report on silent breakaway flag change, if any...
  1084. if ( silentBrkAwayAct ) {
  1085. const TCHAR *msgs[] = { PROCCON_SVC_DISP_NAME, job.fullJobName };
  1086. if ( silentBrkAwayAct > 0 )
  1087. PCLogMessage( PC_SERVICE_SET_SILENT_BREAKAWAY_ENABLED, EVENTLOG_INFORMATION_TYPE,
  1088. ENTRY_COUNT(msgs), msgs );
  1089. else
  1090. PCLogMessage( PC_SERVICE_UNSET_SILENT_BREAKAWAY_ENABLED, EVENTLOG_INFORMATION_TYPE,
  1091. ENTRY_COUNT(msgs), msgs );
  1092. }
  1093. // Report on unhandled exception flag change, if any...
  1094. if ( dieUHExcept ) {
  1095. const TCHAR *msgs[] = { PROCCON_SVC_DISP_NAME, job.fullJobName };
  1096. if ( dieUHExcept > 0 )
  1097. PCLogMessage( PC_SERVICE_SET_LIMIT_DIE_ON_UNHANDLED_EXCEPTION, EVENTLOG_INFORMATION_TYPE,
  1098. ENTRY_COUNT(msgs), msgs );
  1099. else
  1100. PCLogMessage( PC_SERVICE_UNSET_LIMIT_DIE_ON_UNHANDLED_EXCEPTION, EVENTLOG_INFORMATION_TYPE,
  1101. ENTRY_COUNT(msgs), msgs );
  1102. }
  1103. // Report on process memory limit change, if any...
  1104. if ( doProcMemory ) {
  1105. TCHAR from[32], to[32];
  1106. _i64tot( oldProcMemory, from, 10 );
  1107. _i64tot( newProcMemory, to, 10 );
  1108. const TCHAR *msgs[] = { PROCCON_SVC_DISP_NAME, job.fullJobName, from, to };
  1109. if ( doProcMemory > 0 )
  1110. PCLogMessage( PC_SERVICE_CHANGE_JOB_PROCESS_MEMORY, EVENTLOG_INFORMATION_TYPE,
  1111. ENTRY_COUNT(msgs), msgs );
  1112. else
  1113. PCLogMessage( PC_SERVICE_REMOVE_JOB_PROCESS_MEMORY, EVENTLOG_INFORMATION_TYPE,
  1114. ENTRY_COUNT(msgs), msgs );
  1115. }
  1116. // Report on job memory limit change, if any...
  1117. if ( doJobMemory ) {
  1118. TCHAR from[32], to[32];
  1119. _i64tot( oldJobMemory, from, 10 );
  1120. _i64tot( newJobMemory, to, 10 );
  1121. const TCHAR *msgs[] = { PROCCON_SVC_DISP_NAME, job.fullJobName, from, to };
  1122. if ( doJobMemory > 0 )
  1123. PCLogMessage( PC_SERVICE_CHANGE_JOB_JOB_MEMORY, EVENTLOG_INFORMATION_TYPE,
  1124. ENTRY_COUNT(msgs), msgs );
  1125. else
  1126. PCLogMessage( PC_SERVICE_REMOVE_JOB_JOB_MEMORY, EVENTLOG_INFORMATION_TYPE,
  1127. ENTRY_COUNT(msgs), msgs );
  1128. }
  1129. // Report on process time limit change, if any...
  1130. if ( doProcTime ) {
  1131. TCHAR from[32], to[32];
  1132. _i64tot( oldProcTime / 10000, from, 10 ); // display in milliseconds
  1133. _i64tot( newProcTime / 10000, to, 10 ); // display in milliseconds
  1134. const TCHAR *msgs[] = { PROCCON_SVC_DISP_NAME, job.fullJobName, from, to };
  1135. if ( doProcTime > 0 )
  1136. PCLogMessage( PC_SERVICE_CHANGE_JOB_PROCESS_TIME, EVENTLOG_INFORMATION_TYPE,
  1137. ENTRY_COUNT(msgs), msgs );
  1138. else
  1139. PCLogMessage( PC_SERVICE_REMOVE_JOB_PROCESS_TIME, EVENTLOG_INFORMATION_TYPE,
  1140. ENTRY_COUNT(msgs), msgs );
  1141. }
  1142. // Report on job time limit change, if any...
  1143. if ( doJobTime ) {
  1144. TCHAR from[32], to[32];
  1145. _i64tot( oldJobTime / 10000, from, 10 ); // display in milliseconds
  1146. _i64tot( newJobTime / 10000, to, 10 ); // display in milliseconds
  1147. const TCHAR *msgs[] = { PROCCON_SVC_DISP_NAME, job.fullJobName, from, to };
  1148. if ( doJobTime > 0 )
  1149. PCLogMessage( PC_SERVICE_CHANGE_JOB_JOB_TIME, EVENTLOG_INFORMATION_TYPE,
  1150. ENTRY_COUNT(msgs), msgs );
  1151. else
  1152. PCLogMessage( PC_SERVICE_REMOVE_JOB_JOB_TIME, EVENTLOG_INFORMATION_TYPE,
  1153. ENTRY_COUNT(msgs), msgs );
  1154. }
  1155. // Report on process count limit change, if any...
  1156. if ( doProcCount ) {
  1157. TCHAR from[32], to[32];
  1158. _ltot( oldProcCount, from, 10 );
  1159. _ltot( newProcCount, to, 10 );
  1160. const TCHAR *msgs[] = { PROCCON_SVC_DISP_NAME, job.fullJobName, from, to };
  1161. if ( doProcCount > 0 )
  1162. PCLogMessage( PC_SERVICE_CHANGE_JOB_PROCESS_COUNT, EVENTLOG_INFORMATION_TYPE,
  1163. ENTRY_COUNT(msgs), msgs );
  1164. else
  1165. PCLogMessage( PC_SERVICE_REMOVE_JOB_PROCESS_COUNT, EVENTLOG_INFORMATION_TYPE,
  1166. ENTRY_COUNT(msgs), msgs );
  1167. }
  1168. // Report on priority class limit change, if any...
  1169. if ( doPri ) {
  1170. TCHAR from[32], to[32];
  1171. _ltot( PCMapPriorityToPC( oldPri ), from, 10 );
  1172. _ltot( PCMapPriorityToPC( newPri ), to, 10 );
  1173. const TCHAR *msgs[] = { PROCCON_SVC_DISP_NAME, job.fullJobName, from, to };
  1174. if ( doPri > 0 )
  1175. PCLogMessage( PC_SERVICE_CHANGE_JOB_PRIORITY, EVENTLOG_INFORMATION_TYPE,
  1176. ENTRY_COUNT(msgs), msgs );
  1177. else
  1178. PCLogMessage( PC_SERVICE_REMOVE_JOB_PRIORITY, EVENTLOG_INFORMATION_TYPE,
  1179. ENTRY_COUNT(msgs), msgs );
  1180. }
  1181. // Report on affinity limit change, if any...
  1182. if ( doAff ) {
  1183. TCHAR from[32] = TEXT("0x"), to[32] = TEXT("0x");
  1184. _i64tot( oldAff, &from[2], 16 );
  1185. _i64tot( newAff, &to[2], 16 );
  1186. const TCHAR *msgs[] = { PROCCON_SVC_DISP_NAME, job.fullJobName, from, to };
  1187. if ( doAff > 0 )
  1188. PCLogMessage( PC_SERVICE_CHANGE_JOB_AFFINITY, EVENTLOG_INFORMATION_TYPE,
  1189. ENTRY_COUNT(msgs), msgs );
  1190. else
  1191. PCLogMessage( PC_SERVICE_REMOVE_JOB_AFFINITY, EVENTLOG_INFORMATION_TYPE,
  1192. ENTRY_COUNT(msgs), msgs );
  1193. }
  1194. // Report on scheduling class limit change, if any...
  1195. if ( doSch ) {
  1196. TCHAR from[32], to[32];
  1197. _ltot( oldSch, from, 10 );
  1198. _ltot( newSch, to, 10 );
  1199. const TCHAR *msgs[] = { PROCCON_SVC_DISP_NAME, job.fullJobName, from, to };
  1200. if ( doSch > 0 )
  1201. PCLogMessage( PC_SERVICE_CHANGE_JOB_SCHEDULING_CLASS, EVENTLOG_INFORMATION_TYPE,
  1202. ENTRY_COUNT(msgs), msgs );
  1203. else
  1204. PCLogMessage( PC_SERVICE_REMOVE_JOB_SCHEDULING_CLASS, EVENTLOG_INFORMATION_TYPE,
  1205. ENTRY_COUNT(msgs), msgs );
  1206. }
  1207. // Report on working set limit change, if any...
  1208. if ( doWS ) {
  1209. TCHAR from[32], to[32], from2[32], to2[32];
  1210. _i64tot( oldMinWS, from, 10 );
  1211. _i64tot( oldMaxWS, from2, 10 );
  1212. _i64tot( newMinWS, to, 10 );
  1213. _i64tot( newMaxWS, to2, 10 );
  1214. const TCHAR *msgs[] = { PROCCON_SVC_DISP_NAME, job.fullJobName, from, from2, to, to2 };
  1215. if ( doWS > 0 )
  1216. PCLogMessage( PC_SERVICE_CHANGE_JOB_WORKING_SET, EVENTLOG_INFORMATION_TYPE,
  1217. ENTRY_COUNT(msgs), msgs );
  1218. else
  1219. PCLogMessage( PC_SERVICE_REMOVE_JOB_WORKING_SET, EVENTLOG_INFORMATION_TYPE,
  1220. ENTRY_COUNT(msgs), msgs );
  1221. }
  1222. applied = TRUE;
  1223. }
  1224. return applied;
  1225. }
  1226. //--------------------------------------------------------------------------------------------//
  1227. // function to apply requested management behavior to the process in question //
  1228. // Input: managed process definition, process handle //
  1229. // Returns: TRUE if any requested behavior is successfully applied, else FALSE //
  1230. //--------------------------------------------------------------------------------------------//
  1231. BOOL CProcConMgr::ApplyProcMgmt( ManagedProc &proc, HANDLE hProc ) {
  1232. BOOL setProc = FALSE;
  1233. ULONG_PTR oldAff, newAff;
  1234. PRIORITY oldPri, newPri;
  1235. SIZE_T oldMinWS, oldMaxWS;
  1236. // Handle request to set or unset process affinity...
  1237. // Check to see if affinity is to be applied...
  1238. if ( proc.procParms.mFlags & PCMFLAG_APPLY_AFFINITY ) {
  1239. // Get current affinity and save as original if not yet saved...
  1240. GetProcessAffinityMask( hProc, &oldAff, &m_systemMask );
  1241. if ( !(proc.originalParms.mFlags & PCMFLAG_APPLY_AFFINITY) ) {
  1242. proc.originalParms.mFlags |= PCMFLAG_APPLY_AFFINITY;
  1243. proc.originalParms.affinity = oldAff;
  1244. }
  1245. // Get new affinity and complain if invalid and not reported...
  1246. newAff = (ULONG_PTR) proc.procParms.affinity & m_systemMask;
  1247. if ( !newAff && !(proc.passSkipFlags & PCMFLAG_APPLY_AFFINITY) ) {
  1248. // Flag to skip affinity test on next pass so we don't report error repeatedly...
  1249. proc.passSkipFlags |= PCMFLAG_APPLY_AFFINITY;
  1250. const TCHAR *msgs[] = { PROCCON_SVC_DISP_NAME, proc.pName };
  1251. PCLogMessage( PC_SERVICE_APPLY_PROC_AFFINITY_REJECT, EVENTLOG_ERROR_TYPE,
  1252. ENTRY_COUNT(msgs), msgs );
  1253. }
  1254. // If new affinity differs from old, attempt change and report on success or failure...
  1255. else if ( newAff != oldAff ) {
  1256. PCULONG32 rc = SetProcessAffinityMask( hProc, newAff );
  1257. if ( rc ) {
  1258. proc.passSkipFlags &= ~PCMFLAG_APPLY_AFFINITY;
  1259. proc.isAppliedFlags |= PCMFLAG_APPLY_AFFINITY;
  1260. TCHAR from[32] = TEXT("0x"), to[32] = TEXT("0x");
  1261. _i64tot( oldAff, &from[2], 16 );
  1262. _i64tot( newAff, &to[2], 16 );
  1263. const TCHAR *msgs[] = { PROCCON_SVC_DISP_NAME, proc.pName, proc.pidAsString, proc.imageName, from, to };
  1264. PCLogMessage( PC_SERVICE_CHANGE_PROC_AFFINITY, EVENTLOG_INFORMATION_TYPE, ENTRY_COUNT(msgs), msgs );
  1265. setProc = TRUE;
  1266. }
  1267. else if ( !(proc.passSkipFlags & PCMFLAG_APPLY_AFFINITY) ) {
  1268. proc.passSkipFlags |= PCMFLAG_APPLY_AFFINITY;
  1269. const TCHAR *msgs[] = { PROCCON_SVC_DISP_NAME, proc.pName, proc.pidAsString, proc.imageName };
  1270. PCLogMessage( PC_SERVICE_APPLY_PROC_AFFINITY_ERROR, EVENTLOG_ERROR_TYPE, ENTRY_COUNT(msgs), msgs );
  1271. }
  1272. }
  1273. }
  1274. // Not applying affinity -- check to see if affinity is to be un-applied...
  1275. else if ( !(proc.procParms.mFlags & PCMFLAG_APPLY_AFFINITY) && proc.isAppliedFlags & PCMFLAG_APPLY_AFFINITY ) {
  1276. // Get current affinity to verify we are making a change...
  1277. GetProcessAffinityMask( hProc, &oldAff, &m_systemMask );
  1278. newAff = (ULONG_PTR) proc.originalParms.affinity;
  1279. if ( newAff != oldAff ) {
  1280. PCULONG32 rc = SetProcessAffinityMask( hProc, newAff );
  1281. // We reverted to original value, reset flags and report...
  1282. if ( rc ) {
  1283. proc.isAppliedFlags &= ~PCMFLAG_APPLY_AFFINITY;
  1284. proc.passSkipFlags &= ~PCMFLAG_APPLY_AFFINITY;
  1285. TCHAR from[32] = TEXT("0x"), to[32] = TEXT("0x");
  1286. _i64tot( oldAff, &from[2], 16 );
  1287. _i64tot( newAff, &to[2], 16 );
  1288. const TCHAR *msgs[] = { PROCCON_SVC_DISP_NAME, proc.pName, proc.pidAsString, proc.imageName, from, to };
  1289. PCLogMessage( PC_SERVICE_CHANGE_PROC_AFFINITY, EVENTLOG_INFORMATION_TYPE, ENTRY_COUNT(msgs), msgs );
  1290. setProc = TRUE;
  1291. }
  1292. else if ( !(proc.passSkipFlags & PCMFLAG_APPLY_AFFINITY) ) {
  1293. proc.passSkipFlags |= PCMFLAG_APPLY_AFFINITY;
  1294. const TCHAR *msgs[] = { PROCCON_SVC_DISP_NAME, proc.pName, proc.pidAsString, proc.imageName };
  1295. PCLogMessage( PC_SERVICE_APPLY_PROC_AFFINITY_ERROR, EVENTLOG_ERROR_TYPE, ENTRY_COUNT(msgs), msgs );
  1296. }
  1297. }
  1298. else {
  1299. proc.isAppliedFlags &= ~PCMFLAG_APPLY_AFFINITY;
  1300. proc.passSkipFlags &= ~PCMFLAG_APPLY_AFFINITY;
  1301. }
  1302. }
  1303. // Handle request to set or unset process priority...
  1304. // Check to see if priority is to be applied now...
  1305. if ( proc.procParms.mFlags & PCMFLAG_APPLY_PRIORITY ) {
  1306. // Get current priority and save as original if not yet saved...
  1307. oldPri = GetPriorityClass( hProc );
  1308. if ( !(proc.originalParms.mFlags & PCMFLAG_APPLY_PRIORITY) ) {
  1309. proc.originalParms.mFlags |= PCMFLAG_APPLY_PRIORITY;
  1310. proc.originalParms.priority = PCMapPriorityToPC( oldPri );
  1311. }
  1312. // Get new priority and complain if zero...
  1313. newPri = PCMapPriorityToNT( proc.procParms.priority );
  1314. if ( !newPri && !(proc.passSkipFlags & PCMFLAG_APPLY_PRIORITY) ) {
  1315. proc.passSkipFlags |= PCMFLAG_APPLY_PRIORITY;
  1316. const TCHAR *msgs[] = { PROCCON_SVC_DISP_NAME, proc.pName };
  1317. PCLogMessage( PC_SERVICE_APPLY_PROC_PRIORITY_REJECT, EVENTLOG_ERROR_TYPE,
  1318. ENTRY_COUNT(msgs), msgs );
  1319. }
  1320. // If new priority differs from old, attempt change and report on success or failure...
  1321. else if ( newPri != oldPri ) {
  1322. PCULONG32 rc = SetPriorityClass( hProc, newPri );
  1323. if ( rc ) {
  1324. proc.passSkipFlags &= ~PCMFLAG_APPLY_PRIORITY;
  1325. proc.isAppliedFlags |= PCMFLAG_APPLY_PRIORITY;
  1326. TCHAR from[32], to[32];
  1327. _ltot( PCMapPriorityToPC( oldPri ), from, 10 );
  1328. _ltot( PCMapPriorityToPC( newPri ), to, 10 );
  1329. const TCHAR *msgs[] = { PROCCON_SVC_DISP_NAME, proc.pName, proc.pidAsString, proc.imageName, from, to };
  1330. PCLogMessage( PC_SERVICE_CHANGE_PROC_PRIORITY, EVENTLOG_INFORMATION_TYPE, ENTRY_COUNT(msgs), msgs );
  1331. setProc = TRUE;
  1332. }
  1333. else if ( !(proc.passSkipFlags & PCMFLAG_APPLY_PRIORITY) ) {
  1334. // Flag to skip priority test on next pass so we don't report error repeatedly...
  1335. proc.passSkipFlags |= PCMFLAG_APPLY_PRIORITY;
  1336. const TCHAR *msgs[] = { PROCCON_SVC_DISP_NAME, proc.pName, proc.pidAsString, proc.imageName };
  1337. PCLogMessage( PC_SERVICE_APPLY_PROC_PRIORITY_ERROR, EVENTLOG_ERROR_TYPE, ENTRY_COUNT(msgs), msgs );
  1338. }
  1339. }
  1340. }
  1341. // Not applying priority -- check to see if priority is to be un-applied...
  1342. else if ( !(proc.procParms.mFlags & PCMFLAG_APPLY_PRIORITY) && proc.isAppliedFlags & PCMFLAG_APPLY_PRIORITY ) {
  1343. // Get current priority to verify we are making a change...
  1344. oldPri = GetPriorityClass( hProc );
  1345. newPri = PCMapPriorityToNT( proc.originalParms.priority );
  1346. if ( newPri != oldPri) {
  1347. PCULONG32 rc = SetPriorityClass( hProc, newPri );
  1348. // We reverted to original value, reset all flags and report...
  1349. if ( rc ) {
  1350. proc.isAppliedFlags &= ~PCMFLAG_APPLY_PRIORITY;
  1351. proc.passSkipFlags &= ~PCMFLAG_APPLY_PRIORITY;
  1352. TCHAR from[32], to[32];
  1353. _ltot( PCMapPriorityToPC( oldPri ), from, 10 );
  1354. _ltot( PCMapPriorityToPC( newPri ), to, 10 );
  1355. const TCHAR *msgs[] = { PROCCON_SVC_DISP_NAME, proc.pName, proc.pidAsString, proc.imageName, from, to };
  1356. PCLogMessage( PC_SERVICE_CHANGE_PROC_PRIORITY, EVENTLOG_INFORMATION_TYPE, ENTRY_COUNT(msgs), msgs );
  1357. setProc = TRUE;
  1358. }
  1359. else if ( !(proc.passSkipFlags & PCMFLAG_APPLY_PRIORITY) ) {
  1360. proc.passSkipFlags |= PCMFLAG_APPLY_PRIORITY;
  1361. const TCHAR *msgs[] = { PROCCON_SVC_DISP_NAME, proc.pName, proc.pidAsString, proc.imageName };
  1362. PCLogMessage( PC_SERVICE_APPLY_PROC_PRIORITY_ERROR, EVENTLOG_ERROR_TYPE, ENTRY_COUNT(msgs), msgs );
  1363. }
  1364. }
  1365. else {
  1366. proc.isAppliedFlags &= ~PCMFLAG_APPLY_PRIORITY;
  1367. proc.passSkipFlags &= ~PCMFLAG_APPLY_PRIORITY;
  1368. }
  1369. }
  1370. // Handle request to set or unset process working set...
  1371. // Check to see if working set is to be applied now...
  1372. if ( proc.procParms.mFlags & PCMFLAG_APPLY_WS_MINMAX ) {
  1373. // Ensure that requested working set limits are not larger than API can handle...
  1374. PCUINT32 pageSize = m_cPC.GetPageSize();
  1375. if ( sizeof(SIZE_T) == 4 && proc.procParms.maxWS > ((MAXDWORD / pageSize) * pageSize) ) { // exceeds largest 32 bit value that is page size multiple
  1376. proc.procParms.maxWS = ((MAXDWORD / pageSize) * pageSize);
  1377. if ( proc.procParms.minWS >= proc.procParms.maxWS )
  1378. proc.procParms.minWS = proc.procParms.maxWS - 4 * pageSize;
  1379. }
  1380. // Get current working set and save as original if not yet saved...
  1381. GetProcessWorkingSetSize( hProc, &oldMinWS, &oldMaxWS );
  1382. if ( !(proc.originalParms.mFlags & PCMFLAG_APPLY_WS_MINMAX) ) {
  1383. proc.originalParms.mFlags |= PCMFLAG_APPLY_WS_MINMAX;
  1384. proc.originalParms.minWS = oldMinWS;
  1385. proc.originalParms.maxWS = oldMaxWS;
  1386. }
  1387. // Verify new working set and complain if bad...
  1388. if ( (!proc.procParms.minWS || proc.procParms.minWS >= proc.procParms.maxWS) &&
  1389. !(proc.passSkipFlags & PCMFLAG_APPLY_WS_MINMAX) ) {
  1390. proc.passSkipFlags |= PCMFLAG_APPLY_WS_MINMAX;
  1391. const TCHAR *msgs[] = { PROCCON_SVC_DISP_NAME, proc.pName };
  1392. PCLogMessage( PC_SERVICE_APPLY_PROC_WORKING_SET_REJECT, EVENTLOG_ERROR_TYPE,
  1393. ENTRY_COUNT(msgs), msgs );
  1394. }
  1395. // If new working set differs from old, attempt change and report on success or failure...
  1396. else if ( proc.procParms.minWS != oldMinWS || proc.procParms.maxWS != oldMaxWS ) {
  1397. PCULONG32 rc = SetProcessWorkingSetSize( hProc, (SIZE_T) proc.procParms.minWS,
  1398. (SIZE_T) proc.procParms.maxWS );
  1399. if ( rc ) {
  1400. proc.passSkipFlags &= ~PCMFLAG_APPLY_WS_MINMAX;
  1401. proc.isAppliedFlags |= PCMFLAG_APPLY_WS_MINMAX;
  1402. TCHAR from[32], to[32], from2[32], to2[32];
  1403. _i64tot( (__int64) oldMinWS, from, 10 );
  1404. _i64tot( (__int64) oldMaxWS, from2, 10 );
  1405. _i64tot( proc.procParms.minWS, to, 10 );
  1406. _i64tot( proc.procParms.maxWS, to2, 10 );
  1407. const TCHAR *msgs[] = { PROCCON_SVC_DISP_NAME, proc.pName, proc.pidAsString, proc.imageName,
  1408. from, from2, to, to2 };
  1409. PCLogMessage( PC_SERVICE_CHANGE_PROC_WORKING_SET, EVENTLOG_INFORMATION_TYPE, ENTRY_COUNT(msgs), msgs );
  1410. setProc = TRUE;
  1411. }
  1412. else if ( !(proc.passSkipFlags & PCMFLAG_APPLY_WS_MINMAX) ) {
  1413. proc.passSkipFlags |= PCMFLAG_APPLY_WS_MINMAX;
  1414. const TCHAR *msgs[] = { PROCCON_SVC_DISP_NAME, proc.pName, proc.pidAsString, proc.imageName };
  1415. PCLogMessage( PC_SERVICE_APPLY_PROC_WORKINGSET_ERROR, EVENTLOG_ERROR_TYPE, ENTRY_COUNT(msgs), msgs );
  1416. }
  1417. }
  1418. }
  1419. // Not applying working set -- check to see if working set is to be un-applied...
  1420. else if ( !(proc.procParms.mFlags & PCMFLAG_APPLY_WS_MINMAX) && proc.isAppliedFlags & PCMFLAG_APPLY_WS_MINMAX ) {
  1421. // Get current working set to verify we are making a change...
  1422. GetProcessWorkingSetSize( hProc, &oldMinWS, &oldMaxWS );
  1423. if ( proc.originalParms.minWS != oldMinWS || proc.originalParms.maxWS != oldMaxWS ) {
  1424. PCULONG32 rc = SetProcessWorkingSetSize( hProc, (SIZE_T) proc.originalParms.minWS,
  1425. (SIZE_T) proc.originalParms.maxWS );
  1426. // We reverted to original values, reset all flags and report...
  1427. if ( rc ) {
  1428. proc.passSkipFlags &= ~PCMFLAG_APPLY_WS_MINMAX;
  1429. proc.isAppliedFlags &= ~PCMFLAG_APPLY_WS_MINMAX;
  1430. TCHAR from[32], to[32], from2[32], to2[32];
  1431. _i64tot( (__int64) oldMinWS, from, 10 );
  1432. _i64tot( (__int64) oldMaxWS, from2, 10 );
  1433. _i64tot( proc.originalParms.minWS, to, 10 );
  1434. _i64tot( proc.originalParms.maxWS, to2, 10 );
  1435. const TCHAR *msgs[] = { PROCCON_SVC_DISP_NAME, proc.pName, proc.pidAsString, proc.imageName,
  1436. from, from2, to, to2 };
  1437. PCLogMessage( PC_SERVICE_CHANGE_PROC_WORKING_SET, EVENTLOG_INFORMATION_TYPE, ENTRY_COUNT(msgs), msgs );
  1438. setProc = TRUE;
  1439. }
  1440. else if ( !(proc.passSkipFlags & PCMFLAG_APPLY_WS_MINMAX) ) {
  1441. proc.passSkipFlags |= PCMFLAG_APPLY_WS_MINMAX;
  1442. const TCHAR *msgs[] = { PROCCON_SVC_DISP_NAME, proc.pName, proc.pidAsString, proc.imageName };
  1443. PCLogMessage( PC_SERVICE_APPLY_PROC_WORKINGSET_ERROR, EVENTLOG_ERROR_TYPE, ENTRY_COUNT(msgs), msgs );
  1444. }
  1445. }
  1446. else {
  1447. proc.isAppliedFlags &= ~PCMFLAG_APPLY_WS_MINMAX;
  1448. proc.passSkipFlags &= ~PCMFLAG_APPLY_WS_MINMAX;
  1449. }
  1450. }
  1451. return setProc;
  1452. }
  1453. //--------------------------------------------------------------------------------------------//
  1454. // function to build copy of active process list for exporting (to API) //
  1455. // Input: location to store allocated buffer (call frees it) //
  1456. // Returns: number of entries in the list //
  1457. //--------------------------------------------------------------------------------------------//
  1458. PCULONG32 CProcConMgr::ExportActiveProcList( PCProcListItem **list ) {
  1459. Discover(); // Go build or refresh process and job lists
  1460. EnterCriticalSection( &m_mgCSMgrLists );
  1461. PCULONG32 count = m_rawProcCount;
  1462. *list = NULL;
  1463. if ( m_rawProcList ) {
  1464. *list = new PCProcListItem[m_rawProcCount];
  1465. if ( !*list ) {
  1466. PCLogNoMemory( TEXT("AllocExportProcList"), sizeof(PCProcListItem) * m_rawProcCount );
  1467. LeaveCriticalSection( &m_mgCSMgrLists );
  1468. return 0;
  1469. }
  1470. else memset( *list, 0, sizeof(PCProcListItem) * m_rawProcCount );
  1471. }
  1472. for ( PCULONG32 i = 0; i < count; ++i ) {
  1473. PCProcListItem &target = (*list)[i];
  1474. memcpy( target.procName, m_rawProcList[i].pName, sizeof(target.procName) );
  1475. memcpy( target.imageName, m_rawProcList[i].imageName, sizeof(target.imageName) );
  1476. target.procStats.pid = m_rawProcList[i].pId;
  1477. target.procStats.createTime = PCFileTimeToInt64( m_rawProcList[i].createTime );
  1478. target.procStats.TotalUserTime = PCFileTimeToInt64( m_rawProcList[i].userTime );
  1479. target.procStats.TotalKernelTime = PCFileTimeToInt64( m_rawProcList[i].kernelTime );
  1480. target.actualPriority = m_rawProcList[i].actualPriority;
  1481. target.actualAffinity = m_rawProcList[i].actualAffinity;
  1482. target.lFlags = PCLFLAG_IS_RUNNING;
  1483. if ( m_rawProcList[i].pMJob ) {
  1484. target.lFlags |= PCLFLAG_IS_IN_A_JOB;
  1485. memcpy(target.jobName, m_rawProcList[i].pMJob->jName, sizeof( target.jobName ) );
  1486. }
  1487. }
  1488. LeaveCriticalSection( &m_mgCSMgrLists );
  1489. return count;
  1490. }
  1491. //--------------------------------------------------------------------------------------------//
  1492. // function to build copy of active job list for exporting (to API) //
  1493. // Input: location to store allocated buffer (call frees it) //
  1494. // Returns: number of entries in the list //
  1495. //--------------------------------------------------------------------------------------------//
  1496. PCULONG32 CProcConMgr::ExportActiveJobList( PCJobListItem **list ) {
  1497. Discover(); // Go build or refresh process and job lists
  1498. EnterCriticalSection( &m_mgCSMgrLists );
  1499. PCULONG32 count = m_jobManagedCount;
  1500. // Allocate buffer for job list (caller will free)...
  1501. *list = new PCJobListItem[count];
  1502. if ( !*list ) {
  1503. PCLogNoMemory( TEXT("AllocJobList"), sizeof(PCJobListItem) * count );
  1504. LeaveCriticalSection( &m_mgCSMgrLists );
  1505. return 0;
  1506. }
  1507. memset( *list, 0, sizeof(PCJobListItem) * count );
  1508. // Copy job names to list and set flag(s)...
  1509. PCULONG32 i = 0;
  1510. for ( ManagedJob *curJob = m_jobAnchor; curJob; curJob = curJob->next, ++i ) {
  1511. PCJobListItem &target = (*list)[i];
  1512. memcpy( target.jobName, curJob->jName, sizeof(curJob->jName) );
  1513. target.jobStats.TotalUserTime =
  1514. PCLargeIntToInt64( curJob->JOBasicAndIoAcctInfo.BasicInfo.TotalUserTime );
  1515. target.jobStats.TotalKernelTime =
  1516. PCLargeIntToInt64( curJob->JOBasicAndIoAcctInfo.BasicInfo.TotalKernelTime );
  1517. target.jobStats.ThisPeriodTotalUserTime =
  1518. PCLargeIntToInt64( curJob->JOBasicAndIoAcctInfo.BasicInfo.ThisPeriodTotalUserTime );
  1519. target.jobStats.ThisPeriodTotalKernelTime =
  1520. PCLargeIntToInt64( curJob->JOBasicAndIoAcctInfo.BasicInfo.ThisPeriodTotalKernelTime );
  1521. target.jobStats.TotalPageFaultCount = curJob->JOBasicAndIoAcctInfo.BasicInfo.TotalPageFaultCount;
  1522. target.jobStats.TotalProcesses = curJob->JOBasicAndIoAcctInfo.BasicInfo.TotalProcesses;
  1523. target.jobStats.ActiveProcesses = curJob->JOBasicAndIoAcctInfo.BasicInfo.ActiveProcesses;
  1524. target.jobStats.TotalTerminatedProcesses = curJob->JOBasicAndIoAcctInfo.BasicInfo.TotalTerminatedProcesses;
  1525. target.jobStats.ReadOperationCount = curJob->JOBasicAndIoAcctInfo.IoInfo.ReadOperationCount;
  1526. target.jobStats.WriteOperationCount = curJob->JOBasicAndIoAcctInfo.IoInfo.WriteOperationCount;
  1527. target.jobStats.OtherOperationCount = curJob->JOBasicAndIoAcctInfo.IoInfo.OtherOperationCount;
  1528. target.jobStats.ReadTransferCount = curJob->JOBasicAndIoAcctInfo.IoInfo.ReadTransferCount;
  1529. target.jobStats.WriteTransferCount = curJob->JOBasicAndIoAcctInfo.IoInfo.WriteTransferCount;
  1530. target.jobStats.OtherTransferCount = curJob->JOBasicAndIoAcctInfo.IoInfo.OtherTransferCount;
  1531. target.jobStats.PeakProcessMemoryUsed = curJob->JOExtendedLimitInfo.PeakProcessMemoryUsed;
  1532. target.jobStats.PeakJobMemoryUsed = curJob->JOExtendedLimitInfo.PeakJobMemoryUsed;
  1533. target.actualPriority =
  1534. PCMapPriorityToPC( curJob->JOExtendedLimitInfo.BasicLimitInformation.PriorityClass );
  1535. target.actualAffinity = curJob->JOExtendedLimitInfo.BasicLimitInformation.Affinity;
  1536. target.actualSchedClass = curJob->JOExtendedLimitInfo.BasicLimitInformation.SchedulingClass;
  1537. target.lFlags = PCLFLAG_IS_RUNNING;
  1538. }
  1539. // Sort the list by name...
  1540. qsort( *list, count, sizeof(PCJobListItem), CompareJobName );
  1541. LeaveCriticalSection( &m_mgCSMgrLists );
  1542. return count;
  1543. }
  1544. //--------------------------------------------------------------------------------------------//
  1545. // functions to kill a job (only ProcCon created jobs can be killed) //
  1546. // Input: job name //
  1547. // Returns: PCERROR_SUCCESS on success, else error code //
  1548. //--------------------------------------------------------------------------------------------//
  1549. INT32 CProcConMgr::KillJob( JOB_NAME &name ) {
  1550. // Determine if user has right to kill jobs...
  1551. if ( m_cDB.TestAccess( PROCCON_REG_KILLJOB_ACCTEST ) != ERROR_SUCCESS )
  1552. return GetLastError();
  1553. INT32 err = PCERROR_DOES_NOT_EXIST; // prime error code for subsequent logic
  1554. // Locate the job in our job list to get handle. If found, simply terminate the job.
  1555. // Note that terminating the job simply means terminate all contained processes.
  1556. // If the close on empty option is set, the job will be closed in the notify routine.
  1557. EnterCriticalSection( &m_mgCSMgrLists );
  1558. for ( ManagedJob *prev = NULL, *job = m_jobAnchor; job; prev = job, job = job->next ) {
  1559. if ( !CompareJobName( &name, &job->jName ) ) {
  1560. if ( !TerminateJobObject( job->jobHandle, ERROR_PROCESS_ABORTED ) )
  1561. err = GetLastError();
  1562. else
  1563. err = PCERROR_SUCCESS;
  1564. break;
  1565. }
  1566. }
  1567. LeaveCriticalSection( &m_mgCSMgrLists );
  1568. // If successful, log a message...
  1569. if ( err == PCERROR_SUCCESS ) {
  1570. const TCHAR *msgs[] = { PROCCON_SVC_DISP_NAME, name };
  1571. PCLogMessage( PC_SERVICE_KILLED_JOB, EVENTLOG_INFORMATION_TYPE, ENTRY_COUNT(msgs), msgs );
  1572. }
  1573. return err;
  1574. }
  1575. //--------------------------------------------------------------------------------------------//
  1576. // functions to kill a process (any Windows process can be killed) //
  1577. // Input: process pid and process create time //
  1578. // Returns: PCERROR_SUCCESS on success, else error code //
  1579. //--------------------------------------------------------------------------------------------//
  1580. INT32 CProcConMgr::KillProcess( ULONG_PTR pid, TIME_VALUE created ) {
  1581. // Determine if user has right to kill processes...
  1582. if ( m_cDB.TestAccess( PROCCON_REG_KILLPROC_ACCTEST ) != ERROR_SUCCESS )
  1583. return GetLastError();
  1584. INT32 err = ERROR_SUCCESS;
  1585. // Attempt to get a handle to the process...
  1586. HANDLE hProc = OpenProcess( PROCESS_QUERY_INFORMATION // to get time data
  1587. + PROCESS_TERMINATE, // to terminate it
  1588. FALSE, (DWORD) pid ); // Win64 OpenProcess still uses DWORD PID == warning
  1589. // If we found it, determine if its the same one (by create time) and terminate it...
  1590. if ( hProc ) {
  1591. FILETIME create, exit, kernel, user;
  1592. GetProcessTimes( hProc, &create, &exit, &kernel, &user );
  1593. if ( created != 0x777deadfeeb1e777 && PCFileTimeToInt64( create ) != created )
  1594. err = PCERROR_DOES_NOT_EXIST;
  1595. else if ( !TerminateProcess( hProc, ERROR_PROCESS_ABORTED ) )
  1596. err = GetLastError();
  1597. CloseHandle( hProc );
  1598. }
  1599. else {
  1600. err = GetLastError();
  1601. if ( err == ERROR_INVALID_PARAMETER )
  1602. err = PCERROR_DOES_NOT_EXIST;
  1603. }
  1604. // If successful, log a message...
  1605. if ( err == ERROR_SUCCESS ) {
  1606. TCHAR pidAsString[32];
  1607. _i64tot( pid, pidAsString, 10 );
  1608. const TCHAR *msgs[] = { PROCCON_SVC_DISP_NAME, pidAsString };
  1609. PCLogMessage( PC_SERVICE_KILLED_PROCESS, EVENTLOG_INFORMATION_TYPE, ENTRY_COUNT(msgs), msgs );
  1610. }
  1611. return err;
  1612. }
  1613. // End of CProcConMgr.cpp
  1614. //============================================================================J McDonald fecit====//