Thread Internals

 < Day Day Up > 

Now that we've dissected processes, let's turn our attention to the structure of a thread. Unless explicitly stated otherwise, you can assume that anything in this section applies to both user-mode threads and kernel-mode system threads (which are described in Chapter 2).

Data Structures

At the operating-system level, a Windows thread is represented by an executive thread (ETHREAD) block, which is illustrated in Figure 6-7. The ETHREAD block and the structures it points to exist in the system address space, with the exception of the thread environment block (TEB), which exists in the process address space. In addition, the Windows subsystem process (Csrss) maintains a parallel structure for each thread created in a Windows process. Also, for threads that have called a Windows subsystem USER or GDI function, the kernelmode portion of the Windows subsystem (Win32k.sys) maintains a per-thread data structure (called the W32THREAD structure) that the ETHREAD block points to.

Figure 6-7. Structure of the executive thread block


Most of the fields illustrated in Figure 6-7 are self-explanatory. The first field is the kernel thread (KTHREAD) block. Following that are the thread identification information, the process identification information (including a pointer to the owning process so that its environment information can be accessed), security information in the form of a pointer to the access token and impersonation information, and finally, fields relating to LPC messages and pending I/O requests. As you can see in Table 6-8, some of these key fields are covered in more detail elsewhere in this book. For more details on the internal structure of an ETHREAD block, you can use the kernel debugger dt command to display the format of the structure.

Table 6-8. Key Contents of the Executive Thread Block

Element

Description

Additional Reference

KTHREAD

See Table 6-9.

 

Thread time

Thread create and exit time information.

 

Process identification

Process ID and pointer to EPROCESS block of the process that the thread belongs to.

 

Start address

Address of thread start routine.

 

Impersonation information

Access token and impersonation level (if the thread is impersonating a client).

Chapter 8

LPC information

Message ID that the thread is waiting for and address of message.

Local procedure calls (Chapter 3)

I/O information

List of pending I/O request packets (IRPs).

I/O system (Chapter 9)


Table 6-9. Key Contents of the KTHREAD Block

Element

Description

Additional Reference

Dispatcher header

Because the thread is an object that can be waited on, it starts with a standard kernel dispatcher object header.

Kernel Dispatcher objects (Chapter 3)

Execution time

Total user and kernel CPU time.

 

Pointer to kernel stack information

Base and upper address of the kernel stack.

Memory management (Chapter 7)

Pointer to system service table

Each thread starts out with this field service table pointing to the main system service table (KeServiceDescriptorTable). When a thread first calls a Windows GUI service, its system service table is changed to one that includes the GDI and USER services in Win32k.sys.

System Service Dispatching (Chapter 3)

Scheduling information

Base and current priority, quantum, affinity mask, ideal processor, scheduling state, freeze count, and suspend count.

Thread Scheduling

Wait blocks

The thread block contains four built-in wait blocks so that wait blocks don't have to be allocated and initialized each time the thread waits for something. (One wait block is dedicated to timers.)

Synchronization (Chapter 3)

Wait information

List of objects the thread is waiting for, wait reason, and time at which the thread entered the wait state.

Synchronization (Chapter 3)

Mutant list

List of mutant objects the thread owns.

Synchronization (Chapter 3)

APC queues

List of pending user-mode and kernelmode APCs, and alertable flag.

Aynchronous Procedure Call (APC) Interrrupts (Chapter 3)

Timer block

Built-in timer block (also a corresponding wait block).

 

Queue list

Pointer to queue object that the thread is associated with.

Synchronization (Chapter 3)

Pointer to TEB

Thread ID, TLS information, PEB pointer, and GDI and OpenGL information.

 


Let's take a closer look at two of the key thread data structures referred to in the preceding text: the KTHREAD block and the TEB. The KTHREAD block contains the information that the Windows kernel needs to access to perform thread scheduling and synchronization on behalf of running threads. Its layout is illustrated in Figure 6-8.

Figure 6-8. Structure of the kernel thread block


The key fields of the KTHREAD block are described briefly in Table 6-9.

