windows-nt/Source/XPSP1/NT/sdktools/perfmtr/pmon.c
2020-09-26 16:20:57 +08:00

940 lines
29 KiB
C

/*++
Copyright (c) 1993 Microsoft Corporation
Module Name:
pmon.c
Abstract:
This module contains the NT/Win32 Process Monitor
Author:
Lou Perazzoli (loup) 1-Jan-1993
Revision History:
--*/
#include "perfmtrp.h"
#include <search.h>
#include <malloc.h>
#include <limits.h>
#include <stdlib.h>
#define BUFFER_SIZE 64*1024
#define MAX_BUFFER_SIZE 10*1024*1024
ULONG CurrentBufferSize;
PUCHAR PreviousBuffer;
PUCHAR CurrentBuffer;
PUCHAR TempBuffer;
#define CPU_USAGE 0
#define QUOTAS 1
USHORT *NoNameFound = L"Unknown";
USHORT *IdleProcess = L"Idle Process";
UCHAR *StateTable[] = {
"Initialized",
"Ready",
"Running",
"Standby",
"Terminated",
"Wait:",
"Transition",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"Unknown"
};
BOOLEAN Interactive;
ULONG NumberOfInputRecords;
INPUT_RECORD InputRecord;
HANDLE InputHandle;
HANDLE OriginalOutputHandle;
HANDLE OutputHandle;
DWORD OriginalInputMode;
WORD NormalAttribute;
WORD HighlightAttribute;
ULONG NumberOfCols;
ULONG NumberOfRows;
ULONG NumberOfDetailLines;
ULONG FirstDetailLine;
CONSOLE_SCREEN_BUFFER_INFO OriginalConsoleInfo;
UCHAR *WaitTable[] = {
"Executive",
"FreePage",
"PageIn",
"PoolAllocation",
"DelayExecution",
"Suspended",
"UserRequest",
"Executive",
"FreePage",
"PageIn",
"PoolAllocation",
"DelayExecution",
"Suspended",
"UserRequest",
"EventPairHigh",
"EventPairLow",
"LpcReceive",
"LpcReply",
"Spare1",
"Spare2",
"Spare3",
"Spare4",
"Spare5",
"Spare6",
"Spare7",
"Spare8",
"Spare9",
"Unknown",
"Unknown",
"Unknown",
"Unknown"
};
UCHAR *Empty = " ";
PSYSTEM_PROCESS_INFORMATION
FindMatchedProcess (
IN PSYSTEM_PROCESS_INFORMATION ProcessToMatch,
IN PUCHAR SystemInfoBuffer,
IN PULONG Hint
);
PSYSTEM_THREAD_INFORMATION
FindMatchedThread (
IN PSYSTEM_THREAD_INFORMATION ThreadToMatch,
IN PSYSTEM_PROCESS_INFORMATION MatchedProcess
);
typedef struct _TOPCPU {
LARGE_INTEGER TotalTime;
PSYSTEM_PROCESS_INFORMATION ProcessInfo;
PSYSTEM_PROCESS_INFORMATION MatchedProcess;
ULONG Value;
LONG PageFaultDiff;
SIZE_T WorkingSetDiff;
} TOPCPU, *PTOPCPU;
// TOPCPU TopCpu[1000];
// Required for Terminal Services
PTOPCPU TopCpu;
ULONG TopCpuSize;
#define TOPCPU_BUFFER_SIZE (((300*sizeof(TOPCPU))/4096+1)*4096)
#define TOPCPU_MAX_BUFFER_SIZE (50*TOPCPU_BUFFER_SIZE)
BOOL
WriteConsoleLine(
HANDLE OutputHandle,
WORD LineNumber,
LPSTR Text,
BOOL Highlight
)
{
COORD WriteCoord;
DWORD NumberWritten;
DWORD TextLength;
WriteCoord.X = 0;
WriteCoord.Y = LineNumber;
if (!FillConsoleOutputCharacter( OutputHandle,
' ',
NumberOfCols,
WriteCoord,
&NumberWritten
)
) {
return FALSE;
}
if (Text == NULL || (TextLength = strlen( Text )) == 0) {
return TRUE;
}
else {
return WriteConsoleOutputCharacter( OutputHandle,
Text,
TextLength,
WriteCoord,
&NumberWritten
);
}
}
NTSTATUS
GetProcessInfo (
IN PUCHAR p
)
{
NTSTATUS Status;
retry01:
Status = NtQuerySystemInformation(
SystemProcessInformation,
p,
CurrentBufferSize,
NULL
);
if (Status == STATUS_INFO_LENGTH_MISMATCH) {
//
// Increase buffer size.
//
CurrentBufferSize += 8192;
TempBuffer = VirtualAlloc (CurrentBuffer,
CurrentBufferSize,
MEM_COMMIT,
PAGE_READWRITE);
if (TempBuffer == NULL) {
printf("Memory commit failed\n");
ExitProcess(0);
}
TempBuffer = VirtualAlloc (PreviousBuffer,
CurrentBufferSize,
MEM_COMMIT,
PAGE_READWRITE);
if (TempBuffer == NULL) {
printf("Memory commit failed\n");
ExitProcess(0);
}
goto retry01;
}
return Status;
}
int
__cdecl main( argc, argv )
int argc;
char *argv[];
{
NTSTATUS Status;
int i;
ULONG DelayTimeMsec;
ULONG DelayTimeTicks;
ULONG LastCount;
COORD cp;
BOOLEAN Active;
PSYSTEM_THREAD_INFORMATION Thread;
SYSTEM_PERFORMANCE_INFORMATION PerfInfo;
SYSTEM_FILECACHE_INFORMATION FileCache;
SYSTEM_FILECACHE_INFORMATION PrevFileCache;
CHAR OutputBuffer[ 512 ];
UCHAR LastKey;
LONG ScrollDelta;
WORD DisplayLine, LastDetailRow;
BOOLEAN DoQuit = FALSE;
ULONG SkipLine;
ULONG Hint;
ULONG Offset1;
SIZE_T SumCommit;
int num;
int lastnum;
PSYSTEM_PROCESS_INFORMATION CurProcessInfo;
PSYSTEM_PROCESS_INFORMATION MatchedProcess;
LARGE_INTEGER LARGE_ZERO={0,0};
LARGE_INTEGER Ktime;
LARGE_INTEGER Utime;
LARGE_INTEGER TotalTime;
TIME_FIELDS TimeOut;
PTOPCPU PTopCpu;
SYSTEM_BASIC_INFORMATION BasicInfo;
ULONG DisplayType = CPU_USAGE;
INPUT_RECORD InputRecord;
DWORD NumRead;
ULONG Cpu;
ULONG NoScreenChanges = FALSE;
if ( GetPriorityClass(GetCurrentProcess()) == NORMAL_PRIORITY_CLASS) {
SetPriorityClass(GetCurrentProcess(),HIGH_PRIORITY_CLASS);
}
InputHandle = GetStdHandle( STD_INPUT_HANDLE );
OriginalOutputHandle = GetStdHandle( STD_OUTPUT_HANDLE );
Interactive = TRUE;
if (Interactive) {
if (InputHandle == NULL ||
OriginalOutputHandle == NULL ||
!GetConsoleMode( InputHandle, &OriginalInputMode )
) {
Interactive = FALSE;
} else {
OutputHandle = CreateConsoleScreenBuffer( GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_WRITE | FILE_SHARE_READ,
NULL,
CONSOLE_TEXTMODE_BUFFER,
NULL
);
if (OutputHandle == NULL ||
!GetConsoleScreenBufferInfo( OriginalOutputHandle, &OriginalConsoleInfo ) ||
!SetConsoleScreenBufferSize( OutputHandle, OriginalConsoleInfo.dwSize ) ||
!SetConsoleActiveScreenBuffer( OutputHandle ) ||
!SetConsoleMode( InputHandle, 0 )
) {
if (OutputHandle != NULL) {
CloseHandle( OutputHandle );
OutputHandle = NULL;
}
Interactive = FALSE;
} else {
NormalAttribute = 0x1F;
HighlightAttribute = 0x71;
NumberOfCols = OriginalConsoleInfo.dwSize.X;
NumberOfRows = OriginalConsoleInfo.dwSize.Y;
NumberOfDetailLines = NumberOfRows - 7;
}
}
}
Status = NtQuerySystemInformation(
SystemBasicInformation,
&BasicInfo,
sizeof(BasicInfo),
NULL
);
Status = NtQuerySystemInformation(
SystemPerformanceInformation,
&PerfInfo,
sizeof(PerfInfo),
NULL
);
DelayTimeMsec = 10;
DelayTimeTicks = DelayTimeMsec * 10000;
PreviousBuffer = VirtualAlloc (NULL,
MAX_BUFFER_SIZE,
MEM_RESERVE,
PAGE_READWRITE);
if (PreviousBuffer == NULL) {
printf("Memory allocation failed\n");
return 0;
}
TempBuffer = VirtualAlloc (PreviousBuffer,
BUFFER_SIZE,
MEM_COMMIT,
PAGE_READWRITE);
if (TempBuffer == NULL) {
printf("Memory commit failed\n");
return 0;
}
CurrentBuffer = VirtualAlloc (NULL,
MAX_BUFFER_SIZE,
MEM_RESERVE,
PAGE_READWRITE);
if (CurrentBuffer == NULL) {
printf("Memory allocation failed\n");
return 0;
}
TempBuffer = VirtualAlloc (CurrentBuffer,
BUFFER_SIZE,
MEM_COMMIT,
PAGE_READWRITE);
if (TempBuffer == NULL) {
printf("Memory commit failed\n");
return 0;
}
// TS
TopCpu = VirtualAlloc (NULL,
TOPCPU_MAX_BUFFER_SIZE,
MEM_RESERVE,
PAGE_READWRITE);
if(TopCpu == NULL)
{
printf("Memory allocation failed\n");
return 0;
}
TempBuffer = VirtualAlloc( TopCpu,
TOPCPU_BUFFER_SIZE,
MEM_COMMIT,
PAGE_READWRITE);
if( TempBuffer == NULL )
{
printf("Memory commit failed\n");
return 0;
}
num = 0;
TopCpuSize = TOPCPU_BUFFER_SIZE;
CurrentBufferSize = BUFFER_SIZE;
TempBuffer = NULL;
Status = GetProcessInfo (PreviousBuffer);
if( !NT_SUCCESS( Status ) )
{
printf("Get process information failed %lx\n", Status);
return (0);
}
DelayTimeMsec = 5000;
DelayTimeTicks = DelayTimeMsec * 10000;
Status = GetProcessInfo (CurrentBuffer);
if( !NT_SUCCESS( Status ) )
{
printf("Get process information failed %lx\n", Status);
return (0);
}
Status = NtQuerySystemInformation(
SystemPerformanceInformation,
&PerfInfo,
sizeof(PerfInfo),
NULL
);
LastCount = PerfInfo.PageFaultCount;
if ( !NT_SUCCESS(Status) ) {
printf("Query perf Failed %lx\n",Status);
return 0;
}
Status = NtQuerySystemInformation(
SystemFileCacheInformation,
&FileCache,
sizeof(FileCache),
NULL
);
PrevFileCache = FileCache;
if ( !NT_SUCCESS(Status) ) {
printf("Query file cache Failed %lx\n",Status);
return 0;
}
Active = TRUE;
while(TRUE) {
Status = GetProcessInfo (CurrentBuffer);
if( !NT_SUCCESS( Status ) )
{
printf("Get process information failed %lx\n", Status);
return (0);
}
Status = NtQuerySystemInformation(
SystemPerformanceInformation,
&PerfInfo,
sizeof(PerfInfo),
NULL
);
if ( !NT_SUCCESS(Status) ) {
printf("Query perf Failed %lx\n",Status);
return 0;
}
Status = NtQuerySystemInformation(
SystemFileCacheInformation,
&FileCache,
sizeof(FileCache),
NULL
);
if ( !NT_SUCCESS(Status) ) {
printf("Query file cache Failed %lx\n",Status);
return 0;
}
//
// Calculate top CPU users and display information.
//
//
// Cross check previous process/thread info against current
// process/thread info.
//
Offset1 = 0;
lastnum = num;
num = 0;
Hint = 0;
TotalTime = LARGE_ZERO;
SumCommit = 0;
while (TRUE) {
CurProcessInfo = (PSYSTEM_PROCESS_INFORMATION)&CurrentBuffer[Offset1];
//
// Find the corresponding process in the previous array.
//
MatchedProcess = FindMatchedProcess (CurProcessInfo,
PreviousBuffer,
&Hint);
if( num >= (int)( TopCpuSize / sizeof( TOPCPU ) ) )
{
TopCpuSize += 4096;
if( VirtualAlloc( TopCpu, TopCpuSize, MEM_COMMIT, PAGE_READWRITE ) == NULL )
{
printf("Memory commit failed\n");
return 0;
}
}
if (MatchedProcess == NULL) {
TopCpu[num].TotalTime = CurProcessInfo->KernelTime;
TopCpu[num].TotalTime.QuadPart =
TopCpu[num].TotalTime.QuadPart +
CurProcessInfo->UserTime.QuadPart;
TotalTime.QuadPart = TotalTime.QuadPart +
TopCpu[num].TotalTime.QuadPart;
TopCpu[num].ProcessInfo = CurProcessInfo;
TopCpu[num].MatchedProcess = NULL;
num += 1;
} else {
Ktime.QuadPart = CurProcessInfo->KernelTime.QuadPart -
MatchedProcess->KernelTime.QuadPart;
Utime.QuadPart = CurProcessInfo->UserTime.QuadPart -
MatchedProcess->UserTime.QuadPart;
TopCpu[num].TotalTime.QuadPart =
Ktime.QuadPart +
Utime.QuadPart;
TotalTime.QuadPart = TotalTime.QuadPart +
TopCpu[num].TotalTime.QuadPart;
TopCpu[num].ProcessInfo = CurProcessInfo;
TopCpu[num].MatchedProcess = MatchedProcess;
TopCpu[num].PageFaultDiff =
CurProcessInfo->PageFaultCount - MatchedProcess->PageFaultCount;
;
TopCpu[num].WorkingSetDiff =
CurProcessInfo->WorkingSetSize - MatchedProcess->WorkingSetSize;
num += 1;
}
SumCommit += CurProcessInfo->PrivatePageCount / 1024;
if (CurProcessInfo->NextEntryOffset == 0) {
DisplayLine = 0;
sprintf (OutputBuffer,
" Memory:%8ldK Avail:%7ldK PageFlts:%6ld InRam Kernel:%5ldK P:%5ldK",
BasicInfo.NumberOfPhysicalPages*(BasicInfo.PageSize/1024),
PerfInfo.AvailablePages*(BasicInfo.PageSize/1024),
PerfInfo.PageFaultCount - LastCount,
(PerfInfo.ResidentSystemCodePage + PerfInfo.ResidentSystemDriverPage)*(BasicInfo.PageSize/1024),
(PerfInfo.ResidentPagedPoolPage)*(BasicInfo.PageSize/1024)
);
LastCount = PerfInfo.PageFaultCount;
WriteConsoleLine( OutputHandle,
DisplayLine++,
OutputBuffer,
FALSE
);
sprintf(OutputBuffer,
" Commit:%7ldK/%7ldK Limit:%7ldK Peak:%7ldK Pool N:%5ldK P:%5ldK",
PerfInfo.CommittedPages*(BasicInfo.PageSize/1024),
SumCommit,
PerfInfo.CommitLimit*(BasicInfo.PageSize/1024),
PerfInfo.PeakCommitment*(BasicInfo.PageSize/1024),
PerfInfo.NonPagedPoolPages*(BasicInfo.PageSize/1024),
PerfInfo.PagedPoolPages*(BasicInfo.PageSize/1024)
);
WriteConsoleLine( OutputHandle,
DisplayLine++,
OutputBuffer,
FALSE
);
DisplayLine += 1;
if (NoScreenChanges) {
DisplayLine += 2;
} else {
WriteConsoleLine( OutputHandle,
DisplayLine++,
" Mem Mem Page Flts Commit Usage Pri Hnd Thd Image ",
FALSE
);
WriteConsoleLine( OutputHandle,
DisplayLine++,
"CPU CpuTime Usage Diff Faults Diff Charge NonP Page Cnt Cnt Name ",
FALSE
);
}
DisplayLine += 1;
sprintf(OutputBuffer,
" %6ld%5ld%9ld %4ld File Cache ",
FileCache.CurrentSize/1024,
((LONG)FileCache.CurrentSize - (LONG)PrevFileCache.CurrentSize)/1024,
FileCache.PageFaultCount,
(LONG)FileCache.PageFaultCount - (LONG)PrevFileCache.PageFaultCount
);
WriteConsoleLine( OutputHandle,
DisplayLine++,
OutputBuffer,
FALSE
);
PrevFileCache = FileCache;
LastDetailRow = (WORD)NumberOfRows;
for (i = FirstDetailLine; i < num; i++) {
if (DisplayLine >= LastDetailRow) {
break;
}
PTopCpu = &TopCpu[i];
Ktime.QuadPart =
PTopCpu->ProcessInfo->KernelTime.QuadPart +
PTopCpu->ProcessInfo->UserTime.QuadPart;
RtlTimeToElapsedTimeFields ( &Ktime, &TimeOut);
TimeOut.Hour += TimeOut.Day*24;
if (PTopCpu->ProcessInfo->ImageName.Buffer == NULL) {
if (PTopCpu->ProcessInfo->UniqueProcessId == (HANDLE)0) {
PTopCpu->ProcessInfo->ImageName.Buffer = (PWSTR)IdleProcess;
} else {
PTopCpu->ProcessInfo->ImageName.Buffer = (PWSTR)NoNameFound;
}
} else {
if (PTopCpu->ProcessInfo->ImageName.Length > 24) {
PTopCpu->ProcessInfo->ImageName.Buffer +=
((PTopCpu->ProcessInfo->ImageName.Length) - 24);
}
}
Cpu = PTopCpu->TotalTime.LowPart / ((TotalTime.LowPart / 100) ? (TotalTime.LowPart / 100) : 1);
if ( Cpu == 100 ) {
Cpu = 99;
}
//
// See if nothing has changed.
//
SkipLine = FALSE;
if ((PTopCpu->MatchedProcess != NULL) &&
(Cpu == 0) &&
(PTopCpu->WorkingSetDiff == 0) &&
(PTopCpu->PageFaultDiff == 0) &&
(PTopCpu->MatchedProcess->NumberOfThreads ==
PTopCpu->ProcessInfo->NumberOfThreads) &&
(PTopCpu->MatchedProcess->HandleCount ==
PTopCpu->ProcessInfo->HandleCount) &&
(PTopCpu->MatchedProcess->PrivatePageCount ==
PTopCpu->ProcessInfo->PrivatePageCount)) {
PTopCpu->ProcessInfo->PeakPagefileUsage = 0xffffffff;
PTopCpu->ProcessInfo->PeakWorkingSetSize = DisplayLine;
if ((PTopCpu->MatchedProcess->PeakPagefileUsage == 0xffffffff) &&
(PTopCpu->MatchedProcess->PeakWorkingSetSize == DisplayLine) &&
(NoScreenChanges)) {
SkipLine = TRUE;
}
}
if (SkipLine) {
//
// The line on the screen has not changed, just skip
// writing this one.
//
DisplayLine += 1;
} else {
sprintf(OutputBuffer,
"%2ld%4ld:%02ld:%02ld%7ld%5ld%9ld%5ld%7ld%5ld%5ld %2ld%5ld%3ld %ws",
Cpu,
TimeOut.Hour,
TimeOut.Minute,
TimeOut.Second,
PTopCpu->ProcessInfo->WorkingSetSize / 1024,
(ULONG)(PTopCpu->WorkingSetDiff / 1024),
PTopCpu->ProcessInfo->PageFaultCount,
PTopCpu->PageFaultDiff,
PTopCpu->ProcessInfo->PrivatePageCount / 1024,
PTopCpu->ProcessInfo->QuotaNonPagedPoolUsage / 1024,
PTopCpu->ProcessInfo->QuotaPagedPoolUsage / 1024,
PTopCpu->ProcessInfo->BasePriority,
PTopCpu->ProcessInfo->HandleCount,
PTopCpu->ProcessInfo->NumberOfThreads,
PTopCpu->ProcessInfo->ImageName.Buffer
);
WriteConsoleLine( OutputHandle,
DisplayLine++,
OutputBuffer,
FALSE
);
}
Thread = (PSYSTEM_THREAD_INFORMATION)(TopCpu[i].ProcessInfo + 1);
}
while (lastnum > num) {
WriteConsoleLine( OutputHandle,
DisplayLine++,
" ",
FALSE);
lastnum -= 1;
}
}
if (CurProcessInfo->NextEntryOffset == 0) {
break;
}
Offset1 += CurProcessInfo->NextEntryOffset;
} //end while
TempBuffer = PreviousBuffer;
PreviousBuffer = CurrentBuffer;
CurrentBuffer = TempBuffer;
NoScreenChanges = TRUE;
while (WaitForSingleObject( InputHandle, DelayTimeMsec ) == STATUS_WAIT_0) {
//
// Check for input record
//
if (ReadConsoleInput( InputHandle, &InputRecord, 1, &NumberOfInputRecords ) &&
InputRecord.EventType == KEY_EVENT &&
InputRecord.Event.KeyEvent.bKeyDown
) {
LastKey = InputRecord.Event.KeyEvent.uChar.AsciiChar;
if (LastKey < ' ') {
ScrollDelta = 0;
if (LastKey == 'C'-'A'+1) {
DoQuit = TRUE;
} else switch (InputRecord.Event.KeyEvent.wVirtualKeyCode) {
case VK_ESCAPE:
DoQuit = TRUE;
break;
case VK_PRIOR:
ScrollDelta = -(LONG)(InputRecord.Event.KeyEvent.wRepeatCount * NumberOfDetailLines);
break;
case VK_NEXT:
ScrollDelta = InputRecord.Event.KeyEvent.wRepeatCount * NumberOfDetailLines;
break;
case VK_UP:
ScrollDelta = -InputRecord.Event.KeyEvent.wRepeatCount;
break;
case VK_DOWN:
ScrollDelta = InputRecord.Event.KeyEvent.wRepeatCount;
break;
case VK_HOME:
FirstDetailLine = 0;
break;
case VK_END:
if ((ULONG)num > NumberOfDetailLines) {
FirstDetailLine = num - NumberOfDetailLines;
NoScreenChanges = FALSE;
}
break;
}
if (ScrollDelta != 0) {
if (ScrollDelta < 0) {
if (FirstDetailLine <= (ULONG)-ScrollDelta) {
FirstDetailLine = 0;
NoScreenChanges = FALSE;
} else {
FirstDetailLine += ScrollDelta;
NoScreenChanges = FALSE;
}
} else {
FirstDetailLine += ScrollDelta;
NoScreenChanges = FALSE;
if (FirstDetailLine >= (num - NumberOfDetailLines)) {
FirstDetailLine = num - NumberOfDetailLines;
}
}
}
} else {
switch (toupper( LastKey )) {
case 'C':
case 'c':
DisplayType = CPU_USAGE;
break;
case 'P':
case 'p':
DisplayType = QUOTAS;
break;
case 'q':
case 'Q':
DoQuit = TRUE;
break;
default:
break;
}
}
break;
}
}
if (DoQuit) {
if (Interactive) {
SetConsoleActiveScreenBuffer( OriginalOutputHandle );
SetConsoleMode( InputHandle, OriginalInputMode );
CloseHandle( OutputHandle );
}
return 0;
}
}
return 0;
}
PSYSTEM_PROCESS_INFORMATION
FindMatchedProcess (
IN PSYSTEM_PROCESS_INFORMATION ProcessToMatch,
IN PUCHAR SystemInfoBuffer,
IN OUT PULONG Hint
)
/*++
Routine Description:
This procedure finds the process which corresponds to the ProcessToMatch.
It returns the address of the matching Process, or NULL if no
matching process was found.
Arguments:
ProcessToMatch - Supplies a pointer to the target thread to match.
SystemInfoBuffer - Supples a pointer to the system information
buffer in which to locate the process.
Hint - Supplies and returns a hint for optimizing the searches.
Return Value:
Address of the corresponding Process or NULL.
--*/
{
PSYSTEM_PROCESS_INFORMATION Process;
ULONG Offset2;
Offset2 = *Hint;
while (TRUE) {
Process = (PSYSTEM_PROCESS_INFORMATION)&SystemInfoBuffer[Offset2];
if ((Process->UniqueProcessId ==
ProcessToMatch->UniqueProcessId) &&
(Process->CreateTime.QuadPart ==
ProcessToMatch->CreateTime.QuadPart)) {
*Hint = Offset2 + Process->NextEntryOffset;
return(Process);
}
Offset2 += Process->NextEntryOffset;
if (Offset2 == *Hint) {
*Hint = 0;
return(NULL);
}
if (Process->NextEntryOffset == 0) {
if (*Hint == 0) {
return(NULL);
}
Offset2 = 0;
}
}
}
PSYSTEM_THREAD_INFORMATION
FindMatchedThread (
IN PSYSTEM_THREAD_INFORMATION ThreadToMatch,
IN PSYSTEM_PROCESS_INFORMATION MatchedProcess
)
/*++
Routine Description:
This procedure finds thread which corresponds to the ThreadToMatch.
It returns the address of the matching thread, or NULL if no
matching thread was found.
Arguments:
ThreadToMatch - Supplies a pointer to the target thread to match.
MatchedProcess - Supples a pointer to the process which contains
the target thread. The thread information
must follow this process, i.e., this block was
obtain from a NtQuerySystemInformation specifying
PROCESS_INFORMATION.
Return Value:
Address of the corresponding thread from MatchedProcess or NULL.
--*/
{
PSYSTEM_THREAD_INFORMATION Thread;
ULONG i;
Thread = (PSYSTEM_THREAD_INFORMATION)(MatchedProcess + 1);
for (i = 0; i < MatchedProcess->NumberOfThreads; i++) {
if ((Thread->ClientId.UniqueThread ==
ThreadToMatch->ClientId.UniqueThread) &&
(Thread->CreateTime.QuadPart ==
ThreadToMatch->CreateTime.QuadPart)) {
return(Thread);
}
Thread += 1;
}
return(NULL);
}