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.

939 lines
29 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. if ( GetPriorityClass(GetCurrentProcess()) == NORMAL_PRIORITY_CLASS) {
  227. SetPriorityClass(GetCurrentProcess(),HIGH_PRIORITY_CLASS);
  228. }
  229. InputHandle = GetStdHandle( STD_INPUT_HANDLE );
  230. OriginalOutputHandle = GetStdHandle( STD_OUTPUT_HANDLE );
  231. Interactive = TRUE;
  232. if (Interactive) {
  233. if (InputHandle == NULL ||
  234. OriginalOutputHandle == NULL ||
  235. !GetConsoleMode( InputHandle, &OriginalInputMode )
  236. ) {
  237. Interactive = FALSE;
  238. } else {
  239. OutputHandle = CreateConsoleScreenBuffer( GENERIC_READ | GENERIC_WRITE,
  240. FILE_SHARE_WRITE | FILE_SHARE_READ,
  241. NULL,
  242. CONSOLE_TEXTMODE_BUFFER,
  243. NULL
  244. );
  245. if (OutputHandle == NULL ||
  246. !GetConsoleScreenBufferInfo( OriginalOutputHandle, &OriginalConsoleInfo ) ||
  247. !SetConsoleScreenBufferSize( OutputHandle, OriginalConsoleInfo.dwSize ) ||
  248. !SetConsoleActiveScreenBuffer( OutputHandle ) ||
  249. !SetConsoleMode( InputHandle, 0 )
  250. ) {
  251. if (OutputHandle != NULL) {
  252. CloseHandle( OutputHandle );
  253. OutputHandle = NULL;
  254. }
  255. Interactive = FALSE;
  256. } else {
  257. NormalAttribute = 0x1F;
  258. HighlightAttribute = 0x71;
  259. NumberOfCols = OriginalConsoleInfo.dwSize.X;
  260. NumberOfRows = OriginalConsoleInfo.dwSize.Y;
  261. NumberOfDetailLines = NumberOfRows - 7;
  262. }
  263. }
  264. }
  265. Status = NtQuerySystemInformation(
  266. SystemBasicInformation,
  267. &BasicInfo,
  268. sizeof(BasicInfo),
  269. NULL
  270. );
  271. Status = NtQuerySystemInformation(
  272. SystemPerformanceInformation,
  273. &PerfInfo,
  274. sizeof(PerfInfo),
  275. NULL
  276. );
  277. DelayTimeMsec = 10;
  278. DelayTimeTicks = DelayTimeMsec * 10000;
  279. PreviousBuffer = VirtualAlloc (NULL,
  280. MAX_BUFFER_SIZE,
  281. MEM_RESERVE,
  282. PAGE_READWRITE);
  283. if (PreviousBuffer == NULL) {
  284. printf("Memory allocation failed\n");
  285. return 0;
  286. }
  287. TempBuffer = VirtualAlloc (PreviousBuffer,
  288. BUFFER_SIZE,
  289. MEM_COMMIT,
  290. PAGE_READWRITE);
  291. if (TempBuffer == NULL) {
  292. printf("Memory commit failed\n");
  293. return 0;
  294. }
  295. CurrentBuffer = VirtualAlloc (NULL,
  296. MAX_BUFFER_SIZE,
  297. MEM_RESERVE,
  298. PAGE_READWRITE);
  299. if (CurrentBuffer == NULL) {
  300. printf("Memory allocation failed\n");
  301. return 0;
  302. }
  303. TempBuffer = VirtualAlloc (CurrentBuffer,
  304. BUFFER_SIZE,
  305. MEM_COMMIT,
  306. PAGE_READWRITE);
  307. if (TempBuffer == NULL) {
  308. printf("Memory commit failed\n");
  309. return 0;
  310. }
  311. // TS
  312. TopCpu = VirtualAlloc (NULL,
  313. TOPCPU_MAX_BUFFER_SIZE,
  314. MEM_RESERVE,
  315. PAGE_READWRITE);
  316. if(TopCpu == NULL)
  317. {
  318. printf("Memory allocation failed\n");
  319. return 0;
  320. }
  321. TempBuffer = VirtualAlloc( TopCpu,
  322. TOPCPU_BUFFER_SIZE,
  323. MEM_COMMIT,
  324. PAGE_READWRITE);
  325. if( TempBuffer == NULL )
  326. {
  327. printf("Memory commit failed\n");
  328. return 0;
  329. }
  330. num = 0;
  331. TopCpuSize = TOPCPU_BUFFER_SIZE;
  332. CurrentBufferSize = BUFFER_SIZE;
  333. TempBuffer = NULL;
  334. Status = GetProcessInfo (PreviousBuffer);
  335. if( !NT_SUCCESS( Status ) )
  336. {
  337. printf("Get process information failed %lx\n", Status);
  338. return (0);
  339. }
  340. DelayTimeMsec = 5000;
  341. DelayTimeTicks = DelayTimeMsec * 10000;
  342. Status = GetProcessInfo (CurrentBuffer);
  343. if( !NT_SUCCESS( Status ) )
  344. {
  345. printf("Get process information failed %lx\n", Status);
  346. return (0);
  347. }
  348. Status = NtQuerySystemInformation(
  349. SystemPerformanceInformation,
  350. &PerfInfo,
  351. sizeof(PerfInfo),
  352. NULL
  353. );
  354. LastCount = PerfInfo.PageFaultCount;
  355. if ( !NT_SUCCESS(Status) ) {
  356. printf("Query perf Failed %lx\n",Status);
  357. return 0;
  358. }
  359. Status = NtQuerySystemInformation(
  360. SystemFileCacheInformation,
  361. &FileCache,
  362. sizeof(FileCache),
  363. NULL
  364. );
  365. PrevFileCache = FileCache;
  366. if ( !NT_SUCCESS(Status) ) {
  367. printf("Query file cache Failed %lx\n",Status);
  368. return 0;
  369. }
  370. Active = TRUE;
  371. while(TRUE) {
  372. Status = GetProcessInfo (CurrentBuffer);
  373. if( !NT_SUCCESS( Status ) )
  374. {
  375. printf("Get process information failed %lx\n", Status);
  376. return (0);
  377. }
  378. Status = NtQuerySystemInformation(
  379. SystemPerformanceInformation,
  380. &PerfInfo,
  381. sizeof(PerfInfo),
  382. NULL
  383. );
  384. if ( !NT_SUCCESS(Status) ) {
  385. printf("Query perf Failed %lx\n",Status);
  386. return 0;
  387. }
  388. Status = NtQuerySystemInformation(
  389. SystemFileCacheInformation,
  390. &FileCache,
  391. sizeof(FileCache),
  392. NULL
  393. );
  394. if ( !NT_SUCCESS(Status) ) {
  395. printf("Query file cache Failed %lx\n",Status);
  396. return 0;
  397. }
  398. //
  399. // Calculate top CPU users and display information.
  400. //
  401. //
  402. // Cross check previous process/thread info against current
  403. // process/thread info.
  404. //
  405. Offset1 = 0;
  406. lastnum = num;
  407. num = 0;
  408. Hint = 0;
  409. TotalTime = LARGE_ZERO;
  410. SumCommit = 0;
  411. while (TRUE) {
  412. CurProcessInfo = (PSYSTEM_PROCESS_INFORMATION)&CurrentBuffer[Offset1];
  413. //
  414. // Find the corresponding process in the previous array.
  415. //
  416. MatchedProcess = FindMatchedProcess (CurProcessInfo,
  417. PreviousBuffer,
  418. &Hint);
  419. if( num >= (int)( TopCpuSize / sizeof( TOPCPU ) ) )
  420. {
  421. TopCpuSize += 4096;
  422. if( VirtualAlloc( TopCpu, TopCpuSize, MEM_COMMIT, PAGE_READWRITE ) == NULL )
  423. {
  424. printf("Memory commit failed\n");
  425. return 0;
  426. }
  427. }
  428. if (MatchedProcess == NULL) {
  429. TopCpu[num].TotalTime = CurProcessInfo->KernelTime;
  430. TopCpu[num].TotalTime.QuadPart =
  431. TopCpu[num].TotalTime.QuadPart +
  432. CurProcessInfo->UserTime.QuadPart;
  433. TotalTime.QuadPart = TotalTime.QuadPart +
  434. TopCpu[num].TotalTime.QuadPart;
  435. TopCpu[num].ProcessInfo = CurProcessInfo;
  436. TopCpu[num].MatchedProcess = NULL;
  437. num += 1;
  438. } else {
  439. Ktime.QuadPart = CurProcessInfo->KernelTime.QuadPart -
  440. MatchedProcess->KernelTime.QuadPart;
  441. Utime.QuadPart = CurProcessInfo->UserTime.QuadPart -
  442. MatchedProcess->UserTime.QuadPart;
  443. TopCpu[num].TotalTime.QuadPart =
  444. Ktime.QuadPart +
  445. Utime.QuadPart;
  446. TotalTime.QuadPart = TotalTime.QuadPart +
  447. TopCpu[num].TotalTime.QuadPart;
  448. TopCpu[num].ProcessInfo = CurProcessInfo;
  449. TopCpu[num].MatchedProcess = MatchedProcess;
  450. TopCpu[num].PageFaultDiff =
  451. CurProcessInfo->PageFaultCount - MatchedProcess->PageFaultCount;
  452. ;
  453. TopCpu[num].WorkingSetDiff =
  454. CurProcessInfo->WorkingSetSize - MatchedProcess->WorkingSetSize;
  455. num += 1;
  456. }
  457. SumCommit += CurProcessInfo->PrivatePageCount / 1024;
  458. if (CurProcessInfo->NextEntryOffset == 0) {
  459. DisplayLine = 0;
  460. sprintf (OutputBuffer,
  461. " Memory:%8ldK Avail:%7ldK PageFlts:%6ld InRam Kernel:%5ldK P:%5ldK",
  462. BasicInfo.NumberOfPhysicalPages*(BasicInfo.PageSize/1024),
  463. PerfInfo.AvailablePages*(BasicInfo.PageSize/1024),
  464. PerfInfo.PageFaultCount - LastCount,
  465. (PerfInfo.ResidentSystemCodePage + PerfInfo.ResidentSystemDriverPage)*(BasicInfo.PageSize/1024),
  466. (PerfInfo.ResidentPagedPoolPage)*(BasicInfo.PageSize/1024)
  467. );
  468. LastCount = PerfInfo.PageFaultCount;
  469. WriteConsoleLine( OutputHandle,
  470. DisplayLine++,
  471. OutputBuffer,
  472. FALSE
  473. );
  474. sprintf(OutputBuffer,
  475. " Commit:%7ldK/%7ldK Limit:%7ldK Peak:%7ldK Pool N:%5ldK P:%5ldK",
  476. PerfInfo.CommittedPages*(BasicInfo.PageSize/1024),
  477. SumCommit,
  478. PerfInfo.CommitLimit*(BasicInfo.PageSize/1024),
  479. PerfInfo.PeakCommitment*(BasicInfo.PageSize/1024),
  480. PerfInfo.NonPagedPoolPages*(BasicInfo.PageSize/1024),
  481. PerfInfo.PagedPoolPages*(BasicInfo.PageSize/1024)
  482. );
  483. WriteConsoleLine( OutputHandle,
  484. DisplayLine++,
  485. OutputBuffer,
  486. FALSE
  487. );
  488. DisplayLine += 1;
  489. if (NoScreenChanges) {
  490. DisplayLine += 2;
  491. } else {
  492. WriteConsoleLine( OutputHandle,
  493. DisplayLine++,
  494. " Mem Mem Page Flts Commit Usage Pri Hnd Thd Image ",
  495. FALSE
  496. );
  497. WriteConsoleLine( OutputHandle,
  498. DisplayLine++,
  499. "CPU CpuTime Usage Diff Faults Diff Charge NonP Page Cnt Cnt Name ",
  500. FALSE
  501. );
  502. }
  503. DisplayLine += 1;
  504. sprintf(OutputBuffer,
  505. " %6ld%5ld%9ld %4ld File Cache ",
  506. FileCache.CurrentSize/1024,
  507. ((LONG)FileCache.CurrentSize - (LONG)PrevFileCache.CurrentSize)/1024,
  508. FileCache.PageFaultCount,
  509. (LONG)FileCache.PageFaultCount - (LONG)PrevFileCache.PageFaultCount
  510. );
  511. WriteConsoleLine( OutputHandle,
  512. DisplayLine++,
  513. OutputBuffer,
  514. FALSE
  515. );
  516. PrevFileCache = FileCache;
  517. LastDetailRow = (WORD)NumberOfRows;
  518. for (i = FirstDetailLine; i < num; i++) {
  519. if (DisplayLine >= LastDetailRow) {
  520. break;
  521. }
  522. PTopCpu = &TopCpu[i];
  523. Ktime.QuadPart =
  524. PTopCpu->ProcessInfo->KernelTime.QuadPart +
  525. PTopCpu->ProcessInfo->UserTime.QuadPart;
  526. RtlTimeToElapsedTimeFields ( &Ktime, &TimeOut);
  527. TimeOut.Hour += TimeOut.Day*24;
  528. if (PTopCpu->ProcessInfo->ImageName.Buffer == NULL) {
  529. if (PTopCpu->ProcessInfo->UniqueProcessId == (HANDLE)0) {
  530. PTopCpu->ProcessInfo->ImageName.Buffer = (PWSTR)IdleProcess;
  531. } else {
  532. PTopCpu->ProcessInfo->ImageName.Buffer = (PWSTR)NoNameFound;
  533. }
  534. } else {
  535. if (PTopCpu->ProcessInfo->ImageName.Length > 24) {
  536. PTopCpu->ProcessInfo->ImageName.Buffer +=
  537. ((PTopCpu->ProcessInfo->ImageName.Length) - 24);
  538. }
  539. }
  540. Cpu = PTopCpu->TotalTime.LowPart / ((TotalTime.LowPart / 100) ? (TotalTime.LowPart / 100) : 1);
  541. if ( Cpu == 100 ) {
  542. Cpu = 99;
  543. }
  544. //
  545. // See if nothing has changed.
  546. //
  547. SkipLine = FALSE;
  548. if ((PTopCpu->MatchedProcess != NULL) &&
  549. (Cpu == 0) &&
  550. (PTopCpu->WorkingSetDiff == 0) &&
  551. (PTopCpu->PageFaultDiff == 0) &&
  552. (PTopCpu->MatchedProcess->NumberOfThreads ==
  553. PTopCpu->ProcessInfo->NumberOfThreads) &&
  554. (PTopCpu->MatchedProcess->HandleCount ==
  555. PTopCpu->ProcessInfo->HandleCount) &&
  556. (PTopCpu->MatchedProcess->PrivatePageCount ==
  557. PTopCpu->ProcessInfo->PrivatePageCount)) {
  558. PTopCpu->ProcessInfo->PeakPagefileUsage = 0xffffffff;
  559. PTopCpu->ProcessInfo->PeakWorkingSetSize = DisplayLine;
  560. if ((PTopCpu->MatchedProcess->PeakPagefileUsage == 0xffffffff) &&
  561. (PTopCpu->MatchedProcess->PeakWorkingSetSize == DisplayLine) &&
  562. (NoScreenChanges)) {
  563. SkipLine = TRUE;
  564. }
  565. }
  566. if (SkipLine) {
  567. //
  568. // The line on the screen has not changed, just skip
  569. // writing this one.
  570. //
  571. DisplayLine += 1;
  572. } else {
  573. sprintf(OutputBuffer,
  574. "%2ld%4ld:%02ld:%02ld%7ld%5ld%9ld%5ld%7ld%5ld%5ld %2ld%5ld%3ld %ws",
  575. Cpu,
  576. TimeOut.Hour,
  577. TimeOut.Minute,
  578. TimeOut.Second,
  579. PTopCpu->ProcessInfo->WorkingSetSize / 1024,
  580. (ULONG)(PTopCpu->WorkingSetDiff / 1024),
  581. PTopCpu->ProcessInfo->PageFaultCount,
  582. PTopCpu->PageFaultDiff,
  583. PTopCpu->ProcessInfo->PrivatePageCount / 1024,
  584. PTopCpu->ProcessInfo->QuotaNonPagedPoolUsage / 1024,
  585. PTopCpu->ProcessInfo->QuotaPagedPoolUsage / 1024,
  586. PTopCpu->ProcessInfo->BasePriority,
  587. PTopCpu->ProcessInfo->HandleCount,
  588. PTopCpu->ProcessInfo->NumberOfThreads,
  589. PTopCpu->ProcessInfo->ImageName.Buffer
  590. );
  591. WriteConsoleLine( OutputHandle,
  592. DisplayLine++,
  593. OutputBuffer,
  594. FALSE
  595. );
  596. }
  597. Thread = (PSYSTEM_THREAD_INFORMATION)(TopCpu[i].ProcessInfo + 1);
  598. }
  599. while (lastnum > num) {
  600. WriteConsoleLine( OutputHandle,
  601. DisplayLine++,
  602. " ",
  603. FALSE);
  604. lastnum -= 1;
  605. }
  606. }
  607. if (CurProcessInfo->NextEntryOffset == 0) {
  608. break;
  609. }
  610. Offset1 += CurProcessInfo->NextEntryOffset;
  611. } //end while
  612. TempBuffer = PreviousBuffer;
  613. PreviousBuffer = CurrentBuffer;
  614. CurrentBuffer = TempBuffer;
  615. NoScreenChanges = TRUE;
  616. while (WaitForSingleObject( InputHandle, DelayTimeMsec ) == STATUS_WAIT_0) {
  617. //
  618. // Check for input record
  619. //
  620. if (ReadConsoleInput( InputHandle, &InputRecord, 1, &NumberOfInputRecords ) &&
  621. InputRecord.EventType == KEY_EVENT &&
  622. InputRecord.Event.KeyEvent.bKeyDown
  623. ) {
  624. LastKey = InputRecord.Event.KeyEvent.uChar.AsciiChar;
  625. if (LastKey < ' ') {
  626. ScrollDelta = 0;
  627. if (LastKey == 'C'-'A'+1) {
  628. DoQuit = TRUE;
  629. } else switch (InputRecord.Event.KeyEvent.wVirtualKeyCode) {
  630. case VK_ESCAPE:
  631. DoQuit = TRUE;
  632. break;
  633. case VK_PRIOR:
  634. ScrollDelta = -(LONG)(InputRecord.Event.KeyEvent.wRepeatCount * NumberOfDetailLines);
  635. break;
  636. case VK_NEXT:
  637. ScrollDelta = InputRecord.Event.KeyEvent.wRepeatCount * NumberOfDetailLines;
  638. break;
  639. case VK_UP:
  640. ScrollDelta = -InputRecord.Event.KeyEvent.wRepeatCount;
  641. break;
  642. case VK_DOWN:
  643. ScrollDelta = InputRecord.Event.KeyEvent.wRepeatCount;
  644. break;
  645. case VK_HOME:
  646. FirstDetailLine = 0;
  647. break;
  648. case VK_END:
  649. if ((ULONG)num > NumberOfDetailLines) {
  650. FirstDetailLine = num - NumberOfDetailLines;
  651. NoScreenChanges = FALSE;
  652. }
  653. break;
  654. }
  655. if (ScrollDelta != 0) {
  656. if (ScrollDelta < 0) {
  657. if (FirstDetailLine <= (ULONG)-ScrollDelta) {
  658. FirstDetailLine = 0;
  659. NoScreenChanges = FALSE;
  660. } else {
  661. FirstDetailLine += ScrollDelta;
  662. NoScreenChanges = FALSE;
  663. }
  664. } else {
  665. FirstDetailLine += ScrollDelta;
  666. NoScreenChanges = FALSE;
  667. if (FirstDetailLine >= (num - NumberOfDetailLines)) {
  668. FirstDetailLine = num - NumberOfDetailLines;
  669. }
  670. }
  671. }
  672. } else {
  673. switch (toupper( LastKey )) {
  674. case 'C':
  675. case 'c':
  676. DisplayType = CPU_USAGE;
  677. break;
  678. case 'P':
  679. case 'p':
  680. DisplayType = QUOTAS;
  681. break;
  682. case 'q':
  683. case 'Q':
  684. DoQuit = TRUE;
  685. break;
  686. default:
  687. break;
  688. }
  689. }
  690. break;
  691. }
  692. }
  693. if (DoQuit) {
  694. if (Interactive) {
  695. SetConsoleActiveScreenBuffer( OriginalOutputHandle );
  696. SetConsoleMode( InputHandle, OriginalInputMode );
  697. CloseHandle( OutputHandle );
  698. }
  699. return 0;
  700. }
  701. }
  702. return 0;
  703. }
  704. PSYSTEM_PROCESS_INFORMATION
  705. FindMatchedProcess (
  706. IN PSYSTEM_PROCESS_INFORMATION ProcessToMatch,
  707. IN PUCHAR SystemInfoBuffer,
  708. IN OUT PULONG Hint
  709. )
  710. /*++
  711. Routine Description:
  712. This procedure finds the process which corresponds to the ProcessToMatch.
  713. It returns the address of the matching Process, or NULL if no
  714. matching process was found.
  715. Arguments:
  716. ProcessToMatch - Supplies a pointer to the target thread to match.
  717. SystemInfoBuffer - Supples a pointer to the system information
  718. buffer in which to locate the process.
  719. Hint - Supplies and returns a hint for optimizing the searches.
  720. Return Value:
  721. Address of the corresponding Process or NULL.
  722. --*/
  723. {
  724. PSYSTEM_PROCESS_INFORMATION Process;
  725. ULONG Offset2;
  726. Offset2 = *Hint;
  727. while (TRUE) {
  728. Process = (PSYSTEM_PROCESS_INFORMATION)&SystemInfoBuffer[Offset2];
  729. if ((Process->UniqueProcessId ==
  730. ProcessToMatch->UniqueProcessId) &&
  731. (Process->CreateTime.QuadPart ==
  732. ProcessToMatch->CreateTime.QuadPart)) {
  733. *Hint = Offset2 + Process->NextEntryOffset;
  734. return(Process);
  735. }
  736. Offset2 += Process->NextEntryOffset;
  737. if (Offset2 == *Hint) {
  738. *Hint = 0;
  739. return(NULL);
  740. }
  741. if (Process->NextEntryOffset == 0) {
  742. if (*Hint == 0) {
  743. return(NULL);
  744. }
  745. Offset2 = 0;
  746. }
  747. }
  748. }
  749. PSYSTEM_THREAD_INFORMATION
  750. FindMatchedThread (
  751. IN PSYSTEM_THREAD_INFORMATION ThreadToMatch,
  752. IN PSYSTEM_PROCESS_INFORMATION MatchedProcess
  753. )
  754. /*++
  755. Routine Description:
  756. This procedure finds thread which corresponds to the ThreadToMatch.
  757. It returns the address of the matching thread, or NULL if no
  758. matching thread was found.
  759. Arguments:
  760. ThreadToMatch - Supplies a pointer to the target thread to match.
  761. MatchedProcess - Supples a pointer to the process which contains
  762. the target thread. The thread information
  763. must follow this process, i.e., this block was
  764. obtain from a NtQuerySystemInformation specifying
  765. PROCESS_INFORMATION.
  766. Return Value:
  767. Address of the corresponding thread from MatchedProcess or NULL.
  768. --*/
  769. {
  770. PSYSTEM_THREAD_INFORMATION Thread;
  771. ULONG i;
  772. Thread = (PSYSTEM_THREAD_INFORMATION)(MatchedProcess + 1);
  773. for (i = 0; i < MatchedProcess->NumberOfThreads; i++) {
  774. if ((Thread->ClientId.UniqueThread ==
  775. ThreadToMatch->ClientId.UniqueThread) &&
  776. (Thread->CreateTime.QuadPart ==
  777. ThreadToMatch->CreateTime.QuadPart)) {
  778. return(Thread);
  779. }
  780. Thread += 1;
  781. }
  782. return(NULL);
  783. }