EXPERIMENT: Displaying ETHREAD and KTHREAD Structures

The ETHREAD and KTHREAD structures can be displayed with the dt command in the kernel debugger. The following output shows the format of an ETHREAD:

lkd> dt nt!_ethread nt!_ETHREAD    +0x000Tcb              : _KTHREAD    +0x1c0CreateTime       : _LARGE_INTEGER    +0x1c0NestedFaultCount : Pos 0, 2 Bits    +0x1c0ApcNeeded        : Pos 2, 1 Bit    +0x1c8ExitTime         : _LARGE_INTEGER    +0x1c8LpcReplyChain    : _LIST_ENTRY    +0x1c8KeyedWaitChain   : _LIST_ENTRY    +0x1d0ExitStatus       : Int4B    +0x1d0OfsChain         : Ptr32Void    +0x1d4PostBlockList    : _LIST_ENTRY    +0x1dcTerminationPort  : Ptr32_TERMINATION_PORT    +0x1dcReaperLink       : Ptr32_ETHREAD    +0x1dcKeyedWaitValue   : Ptr32Void    +0x1e0ActiveTimerListLock : Uint4B    +0x1e4ActiveTimerListHead : _LIST_ENTRY    +0x1ecCid              : _CLIENT_ID    +0x1f4LpcReplySemaphore : _KSEMAPHORE    +0x1f4KeyedWaitSemaphore : _KSEMAPHORE    +0x208LpcReplyMessage  : Ptr32Void    +0x208LpcWaitingOnPort : Ptr32Void    +0x20cImpersonationInfo : Ptr32 _PS_IMPERSONATION_INFORMATION    +0x210IrpList          : _LIST_ENTRY    +0x218TopLevelIrp      : Uint4B    +0x21cDeviceToVerify   : Ptr32_DEVICE_OBJECT    +0x220ThreadsProcess   : Ptr32_EPROCESS    +0x224StartAddress     : Ptr32Void    +0x228Win32StartAddress : Ptr32Void    +0x228LpcReceivedMessageId : Uint4B    +0x22cThreadListEntry  : _LIST_ENTRY    +0x234RundownProtect   : _EX_RUNDOWN_REF    +0x238ThreadLock       : _EX_PUSH_LOCK    +0x23cLpcReplyMessageId : Uint4B    +0x240ReadClusterSize  : Uint4B    +0x244GrantedAccess    : Uint4B    +0x248CrossThreadFlags : Uint4B    +0x248Terminated       : Pos 0, 1 Bit    +0x248DeadThread       : Pos 1, 1 Bit    +0x248HideFromDebugger : Pos 2, 1 Bit    +0x248ActiveImpersonationInfo : Pos 3, 1 Bit    +0x248SystemThread     : Pos 4, 1 Bit    +0x248HardErrorsAreDisabled : Pos 5, 1 Bit    +0x248BreakOnTermination : Pos 6, 1 Bit    +0x248SkipCreationMsg    : Pos 7, 1 Bit    +0x248SkipTerminationMsg : Pos 8, 1 Bit    +0x24cSameThreadPassiveFlags : Uint4B    +0x24cActiveExWorker   : Pos 0, 1 Bit    +0x24cExWorkerCanWaitUser : Pos 1, 1 Bit    +0x24cMemoryMaker      : Pos 2, 1 Bit    +0x250SameThreadApcFlags : Uint4B    +0x250LpcReceivedMsgIdValid : Pos 0, 1 Bit    +0x250LpcExitThreadCalled : Pos 1, 1 Bit    +0x250AddressSpaceOwner : Pos 2, 1 Bit    +0x254ForwardClusterOnly : UChar    +0x255DisablePageFaultClustering : UChar

The KTHREAD can be displayed with a similar command:

