July 26, 2011, 5:33 a.m.
posted by odin
This section describes the key Windows 2000 process data structures. Also listed are key kernel variables, performance counters, and functions and tools that relate to processes.
Each Windows 2000 process is represented by an executive process (EPROCESS) block. Besides containing many attributes relating to a process, an EPROCESS block contains and points to a number of other related data structures. For example, each process has one or more threads represented by executive thread (ETHREAD) blocks. (Thread data structures are explained in the section "Thread Internals" later in this chapter.) The EPROCESS block and its related data structures exist in system space, with the exception of the process environment block (PEB), which exists in the process address space (because it contains information that is modified by user-mode code).
In addition to the EPROCESS block, the Win32 subsystem process (Csrss) maintains a parallel structure for each Windows 2000 process that executes a Win32 program. Also, the kernel-mode part of the Win32 subsystem (Win32k.sys) has a per-process data structure that is created the first time a thread calls a Win32 USER or GDI function that is implemented in kernel mode.
Figure is a simplified diagram of the process and thread data structures. Each data structure shown in the figure is described in detail in this chapter.
Figure Data structures associated with processes and threads
First let's focus on the process block. (We'll get to the thread block in the section "Thread Internals" later in the chapter.) Figure shows the key fields in an EPROCESS block.
Figure Structure of an executive process block
Displaying the Format of an EPROCESS Block
For a list of most of the fields that make up an EPROCESS block and their offsets in hexadecimal, type !processfields in the kernel debugger. (See Chapter 1 for more information on the kernel debugger.) The output looks like this:
kd> !processfields EPROCESS structure offsets: Pcb: 0x0 ExitStatus: 0x6c LockEvent: 0x70 LockCount: 0x80 CreateTime: 0x88 ExitTime: 0x90 LockOwner: 0x98 UniqueProcessId: 0x9c ActiveProcessLinks: 0xa0 QuotaPeakPoolUsage: 0xa8 QuotaPoolUsage: 0xb0 PagefileUsage: 0xb8 CommitCharge: 0xbc PeakPagefileUsage: 0xc0 PeakVirtualSize: 0xc4 VirtualSize: 0xc8 Vm: 0xd0 DebugPort: 0x120 ExceptionPort: 0x124 ObjectTable: 0x128 Token: 0x12c WorkingSetLock: 0x130 WorkingSetPage: 0x150 ProcessOutswapEnabled: 0x154 ProcessOutswapped: 0x155 AddressSpaceInitialized: 0x156 AddressSpaceDeleted: 0x157 AddressCreationLock: 0x158 ForkInProgress: 0x17c VmOperation: 0x180 VmOperationEvent: 0x184 PageDirectoryPte: 0x1f0 LastFaultCount: 0x18c VadRoot: 0x194 VadHint: 0x198 CloneRoot: 0x19c NumberOfPrivatePages: 0x1a0 NumberOfLockedPages: 0x1a4 ForkWasSuccessful: 0x182 ExitProcessCalled: 0x1aa CreateProcessReported: 0x1ab SectionHandle: 0x1ac Peb: 0x1b0 SectionBaseAddress: 0x1b4 QuotaBlock: 0x1b8 LastThreadExitStatus: 0x1bc WorkingSetWatch: 0x1c0 InheritedFromUniqueProcessId: 0x1c8 GrantedAccess: 0x1cc DefaultHardErrorProcessing 0x1d0 LdtInformation: 0x1d4 VadFreeHint: 0x1d8 VdmObjects: 0x1dc DeviceMap: 0x1e0 ImageFileName: 0x1fc VmTrimFaultValue: 0x20c Win32Process: 0x214 Win32WindowStation: 0x1c4
The !processfields command shows the format of a process block, not its contents. (The !process command actually dumps the contents of a process block. An annotated example of the output from this command is included later in this section.) Although some of the field names are self-explanatory, the output doesn't give the data type of the fields, nor does it show the format of the structures that are included within or pointed to by the EPROCESS block, such as the kernel process block (Pcb), quota block (QuotaBlock), and so on. By examining the offsets, however, you can at least tell the length of a field. (Hint: Fields that are 4 bytes long and refer to some other structure are likely pointers.)
You can also use the !strct command (in the secondary kernel debugger extension library Kdex2x86.dll) to display the format of a process block. This command displays every field and its data type (whereas the !processfields command displays only some of the fields and doesn't display data type information). A portion of the output follows:
kd> !kdex2x86.strct eprocess Loaded kdex2x86 extension DLL struct _EPROCESS (sizeof=648) +000 struct _KPROCESS Pcb +000 struct _DISPATCHER_HEADER Header +000 byte Type +001 byte Absolute +002 byte Size +003 byte Inserted +004 int32 SignalState +008 struct _LIST_ENTRY WaitListHead +008 struct _LIST_ENTRY *Flink +00c struct _LIST_ENTRY *Blink +010 struct _LIST_ENTRY ProfileListHead +010 struct _LIST_ENTRY *Flink +014 struct _LIST_ENTRY *Blink +018 uint32 DirectoryTableBase +020 struct _KGDTENTRY LdtDescriptor +020 uint16 LimitLow +022 uint16 BaseLow +024 union __unnamed9 HighWord +024 struct __unnamed10 Bytes +024 byte BaseMid +025 byte Flags1 +026 byte Flags2 +027 byte BaseHi +024 struct __unnamed11 Bits +024 bits0-7 BaseMid +024 bits8-12 Type +024 bits13-14 Dpl +024 bits15-15 Pres +024 bits16-19 LimitHi +024 bits20-20 Sys +024 bits21-21 Reserved_0 +024 bits22-22 Default_Big +024 bits23-23 Granularity +024 bits24-31 BaseHi +028 struct _KIDTENTRY Int21Descriptor +028 uint16 Offset +02a uint16 Selector +02c uint16 Access +02e uint16 ExtendedOffset +030 uint16 IopmOffset +032 byte Iopl +033 byte VdmFlag +034 uint32 ActiveProcessors +038 uint32 KernelTime +03c uint32 UserTime +040 struct _LIST_ENTRY ReadyListHead +040 struct _LIST_ENTRY *Flink +044 struct _LIST_ENTRY *Blink +048 struct _LIST_ENTRY SwapListEntry +048 struct _LIST_ENTRY *Flink +04c struct _LIST_ENTRY *Blink +050 struct _LIST_ENTRY ThreadListHead +050 struct _LIST_ENTRY *Flink +054 struct _LIST_ENTRY *Blink +058 uint32 ProcessLock +05c uint32 Affinity +060 uint16 StackCount +062 char BasePriority +063 char ThreadQuantum +064 byte AutoAlignment +065 byte State +066 byte ThreadSeed +067 byte DisableBoost +068 byte PowerState +069 byte DisableQuantum +06a byte Spare +06c int32 ExitStatus +070 struct _KEVENT LockEvent +070 struct _DISPATCHER_HEADER Header +070 byte Type +071 byte Absolute +072 byte Size +073 byte Inserted +074 int32 SignalState +078 struct _LIST_ENTRY WaitListHead +078 struct _LIST_ENTRY *Flink +07c struct _LIST_ENTRY *Blink +080 uint32 LockCount +088 union _LARGE_INTEGER CreateTime +088 uint32 LowPart +08c int32 HighPart +088 struct __unnamed3 u +088 uint32 LowPart +08c int32 HighPart +088 int64 QuadPart +090 union _LARGE_INTEGER ExitTime +090 uint32 LowPart +094 int32 HighPart +090 struct __unnamed3 u +090 uint32 LowPart +094 int32 HighPart +090 int64 QuadPart +098 struct _KTHREAD *LockOwner +09c void *UniqueProcessId +0a0 struct _LIST_ENTRY ActiveProcessLinks +0a0 struct _LIST_ENTRY *Flink +0a4 struct _LIST_ENTRY *Blink +0a8 uint32 QuotaPeakPoolUsage +0b0 uint32 QuotaPoolUsage +0b8 uint32 PagefileUsage +0bc uint32 CommitCharge +0c0 uint32 PeakPagefileUsage +0c4 uint32 PeakVirtualSize +0c8 uint32 VirtualSize +0d0 struct _MMSUPPORT Vm +0d0 union _LARGE_INTEGER LastTrimTime +0d0 uint32 LowPart +0d4 int32 HighPart +0d0 struct __unnamed3 u +0d0 uint32 LowPart +0d4 int32 HighPart +0d0 int64 QuadPart +0d8 uint32 LastTrimFaultCount +0dc uint32 PageFaultCount +0e0 uint32 PeakWorkingSetSize +0e4 uint32 WorkingSetSize +0e8 uint32 MinimumWorkingSetSize +0ec uint32 MaximumWorkingSetSize +0f0 *VmWorkingSetList +0f4 struct _LIST_ENTRY WorkingSetExpansionLinks +0f4 struct _LIST_ENTRY *Flink +0f8 struct _LIST_ENTRY *Blink +0fc byte AllowWorkingSetAdjustment +0fd byte AddressSpaceBeingDeleted +0fe byte ForegroundSwitchCount +0ff byte MemoryPriority +100 union __unnamed13 u +100 uint32 LongFlags +100 struct _MMSUPPORT_FLAGS Flags +100 bits0-0 SessionSpace +100 bits1-1 BeingTrimmed +100 bits2-2 ProcessInSession +100 bits3-3 SessionLeader +100 bits4-4 TrimHard +100 bits5-5 WorkingSetHard +100 bits6-6 WriteWatch +100 bits7-31 Filler +104 uint32 Claim +108 uint32 NextEstimationSlot +10c uint32 NextAgingSlot +110 uint32 EstimatedAvailable +114 uint32 GrowthSinceLastEstimate +118 struct _LIST_ENTRY SessionProcessLinks +118 struct _LIST_ENTRY *Flink +11c struct _LIST_ENTRY *Blink +120 void *DebugPort +124 void *ExceptionPort +128 struct _HANDLE_TABLE *ObjectTable +12c void *Token +130 struct _FAST_MUTEX WorkingSetLock +130 int32 Count +134 struct _KTHREAD *Owner +138 uint32 Contention +13c struct _KEVENT Event +13c struct _DISPATCHER_HEADER Header +13c byte Type +13d byte Absolute +13e byte Size +13f byte Inserted +140 int32 SignalState +144 struct _LIST_ENTRY WaitListHead +144 struct _LIST_ENTRY *Flink +148 struct _LIST_ENTRY *Blink +14c uint32 OldIrql +150 uint32 WorkingSetPage +154 byte ProcessOutswapEnabled +155 byte ProcessOutswapped +156 byte AddressSpaceInitialized +157 byte AddressSpaceDeleted +158 struct _FAST_MUTEX AddressCreationLock +158 int32 Count +15c struct _KTHREAD *Owner +160 uint32 Contention +164 struct _KEVENT Event +164 struct _DISPATCHER_HEADER Header +164 byte Type +165 byte Absolute +166 byte Size +167 byte Inserted +168 int32 SignalState +16c struct _LIST_ENTRY WaitListHead +16c struct _LIST_ENTRY *Flink +170 struct _LIST_ENTRY *Blink +174 uint32 OldIrql +178 uint32 HyperSpaceLock +17c struct _ETHREAD *ForkInProgress +180 uint16 VmOperation +182 byte ForkWasSuccessful +183 byte MmAgressiveWsTrimMask +184 struct _KEVENT *VmOperationEvent +188 void *PaeTop +18c uint32 LastFaultCount +190 uint32 ModifiedPageCount +194 void *VadRoot +198 void *VadHint +19c void *CloneRoot +1a0 uint32 NumberOfPrivatePages +1a4 uint32 NumberOfLockedPages +1a8 uint16 NextPageColor +1aa byte ExitProcessCalled +1ab byte CreateProcessReported +1ac void *SectionHandle +1b0 struct _PEB *Peb +1b4 void *SectionBaseAddress +1b8 struct _EPROCESS_QUOTA_BLOCK *QuotaBlock +1bc int32 LastThreadExitStatus +1c0 struct _PAGEFAULT_HISTORY *WorkingSetWatch +1c4 void *Win32WindowStation +1c8 void *InheritedFromUniqueProcessId +1cc uint32 GrantedAccess +1d0 uint32 DefaultHardErrorProcessing +1d4 void *LdtInformation +1d8 void *VadFreeHint +1dc void *VdmObjects +1e0 void *DeviceMap +1e4 uint32 SessionId +1e8 struct _LIST_ENTRY PhysicalVadList +1e8 struct _LIST_ENTRY *Flink +1ec struct _LIST_ENTRY *Blink +1f0 struct _HARDWARE_PTE_X86 PageDirectoryPte +1f0 bits0-0 Valid +1f0 bits1-1 Write +1f0 bits2-2 Owner +1f0 bits3-3 WriteThrough +1f0 bits4-4 CacheDisable +1f0 bits5-5 Accessed +1f0 bits6-6 Dirty +1f0 bits7-7 LargePage +1f0 bits8-8 Global +1f0 bits9-9 CopyOnWrite +1f0 bits10-10 Prototype +1f0 bits11-11 reserved +1f0 bits12-31 PageFrameNumber +1f0 uint64 Filler +1f8 uint32 PaePageDirectoryPage +1fc byte ImageFileName +20c uint32 VmTrimFaultValue +210 byte SetTimerResolution +211 byte PriorityClass +212 byte SubSystemMinorVersion +213 byte SubSystemMajorVersion +212 uint16 SubSystemVersion +214 void *Win32Process +218 struct _EJOB *Job +21c uint32 JobStatus +220 struct _LIST_ENTRY JobLinks +220 struct _LIST_ENTRY *Flink +224 struct _LIST_ENTRY *Blink +228 void *LockedPagesList +22c void *SecurityPort +230 struct _WOW64_PROCESS *Wow64Process +238 union _LARGE_INTEGER ReadOperationCount +238 uint32 LowPart +23c int32 HighPart +238 struct __unnamed3 u +238 uint32 LowPart +23c int32 HighPart +238 int64 QuadPart +240 union _LARGE_INTEGER WriteOperationCount +240 uint32 LowPart +244 int32 HighPart +240 struct __unnamed3 u +240 uint32 LowPart +244 int32 HighPart +240 int64 QuadPart +248 union _LARGE_INTEGER OtherOperationCount +248 uint32 LowPart +24c int32 HighPart +248 struct __unnamed3 u +248 uint32 LowPart +24c int32 HighPart +248 int64 QuadPart +250 union _LARGE_INTEGER ReadTransferCount +250 uint32 LowPart +254 int32 HighPart +250 struct __unnamed3 u +250 uint32 LowPart +254 int32 HighPart +250 int64 QuadPart +258 union _LARGE_INTEGER WriteTransferCount +258 uint32 LowPart +25c int32 HighPart +258 struct __unnamed3 u +258 uint32 LowPart +25c int32 HighPart +258 int64 QuadPart +260 union _LARGE_INTEGER OtherTransferCount +260 uint32 LowPart +264 int32 HighPart +260 struct __unnamed3 u +260 uint32 LowPart +264 int32 HighPart +260 int64 QuadPart +268 uint32 CommitChargeLimit +26c uint32 CommitChargePeak +270 struct _LIST_ENTRY ThreadListHead +270 struct _LIST_ENTRY *Flink +274 struct _LIST_ENTRY *Blink +278 struct _RTL_BITMAP *VadPhysicalPagesBitMap +27c uint32 VadPhysicalPages +280 uint32 AweLock
Figure explains some of the fields in the preceding experiment in more detail and includes references to other places in the book where you can find more information about them. As we've said before and will no doubt say again, processes and threads are such an integral part of Windows 2000 that it's impossible to talk about them without referring to many other parts of the system. To keep the length of this chapter manageable, however, we've covered those related subjects (such as memory management, security, objects, and handles) elsewhere.
Figure Contents of the EPROCESS Block
|Kernel process (KPROCESS) block||Common dispatcher object header, pointer to the process page directory, list of kernel thread (KTHREAD) blocks belonging to the process, default base priority, quantum, affinity mask, and total kernel and user time for the threads in the process.||Thread scheduling|
|Process identification||Unique process ID, creating process ID, name of image being run, window station process is running on.|
|Quota block||Limits on nonpaged pool, paged pool, and page file usage plus current and peak process nonpaged and paged pool usage. (Note: Several processes can share this structure: all the system processes point to the single systemwide default quota block; all the processes in the interactive session share a single quota block Winlogon sets up.|
|Virtual address descriptors (VADs)||Series of data structures that describes the status of the portions of the address space that exist in the process.||Memory management (Chapter 7)|
|Working set information||Pointer to working set list (MMWSL structure); current, peak, minimum, and maximum working set size; last trim time; page fault count; memory priority; outswap flags; page fault history.||Memory management (Chapter 7)|
|Virtual memory information||Current and peak virtual size, page file usage, hardware page table entry for process page directory.||Memory management (Chapter 7)|
|Exception local procedure call (LPC) port||Interprocess communication channel to which the process manager sends a message when one of the process's threads causes an exception.||Local procedure calls (Chapter 3)|
|Debugging LPC port||Interprocess communication channel to which the process manager sends a message when one of the process's threads causes a debug event.||Local procedure calls (Chapter 3)|
|Access token (ACCESS_TOKEN)||Executive object describing the security profile of this process.||Security (Chapter 8)|
|Handle table||Address of per-process handle table.||Object handles (Chapter 3)|
|Device map||Address of object directory to resolve device name references in (supports multiple users).||Object manager (Chapter 3)|
|Process environment block (PEB)||Image information (base address, version numbers, module list), process heap information, and thread-local storage utilization. (Note: The pointers to the process heaps start at the first byte after the PEB.)|
|Win32 subsystem process block (W32PROCESS)||Process details needed by the kernel-mode component of the Win32 subsystem.|
The kernel process (KPROCESS) block, which is part of the EPROCESS block, and the process environment block (PEB), which is pointed to by the EPROCESS block, contain additional details about the process object. The KPROCESS block (which is sometimes called the PCB, or process control block) is illustrated in Figure. It contains the basic information that the Windows 2000 kernel needs to schedule threads. (Page directories are covered in Chapter 7, and kernel thread blocks are described in more detail later in this chapter.)
Figure Structure of the kernel process block
The PEB, which lives in the user process address space, contains information needed by the image loader, the heap manager, and other Win32 system DLLs that need to be writable from user mode. (The EPROCESS and KPROCESS blocks are accessible only from kernel mode.) The PEB is always mapped at address 0x7FFDF000. The basic structure of the PEB is illustrated in Figure and is explained in more detail later in this chapter.
Figure Fields of the process environment block
Examining the PEB
You can dump the PEB structure with the !peb command in the kernel debugger. The following example, which uses LiveKd, shows the PEB for the LiveKd process:
kd> !peb PEB at 7FFDF000 InheritedAddressSpace: No ReadImageFileExecOptions: No BeingDebugged: No ImageBaseAddress: 00400000 Ldr.Initialized: Yes Ldr.InInitializationOrderModuleList: 131f40 . 134b98 Ldr.InLoadOrderModuleList: 131ec0 . 134b88 Ldr.InMemoryOrderModuleList: 131ec8 . 134b90 00400000 C:\nt\livekd.exe 77F80000 C:\WINNT\System32\ntdll.dll 77920000 C:\WINNT\system32\IMAGEHLP.dll 78000000 C:\WINNT\system32\MSVCRT.DLL 77E80000 C:\WINNT\system32\KERNEL32.dll 77E10000 C:\WINNT\system32\USER32.dll 77F40000 C:\WINNT\system32\GDI32.DLL 77DB0000 C:\WINNT\system32\ADVAPI32.dll 77D40000 C:\WINNT\system32\RPCRT4.DLL 72A00000 C:\WINNT\system32\DBGHELP.dll SubSystemData: 0 ProcessHeap: 130000 ProcessParameters: 20000 WindowTitle: '\nt\livekd' ImageFile: 'C:\nt\livekd.exe' CommandLine: '\nt\livekd' DllPath: 'C:\nt;.;C:\WINNT\System32; C:\WINNT\system;C:\WINNT; C:\WINNT\system32;C:\WINNT; C:\WINNT\system32\WBEM; C:\Program Files\Support Tools\; C:\Program Files\Resource Kit\' Environment: 0x10000
A few of the key kernel global variables that relate to processes are listed in Figure These variables are referred to later in the chapter, when the steps in creating a process are described.
Figure Process-Related Kernel Variables
|PsActiveProcessHead||Queue header||List head of process blocks|
|PsIdleProcess||EPROCESS||Idle process block|
|PsInitialSystemProcess||Pointer to EPROCESS||Pointer to the process block of the initial system process (process ID 2) that contains the system threads|
|PspCreateProcessNotifyRoutine||Array of pointers||Array of pointers to routines to be called on process creation and deletion (maximum of eight)|
|PspCreateProcessNotifyRoutineCount||DWORD||Count of registered process notification routines|
|PspLoadImageNotifyRoutine||Array of pointers||Array of pointers to routines to be called on image load|
|PspLoadImageNotifyRoutineCount||DWORD||Count of registered image-load notification routines|
|PspCidTable||Pointer to HANDLE_TABLE||Handle table for process and thread client IDs|
Windows 2000 maintains a number of counters with which you can track the processes running on your system; you can retrieve these counters programmatically or view them with the Performance tool. Figure lists the performance counters relevant to processes (except for memory management and I/O-related counters, which are described in chapters 7 and 9, respectively).
Figure Process-Related Performance Counters
|Process: % Privileged Time||Describes the percentage of time that the threads in the process have run in kernel mode during a specified interval.|
|Process: % Processor Time||Describes the percentage of CPU time that the threads in the process have used during a specified interval. This count is the sum of % Privileged Time and % User Time.|
|Process: % User Time||Describes the percentage of time that the threads in the process have run in user mode during a specified interval.|
|Process: Elapsed Time||Describes the total elapsed time in seconds since this process was created.|
|Process: ID Process||Returns the process ID. This ID applies only while the process exists because process IDs are reused.|
|Process: Creating Process ID||Returns the process ID of the creating process. This value isn't updated if the creating process exits.|
|Process: Thread Count||Returns the number of threads in the process.|
|Process: Handle Count||Returns the number of handles open in the process.|
For reference purposes, some of the Win32 functions that apply to processes are described in Figure For further information, consult the Win32 API documentation in the MSDN Library.
Figure Process-Related Functions
|CreateProcess||Creates a new process and thread using the caller's security identification|
|CreateProcessAsUser||Creates a new process and thread with the specified alternate security token|
|CreateProcessWithLogonW||Creates a new process and thread with the specified alternate security token, allowing the user profile to be loaded|
|OpenProcess||Returns a handle to the specified process object|
|ExitProcess||Ends a process and notifies all attached DLLs|
|TerminateProcess||Ends a process without notifying the DLLs|
|FlushInstructionCache||Empties the specified process's instruction cache|
|GetProcessTimes||Obtains a process's timing information, describing how much time the process has spent in user and kernel mode|
|GetExitCodeProcess||Returns the exit code for a process, indicating how and why the process shut down|
|GetCommandLine||Returns a pointer to the command-line string passed to the current process|
|GetCurrentProcessId||Returns the ID of the current process|
|GetProcessVersion||Returns the major and minor versions of the Windows version on which the specified process expects to run|
|GetStartupInfo||Returns the contents of the STARTUPINFO structure specified during CreateProcess|
|GetEnvironmentStrings||Returns the address of the environment block|
|GetEnvironmentVariable||Returns a specific environment variable|
|Get/SetProcessShutdownParameters||Defines the shutdown priority and number of retries for the current process|
|GetGuiResources||Returns a count of User and GDI handles|
A number of tools for viewing (and modifying) processes and process information are available. These tools are included within Windows 2000 itself and within the Windows 2000 Support Tools, Windows 2000 debugging tools, Windows 2000 resource kits, the Platform SDK, and the DDK. The trouble is, you can't get all the information you need with one single tool. However, most information is available from more than one tool, but the data is sometimes identified by different names (and sometimes assigned different values) in each of the tools. To help you determine which tool to use to get the basic process information you need, consult Figure This table isn't a comprehensive list of all the information available about a process—for example, you'll find out what tools you can use to gather memory management information in Chapter 7—but if you need the basics, you'll find them here.
Figure Process-Related Tools
The following experiments illustrate the various views of process information you can obtain with some of these tools.
Viewing Process Information with Task Manager
The built-in Windows 2000 Task Manager provides a quick list of the processes running on the system. You can start Task Manager in one of three ways: (1) press Ctrl+Shift+Esc, (2) right-click on the taskbar and select Task Manager, or (3) press Ctrl+Alt+Delete and click the Task Manager button. Once Task Manager has started, click the Processes tab to see the list of running processes. Notice that processes are identified by the name of the image of which they are an instance. Unlike some objects in Windows 2000, processes can't be given global names. To display additional details, choose Select Columns from the View menu and select additional columns to be added, as shown here:
Although what you see in the Task Manager Processes tab is clearly a list of processes, what the Applications tab displays isn't as obvious. The Applications tab lists the top-level visible windows on all the desktops in the interactive window station. (By default, there are two desktop objects—you can create more by using the Win32 CreateDesktop function.) The Status column indicates whether or not the thread that owns the window is in a Windows message wait state. "Running" means the thread is waiting for windowing input; "Not Responding" means the thread isn't waiting for windowing input (for example, the thread might be running or waiting for I/O or some Win32 synchronization object).
From the Applications tab, you can match a task to the process that owns the thread that owns the task window by right-clicking on the task name and choosing Go To Process.
Viewing the Process Tree
One unique attribute about a process that most tools don't display is the parent or creator process ID. You can retrieve this value with the Performance tool (or programmatically) by querying the Creating Process ID. The Windows 2000 Support Tools command tlist /t uses the information in the attribute to display a process tree that shows the relationship of a process to its parent. Here's an example of output from tlist /t:
C:\>tlist /t System Process (0) System (2) smss.exe (21) csrss.exe (24) winlogon.exe (35) services.exe (41) spoolss.exe (69) llssrv.exe (94) LOCATOR.EXE (96) RpcSs.exe (112) inetinfo.exe (128) lsass.exe (44) nddeagnt.exe (119) explorer.exe (123) Program Manager OSA.EXE (121) WINWORD.EXE (117) Microsoft Word - msch02(s).doc cmd.exe (72) Command Prompt - tlist /t tlist.EXE (100)
Tlist indents each process to show its parent/child relationship. Processes whose parents aren't alive are left-justified, because even if a grandparent process exists, there's no way to find that relationship. Windows 2000 maintains only the creator process ID, not a link back to the creator of the creator, and so forth.
To demonstrate the fact that Windows 2000 doesn't keep track of more than just the parent process ID, follow these steps:
- Open a Command Prompt window.
- Type start cmd (which runs a second Command Prompt).
- Bring up Task Manager.
- Switch to the second Command Prompt.
- Type mspaint (which runs Microsoft Paint).
- Click the intermediate (second) Command Prompt window.
- Type exit. (Notice that Paint remains.)
- Switch to Task Manager.
- Click the Applications tab.
- Right-click on the Command Prompt task, and select Go To Process.
- Click on the Cmd.exe process highlighted in gray.
- Right-click on this process, and select End Process Tree.
- Click Yes in the Task Manager Warning message box.
The first Command Prompt window will disappear, but you should still see the Paintbrush window because it was the grandchild of the Command Prompt process you terminated; and because the intermediate process (the parent of Paintbrush) was terminated, there was no link between the parent and the grandchild.
Viewing Thread Activity with QuickSlice
QuickSlice gives a quick, dynamic view of the proportions of system and kernel time that each process currently running on your system is using. On line, the red part of the bar shows the amount of CPU time spent in kernel mode, and the blue part shows the user-mode time. (Although reproduced in the window below in black and white, the bars in the online display are always red and blue.) The total of all bars shown in the QuickSlice window should add up to 100 percent of CPU time. To run QuickSlice, click the Start button, choose Run, and enter Qslice.exe (assuming the Windows 2000 resource kit is in your path). For example, try running a graphics-intensive application such as Paint (Mspaint.exe). Open QuickSlice and Paint side by side, and draw squiggles in the Paint window. When you do so, you'll see Mspaint.exe running in the QuickSlice window, as shown here:
For additional information about the threads in a process, you can also double-click on a process (on either the process name or the colored bar). Here you can see the threads within the process and the relative CPU time each thread uses (not across the system):
Viewing Process Details with Process Viewer
The Process Viewer (Pviewer.exe) that comes with the Windows 2000 Support Tools permits you to view information about the running processes and threads as well as to kill processes and change process priority classes. You can use this tool to view processes both on the local computer and across the network on remote machines running Windows 2000. This tool is also available in the Platform SDK (where it's called Pview.exe.) The Process Viewer is well documented in the Windows 2000 Support Tools help file, but here's a quick overview of the options available to you. The basic display of the Process Viewer looks like this:
Here's what the various options do:
- The Computer text box displays the name of the computer whose processes are currently displayed. Click the Connect button to browse for another computer.
- The Memory Detail button shows memory management details about the selected process, such as the amount of memory committed to the process, the size of the working set, and so forth.
- The Kill Process button kills the selected process. Be very careful which process you kill, since the process will have no chance to perform any cleanup.
- The Refresh button refreshes the display—the Process Viewer doesn't update the information unless you request it.
- The Processor Time columns in the Process and Thread(s) list boxes show the total processor time the process or thread has used since it was created.
- The Priority collection of radio buttons regulates the selected process's priority class (the Real-time priority class isn't shown), and the Thread Priority collection displays the relative thread priorities of the threads within a process.
- At the bottom of the window, the number of context switches and the thread's dynamic priority, start address, and current PC are displayed.
To see the other displays of process and thread information, try running Tlist.exe (Support Tools), Pstat.exe (Platform SDK or www.reskit.com), Pmon.exe (Support Tools), or Pulist.exe (resource kit).
Using the Kernel Debugger !process Command
The !process command for the kernel debugger (described in Chapter 1) displays a subset of the information in an EPROCESS block. This output is arranged in two parts for each process. First you see the information about the process, as shown below. (Not all the fields in the output are labeled—only the parts germane to this experiment.)
After the basic process output comes a list of the threads in the process. That output is explained in the experiment "Using the Kernel Debugger !thread Command.." Other commands that display process information include !handle, which dumps the process handle table (described in more detail in the section "Object Handles and the Process Handle Table" in Chapter 3). Process and thread security structures are described in Chapter 8.
Another command that dumps an EPROCESS block is the !strct command. See the experiment "Displaying the Format of an EPROCESS Block" for more information on this command.