Leaked source code of windows server 2003
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.

947 lines
30 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. pmon.c
  5. Abstract:
  6. This module contains the NT/Win32 Process Monitor
  7. Author:
  8. Lou Perazzoli (loup) 1-Jan-1993
  9. Revision History:
  10. --*/
  11. #include "perfmtrp.h"
  12. #include <search.h>
  13. #include <malloc.h>
  14. #include <limits.h>
  15. #include <stdlib.h>
  16. #define BUFFER_SIZE 64*1024
  17. #define MAX_BUFFER_SIZE 10*1024*1024
  18. ULONG CurrentBufferSize;
  19. PUCHAR PreviousBuffer;
  20. PUCHAR CurrentBuffer;
  21. PUCHAR TempBuffer;
  22. #define CPU_USAGE 0
  23. #define QUOTAS 1
  24. USHORT *NoNameFound = L"Unknown";
  25. USHORT *IdleProcess = L"Idle Process";
  26. UCHAR *StateTable[] = {
  27. "Initialized",
  28. "Ready",
  29. "Running",
  30. "Standby",
  31. "Terminated",
  32. "Wait:",
  33. "Transition",
  34. "Unknown",
  35. "Unknown",
  36. "Unknown",
  37. "Unknown",
  38. "Unknown"
  39. };
  40. BOOLEAN Interactive;
  41. ULONG NumberOfInputRecords;
  42. //INPUT_RECORD InputRecord;
  43. HANDLE InputHandle;
  44. HANDLE OriginalOutputHandle;
  45. HANDLE OutputHandle;
  46. DWORD OriginalInputMode;
  47. WORD NormalAttribute;
  48. WORD HighlightAttribute;
  49. ULONG NumberOfCols;
  50. ULONG NumberOfRows;
  51. ULONG NumberOfDetailLines;
  52. ULONG FirstDetailLine;
  53. CONSOLE_SCREEN_BUFFER_INFO OriginalConsoleInfo;
  54. UCHAR *WaitTable[] = {
  55. "Executive",
  56. "FreePage",
  57. "PageIn",
  58. "PoolAllocation",
  59. "DelayExecution",
  60. "Suspended",
  61. "UserRequest",
  62. "Executive",
  63. "FreePage",
  64. "PageIn",
  65. "PoolAllocation",
  66. "DelayExecution",
  67. "Suspended",
  68. "UserRequest",
  69. "EventPairHigh",
  70. "EventPairLow",
  71. "LpcReceive",
  72. "LpcReply",
  73. "Spare1",
  74. "Spare2",
  75. "Spare3",
  76. "Spare4",
  77. "Spare5",
  78. "Spare6",
  79. "Spare7",
  80. "Spare8",
  81. "Spare9",
  82. "Unknown",
  83. "Unknown",
  84. "Unknown",
  85. "Unknown"
  86. };
  87. UCHAR *Empty = " ";
  88. PSYSTEM_PROCESS_INFORMATION
  89. FindMatchedProcess (
  90. IN PSYSTEM_PROCESS_INFORMATION ProcessToMatch,
  91. IN PUCHAR SystemInfoBuffer,
  92. IN PULONG Hint
  93. );
  94. PSYSTEM_THREAD_INFORMATION
  95. FindMatchedThread (
  96. IN PSYSTEM_THREAD_INFORMATION ThreadToMatch,
  97. IN PSYSTEM_PROCESS_INFORMATION MatchedProcess
  98. );
  99. typedef struct _TOPCPU {
  100. LARGE_INTEGER TotalTime;
  101. PSYSTEM_PROCESS_INFORMATION ProcessInfo;
  102. PSYSTEM_PROCESS_INFORMATION MatchedProcess;
  103. ULONG Value;
  104. LONG PageFaultDiff;
  105. SIZE_T WorkingSetDiff;
  106. } TOPCPU, *PTOPCPU;
  107. // TOPCPU TopCpu[1000];
  108. // Required for Terminal Services
  109. PTOPCPU TopCpu;
  110. ULONG TopCpuSize;
  111. #define TOPCPU_BUFFER_SIZE (((300*sizeof(TOPCPU))/4096+1)*4096)
  112. #define TOPCPU_MAX_BUFFER_SIZE (50*TOPCPU_BUFFER_SIZE)
  113. BOOL
  114. WriteConsoleLine(
  115. HANDLE OutputHandle,
  116. WORD LineNumber,
  117. LPSTR Text,
  118. BOOL Highlight
  119. )
  120. {
  121. COORD WriteCoord;
  122. DWORD NumberWritten;
  123. DWORD TextLength;
  124. WriteCoord.X = 0;
  125. WriteCoord.Y = LineNumber;
  126. if (!FillConsoleOutputCharacter( OutputHandle,
  127. ' ',
  128. NumberOfCols,
  129. WriteCoord,
  130. &NumberWritten
  131. )
  132. ) {
  133. return FALSE;
  134. }
  135. if (Text == NULL || (TextLength = strlen( Text )) == 0) {
  136. return TRUE;
  137. }
  138. else {
  139. return WriteConsoleOutputCharacter( OutputHandle,
  140. Text,
  141. TextLength,
  142. WriteCoord,
  143. &NumberWritten
  144. );
  145. }
  146. }
  147. NTSTATUS
  148. GetProcessInfo (
  149. IN PUCHAR p
  150. )
  151. {
  152. NTSTATUS Status;
  153. retry01:
  154. Status = NtQuerySystemInformation(
  155. SystemProcessInformation,
  156. p,
  157. CurrentBufferSize,
  158. NULL
  159. );
  160. if (Status == STATUS_INFO_LENGTH_MISMATCH) {
  161. //
  162. // Increase buffer size.
  163. //
  164. CurrentBufferSize += 8192;
  165. TempBuffer = VirtualAlloc (CurrentBuffer,
  166. CurrentBufferSize,
  167. MEM_COMMIT,
  168. PAGE_READWRITE);
  169. if (TempBuffer == NULL) {
  170. printf("Memory commit failed\n");
  171. ExitProcess(0);
  172. }
  173. TempBuffer = VirtualAlloc (PreviousBuffer,
  174. CurrentBufferSize,
  175. MEM_COMMIT,
  176. PAGE_READWRITE);
  177. if (TempBuffer == NULL) {
  178. printf("Memory commit failed\n");
  179. ExitProcess(0);
  180. }
  181. goto retry01;
  182. }
  183. return Status;
  184. }
  185. int
  186. __cdecl main( argc, argv )
  187. int argc;
  188. char *argv[];
  189. {
  190. NTSTATUS Status;
  191. int i;
  192. ULONG DelayTimeMsec;
  193. ULONG DelayTimeTicks;
  194. ULONG LastCount;
  195. COORD cp;
  196. BOOLEAN Active;
  197. PSYSTEM_THREAD_INFORMATION Thread;
  198. SYSTEM_PERFORMANCE_INFORMATION PerfInfo;
  199. SYSTEM_FILECACHE_INFORMATION FileCache;
  200. SYSTEM_FILECACHE_INFORMATION PrevFileCache;
  201. CHAR OutputBuffer[ 512 ];
  202. UCHAR LastKey;
  203. LONG ScrollDelta;
  204. WORD DisplayLine, LastDetailRow;
  205. BOOLEAN DoQuit = FALSE;
  206. ULONG SkipLine;
  207. ULONG Hint;
  208. ULONG Offset1;
  209. SIZE_T SumCommit;
  210. int num;
  211. int lastnum;
  212. PSYSTEM_PROCESS_INFORMATION CurProcessInfo;
  213. PSYSTEM_PROCESS_INFORMATION MatchedProcess;
  214. LARGE_INTEGER LARGE_ZERO={0,0};
  215. LARGE_INTEGER Ktime;
  216. LARGE_INTEGER Utime;
  217. LARGE_INTEGER TotalTime;
  218. TIME_FIELDS TimeOut;
  219. PTOPCPU PTopCpu;
  220. SYSTEM_BASIC_INFORMATION BasicInfo;
  221. ULONG DisplayType = CPU_USAGE;
  222. INPUT_RECORD InputRecord;
  223. DWORD NumRead;
  224. ULONG Cpu;
  225. ULONG NoScreenChanges = FALSE;
  226. OutputBuffer[sizeof(OutputBuffer) - 1] = 0;
  227. if ( GetPriorityClass(GetCurrentProcess()) == NORMAL_PRIORITY_CLASS) {
  228. if (SetPriorityClass(GetCurrentProcess(),HIGH_PRIORITY_CLASS) == 0) {
  229. //
  230. // Not much we can do
  231. //
  232. printf("Cannot elevate process priority\n");
  233. return 0;
  234. }
  235. }
  236. InputHandle = GetStdHandle( STD_INPUT_HANDLE );
  237. OriginalOutputHandle = GetStdHandle( STD_OUTPUT_HANDLE );
  238. Interactive = TRUE;
  239. if (Interactive) {
  240. if (InputHandle == NULL ||
  241. OriginalOutputHandle == NULL ||
  242. !GetConsoleMode( InputHandle, &OriginalInputMode )
  243. ) {
  244. Interactive = FALSE;
  245. } else {
  246. OutputHandle = CreateConsoleScreenBuffer( GENERIC_READ | GENERIC_WRITE,
  247. FILE_SHARE_WRITE | FILE_SHARE_READ,
  248. NULL,
  249. CONSOLE_TEXTMODE_BUFFER,
  250. NULL
  251. );
  252. if (OutputHandle == NULL ||
  253. !GetConsoleScreenBufferInfo( OriginalOutputHandle, &OriginalConsoleInfo ) ||
  254. !SetConsoleScreenBufferSize( OutputHandle, OriginalConsoleInfo.dwSize ) ||
  255. !SetConsoleActiveScreenBuffer( OutputHandle ) ||
  256. !SetConsoleMode( InputHandle, 0 )
  257. ) {
  258. if (OutputHandle != NULL) {
  259. CloseHandle( OutputHandle );
  260. OutputHandle = NULL;
  261. }
  262. Interactive = FALSE;
  263. } else {
  264. NormalAttribute = 0x1F;
  265. HighlightAttribute = 0x71;
  266. NumberOfCols = OriginalConsoleInfo.dwSize.X;
  267. NumberOfRows = OriginalConsoleInfo.dwSize.Y;
  268. NumberOfDetailLines = NumberOfRows - 7;
  269. }
  270. }
  271. }
  272. Status = NtQuerySystemInformation(
  273. SystemBasicInformation,
  274. &BasicInfo,
  275. sizeof(BasicInfo),
  276. NULL
  277. );
  278. Status = NtQuerySystemInformation(
  279. SystemPerformanceInformation,
  280. &PerfInfo,
  281. sizeof(PerfInfo),
  282. NULL
  283. );
  284. DelayTimeMsec = 10;
  285. DelayTimeTicks = DelayTimeMsec * 10000;
  286. PreviousBuffer = VirtualAlloc (NULL,
  287. MAX_BUFFER_SIZE,
  288. MEM_RESERVE,
  289. PAGE_READWRITE);
  290. if (PreviousBuffer == NULL) {
  291. printf("Memory allocation failed\n");
  292. return 0;
  293. }
  294. TempBuffer = VirtualAlloc (PreviousBuffer,
  295. BUFFER_SIZE,
  296. MEM_COMMIT,
  297. PAGE_READWRITE);
  298. if (TempBuffer == NULL) {
  299. printf("Memory commit failed\n");
  300. return 0;
  301. }
  302. CurrentBuffer = VirtualAlloc (NULL,
  303. MAX_BUFFER_SIZE,
  304. MEM_RESERVE,
  305. PAGE_READWRITE);
  306. if (CurrentBuffer == NULL) {
  307. printf("Memory allocation failed\n");
  308. return 0;
  309. }
  310. TempBuffer = VirtualAlloc (CurrentBuffer,
  311. BUFFER_SIZE,
  312. MEM_COMMIT,
  313. PAGE_READWRITE);
  314. if (TempBuffer == NULL) {
  315. printf("Memory commit failed\n");
  316. return 0;
  317. }
  318. // TS
  319. TopCpu = VirtualAlloc (NULL,
  320. TOPCPU_MAX_BUFFER_SIZE,
  321. MEM_RESERVE,
  322. PAGE_READWRITE);
  323. if(TopCpu == NULL)
  324. {
  325. printf("Memory allocation failed\n");
  326. return 0;
  327. }
  328. TempBuffer = VirtualAlloc( TopCpu,
  329. TOPCPU_BUFFER_SIZE,
  330. MEM_COMMIT,
  331. PAGE_READWRITE);
  332. if( TempBuffer == NULL )
  333. {
  334. printf("Memory commit failed\n");
  335. return 0;
  336. }
  337. num = 0;
  338. TopCpuSize = TOPCPU_BUFFER_SIZE;
  339. CurrentBufferSize = BUFFER_SIZE;
  340. TempBuffer = NULL;
  341. Status = GetProcessInfo (PreviousBuffer);
  342. if( !NT_SUCCESS( Status ) )
  343. {
  344. printf("Get process information failed %lx\n", Status);
  345. return (0);
  346. }
  347. DelayTimeMsec = 5000;
  348. DelayTimeTicks = DelayTimeMsec * 10000;
  349. Status = GetProcessInfo (CurrentBuffer);
  350. if( !NT_SUCCESS( Status ) )
  351. {
  352. printf("Get process information failed %lx\n", Status);
  353. return (0);
  354. }
  355. Status = NtQuerySystemInformation(
  356. SystemPerformanceInformation,
  357. &PerfInfo,
  358. sizeof(PerfInfo),
  359. NULL
  360. );
  361. LastCount = PerfInfo.PageFaultCount;
  362. if ( !NT_SUCCESS(Status) ) {
  363. printf("Query perf Failed %lx\n",Status);
  364. return 0;
  365. }
  366. Status = NtQuerySystemInformation(
  367. SystemFileCacheInformation,
  368. &FileCache,
  369. sizeof(FileCache),
  370. NULL
  371. );
  372. PrevFileCache = FileCache;
  373. if ( !NT_SUCCESS(Status) ) {
  374. printf("Query file cache Failed %lx\n",Status);
  375. return 0;
  376. }
  377. Active = TRUE;
  378. while(TRUE) {
  379. Status = GetProcessInfo (CurrentBuffer);
  380. if( !NT_SUCCESS( Status ) )
  381. {
  382. printf("Get process information failed %lx\n", Status);
  383. return (0);
  384. }
  385. Status = NtQuerySystemInformation(
  386. SystemPerformanceInformation,
  387. &PerfInfo,
  388. sizeof(PerfInfo),
  389. NULL
  390. );
  391. if ( !NT_SUCCESS(Status) ) {
  392. printf("Query perf Failed %lx\n",Status);
  393. return 0;
  394. }
  395. Status = NtQuerySystemInformation(
  396. SystemFileCacheInformation,
  397. &FileCache,
  398. sizeof(FileCache),
  399. NULL
  400. );
  401. if ( !NT_SUCCESS(Status) ) {
  402. printf("Query file cache Failed %lx\n",Status);
  403. return 0;
  404. }
  405. //
  406. // Calculate top CPU users and display information.
  407. //
  408. //
  409. // Cross check previous process/thread info against current
  410. // process/thread info.
  411. //
  412. Offset1 = 0;
  413. lastnum = num;
  414. num = 0;
  415. Hint = 0;
  416. TotalTime = LARGE_ZERO;
  417. SumCommit = 0;
  418. while (TRUE) {
  419. CurProcessInfo = (PSYSTEM_PROCESS_INFORMATION)&CurrentBuffer[Offset1];
  420. //
  421. // Find the corresponding process in the previous array.
  422. //
  423. MatchedProcess = FindMatchedProcess (CurProcessInfo,
  424. PreviousBuffer,
  425. &Hint);
  426. if( num >= (int)( TopCpuSize / sizeof( TOPCPU ) ) )
  427. {
  428. TopCpuSize += 4096;
  429. if( VirtualAlloc( TopCpu, TopCpuSize, MEM_COMMIT, PAGE_READWRITE ) == NULL )
  430. {
  431. printf("Memory commit failed\n");
  432. return 0;
  433. }
  434. }
  435. if (MatchedProcess == NULL) {
  436. TopCpu[num].TotalTime = CurProcessInfo->KernelTime;
  437. TopCpu[num].TotalTime.QuadPart =
  438. TopCpu[num].TotalTime.QuadPart +
  439. CurProcessInfo->UserTime.QuadPart;
  440. TotalTime.QuadPart = TotalTime.QuadPart +
  441. TopCpu[num].TotalTime.QuadPart;
  442. TopCpu[num].ProcessInfo = CurProcessInfo;
  443. TopCpu[num].MatchedProcess = NULL;
  444. num += 1;
  445. } else {
  446. Ktime.QuadPart = CurProcessInfo->KernelTime.QuadPart -
  447. MatchedProcess->KernelTime.QuadPart;
  448. Utime.QuadPart = CurProcessInfo->UserTime.QuadPart -
  449. MatchedProcess->UserTime.QuadPart;
  450. TopCpu[num].TotalTime.QuadPart =
  451. Ktime.QuadPart +
  452. Utime.QuadPart;
  453. TotalTime.QuadPart = TotalTime.QuadPart +
  454. TopCpu[num].TotalTime.QuadPart;
  455. TopCpu[num].ProcessInfo = CurProcessInfo;
  456. TopCpu[num].MatchedProcess = MatchedProcess;
  457. TopCpu[num].PageFaultDiff =
  458. CurProcessInfo->PageFaultCount - MatchedProcess->PageFaultCount;
  459. ;
  460. TopCpu[num].WorkingSetDiff =
  461. CurProcessInfo->WorkingSetSize - MatchedProcess->WorkingSetSize;
  462. num += 1;
  463. }
  464. SumCommit += CurProcessInfo->PrivatePageCount / 1024;
  465. if (CurProcessInfo->NextEntryOffset == 0) {
  466. DisplayLine = 0;
  467. _snprintf (OutputBuffer, sizeof(OutputBuffer) - 1,
  468. " Memory:%8ldK Avail:%7ldK PageFlts:%6ld InRam Kernel:%5ldK P:%5ldK",
  469. BasicInfo.NumberOfPhysicalPages*(BasicInfo.PageSize/1024),
  470. PerfInfo.AvailablePages*(BasicInfo.PageSize/1024),
  471. PerfInfo.PageFaultCount - LastCount,
  472. (PerfInfo.ResidentSystemCodePage + PerfInfo.ResidentSystemDriverPage)*(BasicInfo.PageSize/1024),
  473. (PerfInfo.ResidentPagedPoolPage)*(BasicInfo.PageSize/1024)
  474. );
  475. LastCount = PerfInfo.PageFaultCount;
  476. WriteConsoleLine( OutputHandle,
  477. DisplayLine++,
  478. OutputBuffer,
  479. FALSE
  480. );
  481. _snprintf(OutputBuffer, sizeof(OutputBuffer) - 1,
  482. " Commit:%7ldK/%7ldK Limit:%7ldK Peak:%7ldK Pool N:%5ldK P:%5ldK",
  483. PerfInfo.CommittedPages*(BasicInfo.PageSize/1024),
  484. SumCommit,
  485. PerfInfo.CommitLimit*(BasicInfo.PageSize/1024),
  486. PerfInfo.PeakCommitment*(BasicInfo.PageSize/1024),
  487. PerfInfo.NonPagedPoolPages*(BasicInfo.PageSize/1024),
  488. PerfInfo.PagedPoolPages*(BasicInfo.PageSize/1024)
  489. );
  490. WriteConsoleLine( OutputHandle,
  491. DisplayLine++,
  492. OutputBuffer,
  493. FALSE
  494. );
  495. DisplayLine += 1;
  496. if (NoScreenChanges) {
  497. DisplayLine += 2;
  498. } else {
  499. WriteConsoleLine( OutputHandle,
  500. DisplayLine++,
  501. " Mem Mem Page Flts Commit Usage Pri Hnd Thd Image ",
  502. FALSE
  503. );
  504. WriteConsoleLine( OutputHandle,
  505. DisplayLine++,
  506. "CPU CpuTime Usage Diff Faults Diff Charge NonP Page Cnt Cnt Name ",
  507. FALSE
  508. );
  509. }
  510. DisplayLine += 1;
  511. _snprintf(OutputBuffer, sizeof(OutputBuffer) - 1,
  512. " %6ld%5ld%9ld %4ld File Cache ",
  513. FileCache.CurrentSize/1024,
  514. ((LONG)FileCache.CurrentSize - (LONG)PrevFileCache.CurrentSize)/1024,
  515. FileCache.PageFaultCount,
  516. (LONG)FileCache.PageFaultCount - (LONG)PrevFileCache.PageFaultCount
  517. );
  518. WriteConsoleLine( OutputHandle,
  519. DisplayLine++,
  520. OutputBuffer,
  521. FALSE
  522. );
  523. PrevFileCache = FileCache;
  524. LastDetailRow = (WORD)NumberOfRows;
  525. for (i = FirstDetailLine; i < num; i++) {
  526. if (DisplayLine >= LastDetailRow) {
  527. break;
  528. }
  529. PTopCpu = &TopCpu[i];
  530. Ktime.QuadPart =
  531. PTopCpu->ProcessInfo->KernelTime.QuadPart +
  532. PTopCpu->ProcessInfo->UserTime.QuadPart;
  533. RtlTimeToElapsedTimeFields ( &Ktime, &TimeOut);
  534. TimeOut.Hour += TimeOut.Day*24;
  535. if (PTopCpu->ProcessInfo->ImageName.Buffer == NULL) {
  536. if (PTopCpu->ProcessInfo->UniqueProcessId == (HANDLE)0) {
  537. PTopCpu->ProcessInfo->ImageName.Buffer = (PWSTR)IdleProcess;
  538. } else {
  539. PTopCpu->ProcessInfo->ImageName.Buffer = (PWSTR)NoNameFound;
  540. }
  541. } else {
  542. if (PTopCpu->ProcessInfo->ImageName.Length > 24) {
  543. PTopCpu->ProcessInfo->ImageName.Buffer +=
  544. ((PTopCpu->ProcessInfo->ImageName.Length) - 24);
  545. }
  546. }
  547. Cpu = PTopCpu->TotalTime.LowPart / ((TotalTime.LowPart / 100) ? (TotalTime.LowPart / 100) : 1);
  548. if ( Cpu == 100 ) {
  549. Cpu = 99;
  550. }
  551. //
  552. // See if nothing has changed.
  553. //
  554. SkipLine = FALSE;
  555. if ((PTopCpu->MatchedProcess != NULL) &&
  556. (Cpu == 0) &&
  557. (PTopCpu->WorkingSetDiff == 0) &&
  558. (PTopCpu->PageFaultDiff == 0) &&
  559. (PTopCpu->MatchedProcess->NumberOfThreads ==
  560. PTopCpu->ProcessInfo->NumberOfThreads) &&
  561. (PTopCpu->MatchedProcess->HandleCount ==
  562. PTopCpu->ProcessInfo->HandleCount) &&
  563. (PTopCpu->MatchedProcess->PrivatePageCount ==
  564. PTopCpu->ProcessInfo->PrivatePageCount)) {
  565. PTopCpu->ProcessInfo->PeakPagefileUsage = 0xffffffff;
  566. PTopCpu->ProcessInfo->PeakWorkingSetSize = DisplayLine;
  567. if ((PTopCpu->MatchedProcess->PeakPagefileUsage == 0xffffffff) &&
  568. (PTopCpu->MatchedProcess->PeakWorkingSetSize == DisplayLine) &&
  569. (NoScreenChanges)) {
  570. SkipLine = TRUE;
  571. }
  572. }
  573. if (SkipLine) {
  574. //
  575. // The line on the screen has not changed, just skip
  576. // writing this one.
  577. //
  578. DisplayLine += 1;
  579. } else {
  580. _snprintf(OutputBuffer, sizeof(OutputBuffer) - 1,
  581. "%2ld%4ld:%02ld:%02ld%7ld%5ld%9ld%5ld%7ld%5ld%5ld %2ld%5ld%3ld %ws",
  582. Cpu,
  583. TimeOut.Hour,
  584. TimeOut.Minute,
  585. TimeOut.Second,
  586. PTopCpu->ProcessInfo->WorkingSetSize / 1024,
  587. (ULONG)(PTopCpu->WorkingSetDiff / 1024),
  588. PTopCpu->ProcessInfo->PageFaultCount,
  589. PTopCpu->PageFaultDiff,
  590. PTopCpu->ProcessInfo->PrivatePageCount / 1024,
  591. PTopCpu->ProcessInfo->QuotaNonPagedPoolUsage / 1024,
  592. PTopCpu->ProcessInfo->QuotaPagedPoolUsage / 1024,
  593. PTopCpu->ProcessInfo->BasePriority,
  594. PTopCpu->ProcessInfo->HandleCount,
  595. PTopCpu->ProcessInfo->NumberOfThreads,
  596. PTopCpu->ProcessInfo->ImageName.Buffer
  597. );
  598. WriteConsoleLine( OutputHandle,
  599. DisplayLine++,
  600. OutputBuffer,
  601. FALSE
  602. );
  603. }
  604. Thread = (PSYSTEM_THREAD_INFORMATION)(TopCpu[i].ProcessInfo + 1);
  605. }
  606. while (lastnum > num) {
  607. WriteConsoleLine( OutputHandle,
  608. DisplayLine++,
  609. " ",
  610. FALSE);
  611. lastnum -= 1;
  612. }
  613. }
  614. if (CurProcessInfo->NextEntryOffset == 0) {
  615. break;
  616. }
  617. Offset1 += CurProcessInfo->NextEntryOffset;
  618. } //end while
  619. TempBuffer = PreviousBuffer;
  620. PreviousBuffer = CurrentBuffer;
  621. CurrentBuffer = TempBuffer;
  622. NoScreenChanges = TRUE;
  623. while (WaitForSingleObject( InputHandle, DelayTimeMsec ) == STATUS_WAIT_0) {
  624. //
  625. // Check for input record
  626. //
  627. if (ReadConsoleInput( InputHandle, &InputRecord, 1, &NumberOfInputRecords ) &&
  628. InputRecord.EventType == KEY_EVENT &&
  629. InputRecord.Event.KeyEvent.bKeyDown
  630. ) {
  631. LastKey = InputRecord.Event.KeyEvent.uChar.AsciiChar;
  632. if (LastKey < ' ') {
  633. ScrollDelta = 0;
  634. if (LastKey == 'C'-'A'+1) {
  635. DoQuit = TRUE;
  636. } else switch (InputRecord.Event.KeyEvent.wVirtualKeyCode) {
  637. case VK_ESCAPE:
  638. DoQuit = TRUE;
  639. break;
  640. case VK_PRIOR:
  641. ScrollDelta = -(LONG)(InputRecord.Event.KeyEvent.wRepeatCount * NumberOfDetailLines);
  642. break;
  643. case VK_NEXT:
  644. ScrollDelta = InputRecord.Event.KeyEvent.wRepeatCount * NumberOfDetailLines;
  645. break;
  646. case VK_UP:
  647. ScrollDelta = -InputRecord.Event.KeyEvent.wRepeatCount;
  648. break;
  649. case VK_DOWN:
  650. ScrollDelta = InputRecord.Event.KeyEvent.wRepeatCount;
  651. break;
  652. case VK_HOME:
  653. FirstDetailLine = 0;
  654. break;
  655. case VK_END:
  656. if ((ULONG)num > NumberOfDetailLines) {
  657. FirstDetailLine = num - NumberOfDetailLines;
  658. NoScreenChanges = FALSE;
  659. }
  660. break;
  661. }
  662. if (ScrollDelta != 0) {
  663. if (ScrollDelta < 0) {
  664. if (FirstDetailLine <= (ULONG)-ScrollDelta) {
  665. FirstDetailLine = 0;
  666. NoScreenChanges = FALSE;
  667. } else {
  668. FirstDetailLine += ScrollDelta;
  669. NoScreenChanges = FALSE;
  670. }
  671. } else {
  672. FirstDetailLine += ScrollDelta;
  673. NoScreenChanges = FALSE;
  674. if (FirstDetailLine >= (num - NumberOfDetailLines)) {
  675. FirstDetailLine = num - NumberOfDetailLines;
  676. }
  677. }
  678. }
  679. } else {
  680. switch (toupper( LastKey )) {
  681. case 'C':
  682. case 'c':
  683. DisplayType = CPU_USAGE;
  684. break;
  685. case 'P':
  686. case 'p':
  687. DisplayType = QUOTAS;
  688. break;
  689. case 'q':
  690. case 'Q':
  691. DoQuit = TRUE;
  692. break;
  693. default:
  694. break;
  695. }
  696. }
  697. break;
  698. }
  699. }
  700. if (DoQuit) {
  701. if (Interactive) {
  702. SetConsoleActiveScreenBuffer( OriginalOutputHandle );
  703. SetConsoleMode( InputHandle, OriginalInputMode );
  704. CloseHandle( OutputHandle );
  705. }
  706. return 0;
  707. }
  708. }
  709. return 0;
  710. }
  711. PSYSTEM_PROCESS_INFORMATION
  712. FindMatchedProcess (
  713. IN PSYSTEM_PROCESS_INFORMATION ProcessToMatch,
  714. IN PUCHAR SystemInfoBuffer,
  715. IN OUT PULONG Hint
  716. )
  717. /*++
  718. Routine Description:
  719. This procedure finds the process which corresponds to the ProcessToMatch.
  720. It returns the address of the matching Process, or NULL if no
  721. matching process was found.
  722. Arguments:
  723. ProcessToMatch - Supplies a pointer to the target thread to match.
  724. SystemInfoBuffer - Supples a pointer to the system information
  725. buffer in which to locate the process.
  726. Hint - Supplies and returns a hint for optimizing the searches.
  727. Return Value:
  728. Address of the corresponding Process or NULL.
  729. --*/
  730. {
  731. PSYSTEM_PROCESS_INFORMATION Process;
  732. ULONG Offset2;
  733. Offset2 = *Hint;
  734. while (TRUE) {
  735. Process = (PSYSTEM_PROCESS_INFORMATION)&SystemInfoBuffer[Offset2];
  736. if ((Process->UniqueProcessId ==
  737. ProcessToMatch->UniqueProcessId) &&
  738. (Process->CreateTime.QuadPart ==
  739. ProcessToMatch->CreateTime.QuadPart)) {
  740. *Hint = Offset2 + Process->NextEntryOffset;
  741. return(Process);
  742. }
  743. Offset2 += Process->NextEntryOffset;
  744. if (Offset2 == *Hint) {
  745. *Hint = 0;
  746. return(NULL);
  747. }
  748. if (Process->NextEntryOffset == 0) {
  749. if (*Hint == 0) {
  750. return(NULL);
  751. }
  752. Offset2 = 0;
  753. }
  754. }
  755. }
  756. PSYSTEM_THREAD_INFORMATION
  757. FindMatchedThread (
  758. IN PSYSTEM_THREAD_INFORMATION ThreadToMatch,
  759. IN PSYSTEM_PROCESS_INFORMATION MatchedProcess
  760. )
  761. /*++
  762. Routine Description:
  763. This procedure finds thread which corresponds to the ThreadToMatch.
  764. It returns the address of the matching thread, or NULL if no
  765. matching thread was found.
  766. Arguments:
  767. ThreadToMatch - Supplies a pointer to the target thread to match.
  768. MatchedProcess - Supples a pointer to the process which contains
  769. the target thread. The thread information
  770. must follow this process, i.e., this block was
  771. obtain from a NtQuerySystemInformation specifying
  772. PROCESS_INFORMATION.
  773. Return Value:
  774. Address of the corresponding thread from MatchedProcess or NULL.
  775. --*/
  776. {
  777. PSYSTEM_THREAD_INFORMATION Thread;
  778. ULONG i;
  779. Thread = (PSYSTEM_THREAD_INFORMATION)(MatchedProcess + 1);
  780. for (i = 0; i < MatchedProcess->NumberOfThreads; i++) {
  781. if ((Thread->ClientId.UniqueThread ==
  782. ThreadToMatch->ClientId.UniqueThread) &&
  783. (Thread->CreateTime.QuadPart ==
  784. ThreadToMatch->CreateTime.QuadPart)) {
  785. return(Thread);
  786. }
  787. Thread += 1;
  788. }
  789. return(NULL);
  790. }