lkd>  dt  nt!_kthread nt!_KTHREAD    +0x000Header          : _DISPATCHER_HEADER    +0x010MutantListHead  : _LIST_ENTRY    +0x018InitialStack    : Ptr32Void    +0x01cStackLimit      : Ptr32Void    +0x020Teb             : Ptr32Void    +0x024TlsArray        : Ptr32Void    +0x028KernelStack     : Ptr32Void    +0x02cDebugActive     : UChar    +0x02dState           : UChar    +0x02eAlerted         : [2] UChar    +0x030Iopl            : UChar    +0x031NpxState        : UChar    +0x032Saturation      : Char    +0x033Priority        : Char    +0x034ApcState        : _KAPC_STATE    +0x04cContextSwitches : Uint4B    +0x050IdleSwapBlock   : UChar    +0x051Spare0          : [3] UChar    +0x054WaitStatus      : Int4B


EXPERIMENT: Using the Kernel Debugger !thread Command

The kernel debugger !thread command dumps a subset of the information in the thread data structures. Some key elements of the information the kernel debugger displays can't be displayed by any utility: internal structure addresses; priority details; stack information; the pending I/O request list; and, for threads in a wait state, the list of objects the thread is waiting for.

To display thread information, use either the !process command (which displays all the thread blocks after displaying the process block) or the !thread command to dump a specific thread. The output of the thread information, along with some annotations of key fields, is shown here:




EXPERIMENT: Viewing Thread Information

The following output is the detailed display of a process produced by using the Tlist utility in the Windows Debugging Tools. Notice that the thread list shows the "Win32StartAddress." This is the address passed to the CreateThread function by the application. All the other utilities, except Process Explorer, that show the thread start address show the actual start address (a function in Kernel32.dll), not the applicationspecified start address.

C:\> tlist winword  155 WINWORD.EXE        Document1 - Microsoft Word    CWD:     C:\book\    CmdLine: "C:\Program Files\Microsoft Office\Office\WINWORD.EXE"    VirtualSize:    64448KB     PeakVirtualSize:     106748KB    WorkingSetSize:  1104KB     PeakWorkingSetSize:    6776KB    NumberOfThreads:2     156 Win32StartAddr:0x5032cfdb LastErr:0x00000000 State:Waiting     167 Win32StartAddr:0x00022982 LastErr:0x00000000 State:Waiting                      0x50000000  WINWORD.EXE      5.0.2163.1 shp  0x77f60000  ntdll.dll      5.0.2191.1 shp  0x77f00000  KERNEL32.dll          §          list of DLLs loaded in process


The TEB, illustrated in Figure 6-9, is the only data structure explained in this section that exists in the process address space (as opposed to the system space).

Figure 6-9. Fields of the thread environment block


The TEB stores context information for the image loader and various Windows DLLs. Because these components run in user mode, they need a data structure writable from user mode. That's why this structure exists in the process address space instead of in the system space, where it would be writable only from kernel mode. You can find the address of the TEB with the kernel debugger !thread command.

EXPERIMENT: Examining the TEB

You can dump the TEB structure with the !teb command in the kernel debugger. The output looks like this:

kd> !teb TEB at 7ffde000     ExceptionList:         0006b540     StackBase:             00070000     StackLimit:            00065000     SubSystemTib:          00000000     FiberData:             00001e00     ArbitraryUserPointer:  00000000     Self:                  7ffde000     EnvironmentPointer:    00000000     ClientId:              00000254 . 000007ac     RpcHandle:             00000000     Tls Storage:           00000000     PEB Address:           7ffdf000     LastErrorValue:        2     LastStatusValue:       c0000034     CountOwnedLocks:       0     HardErrorMode:      0


Kernel Variables

As with processes, a number of Windows kernel variables control how threads run. Table 6-10 shows the kernel-mode kernel variables that relate to threads.

Table 6-10. Thread-Related Kernel Variables

Variable

Type

Description

PspCreateThreadNotifyRoutine

Array of pointers

Array of pointers to routines to be called on during thread creation and deletion (maximum of eight).

PspCreateThreadNotifyRoutineCount

DWORD

Count of registered thread-notification routines.

PspCreateProcessNotifyRoutine

Array of pointers

