[Previous] [Next]

Process Internals

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.

Data Structures

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 6-1 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.

Click to view at full size.

Figure 6-1 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 6-2 shows the key fields in an EPROCESS block.

Click to view at full size.

Figure 6-2 Structure of an executive process block

EXPERIMENT
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[0]:ááááááááááááá0xa8
ááááQuotaPoolUsage[0]:ááááááááááááááááá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[0]:áááááááááááááááááá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[2]
+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[2]
+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[2]
+0b0 uint32   QuotaPoolUsage[2]
+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[16]
+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

Table 6-1 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.

Table 6-1 Contents of the EPROCESS Block

Element Purpose Additional Reference
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 6-3. 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.)

Click to view at full size.

Figure 6-3 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 6-4 and is explained in more detail later in this chapter.

Click to view at full size.

Figure 6-4 Fields of the process environment block

EXPERIMENT
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

Kernel Variables

A few of the key kernel global variables that relate to processes are listed in Table 6-2. These variables are referred to later in the chapter, when the steps in creating a process are described.

Table 6-2 Process-Related Kernel Variables

Variable Type Description
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

Performance Counters

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. Table 6-3 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).

Table 6-3 Process-Related Performance Counters

Object: Counter Function
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.

Relevant Functions

For reference purposes, some of the Win32 functions that apply to processes are described in Table 6-4. For further information, consult the Win32 API documentation in the MSDN Library.

Table 6-4 Process-Related Functions

Function Description
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

Relevant Tools

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 Table 6-5. 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.

Table 6-5 Process-Related Tools

Click to view at full size.

The following experiments illustrate the various views of process information you can obtain with some of these tools.

EXPERIMENT
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.

EXPERIMENT
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:

  1. Open a Command Prompt window.
  2. Type start cmd (which runs a second Command Prompt).
  3. Bring up Task Manager.
  4. Switch to the second Command Prompt.
  5. Type mspaint (which runs Microsoft Paint).
  6. Click the intermediate (second) Command Prompt window.
  7. Type exit. (Notice that Paint remains.)
  8. Switch to Task Manager.
  9. Click the Applications tab.
  10. Right-click on the Command Prompt task, and select Go To Process.
  11. Click on the Cmd.exe process highlighted in gray.
  12. Right-click on this process, and select End Process Tree.
  13. 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.

EXPERIMENT
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):

EXPERIMENT
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:

Click to view at full size.

Here's what the various options do:

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).

EXPERIMENT
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.)

Click to view at full size.

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.