Array of pointers to routines to be called on during process creation and deletion (maximum of eight).


Performance Counters

Most of the key information in the thread data structures is exported as performance counters, which are listed in Table 6-11. You can extract much information about the internals of a thread just by using the Performance tool in Windows.

Table 6-11. Thread-Related Performance Counters

Object: Counter

Function

Process: Priority Base

Returns the current base priority of the process. This is the starting priority for threads created within this process.

Thread: % Privileged Time

Describes the percentage of time that the thread has run in kernel mode during a specified interval.

Thread: % Processor Time

Describes the percentage of CPU time that the thread has used during a specified interval. This count is the sum of % Privileged Time and % User Time.

Thread: % User Time

Describes the percentage of time that the thread has run in user mode during a specified interval.

Thread: Context Switches/Sec

Returns the number of context switches per second that the system is executing.

Thread: Elapsed Time

Returns the amount of CPU time (in seconds) that the thread has consumed.

Thread: ID Process

Returns the process ID of the thread's process. This ID is valid only during the process's lifetime because process IDs are reused.

Thread: ID Thread

Returns the thread's thread ID. This ID is valid only during the thread's lifetime because thread IDs are reused.

Thread: Priority Base

Returns the thread's current base priority. This number might be different from the thread's starting base priority.

Thread: Priority Current

Returns the thread's current dynamic priority.

Thread: Start Address

Returns the thread's starting virtual address (Note: This address will be the same for most threads.)

Thread: Thread State

Returns a value from 0 through 7 relating to the current state of the thread.

Thread: Thread Wait Reason

Returns a value from 0 through 19 relating to the reason why the thread is in a wait state.


Relevant Functions

Table 6-12 shows the Windows functions for creating and manipulating threads. This table doesn't include functions that have to do with thread scheduling and priorities those are included in the section "Thread Scheduling" later in this chapter.

Table 6-12. Windows Thread Functions

Function

Description

CreateThread

Creates a new thread

CreateRemoteThread

Creates a thread in another process

OpenThread

Opens an existing thread

ExitThread

Ends execution of a thread normally

TerminateThread

Terminates a thread

GetExitCodeThread

Gets another thread's exit code

GetThreadTimes

Returns timing information for a thread

GetCurrentProcess

Returns a pseudo handle for the current thread

GetCurrentProcessId

Returns the thread ID of the current thread

GetThreadId

Returns the thread ID of the specified thread

Get/SetThreadContext

Returns or changes a thread's CPU registers

GetThreadSelectorEntry

Returns another thread's descriptor table entry (applies only to x86 systems)


Birth of a Thread

A thread's life cycle starts when a program creates a new thread. The request filters down to the Windows executive, where the process manager allocates space for a thread object and calls the kernel to initialize the kernel thread block. The steps in the following list are taken inside the Windows CreateThread function in Kernel32.dll to create a Windows thread.

  1. CreateThread creates a user-mode stack for the thread in the process's address space.

  2. CreateThread initializes the thread's hardware context (CPU architecture specific). (For further information on the thread context block, see the Windows API reference documentation on the CONTEXT structure.)

  3. NtCreateThread is called to create the executive thread object in the suspended state. For a description of the steps performed by this function, see the description of Stage 3 and Stage 6 in the section "Flow of CreateProcess."

  4. CreateThread notifies the Windows subsystem about the new thread, and the subsystem does some setup work for the new thread.

  5. The thread handle and the thread ID (generated during step 3) are returned to the caller.

  6. Unless the caller created the thread with the CREATE_SUSPENDED flag set, the thread is now resumed so that it can be scheduled for execution. When the thread starts running, it executes the steps described in the earlier section "Stage 6: Performing Process Initialization in the Context of the New Process" before calling the actual user's specified start address.

     < Day Day Up > 


    Microsoft Windows Internals
    Microsoft Windows Internals (4th Edition): Microsoft Windows Server 2003, Windows XP, and Windows 2000
    ISBN: 0735619174
    EAN: 2147483647
    Year: 2004
    Pages: 158

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net