天天看點

Windows核心原理與實作--Windows程序線程基本概念(1)

程序的一些基本概念

作業系統需要做的事情是:維護一個全局的程序表,記錄下目前有哪些程序正在被執行,把時間分成适當的片段,設定時鐘中斷來完成,因而每次時鐘中斷到來時系統就會獲得控制權,在程序間實施切換,即保留上一個程序的環境資訊,恢複下一個執行環境。

一個典型布局的程式結構是這樣的:

記憶體高位址 指令行 環境資訊(随運作時确定)

調用棧(随控制流而變化)

堆(動态資料區)

未初始化的資料 喜聞樂見的bss(靜态資料區)

已初始化的資料(靜态資料區)

記憶體低位址 代碼 text

線程的一些基本概念

線程有兩種模型,使用者級線程和核心級線程。使用者級線程模型的優勢是線程切換效率高,因為不涉及核心模式和使用者模式之間的切換,并且應用程式可以采用合适自己特點的線程選擇算法。核心級線程有可能應用各種算法來配置設定處理器時間,線程可以有優先級,高優先級的線程被優先執行。系統維護一個全局線程表,系統在适當的時候挂起一個正在執行的線程,這個适當的時候有多種可能:sleep、wait/select、硬中斷或異常、線程終止。核心級線程的好處是,無需考慮自己霸占處理器而導緻其他線程得不到處理器時間。代價是,所有線程切換都是在核心模式下完成的。對于在使用者模式下運作的線程來說,一個線程被切換出去,下次再切換回來,需要從使用者模式到核心模式,再從核心模式切換回使用者模式。

線程排程算法可以分為非搶占式和搶占式。搶占式通過一個時鐘中斷來獲得對處理器的控制權。有三種典型的線程排程算法:先到先服務算法,時間片輪轉算法,優先級排程算法。Windows的排程算法是一個搶占式的、支援多處理器的優先級排程算法,每個處理器定義了一個連結清單數組,相同優先級的線程挂在同一個連結清單中,不同優先級的線程分别屬于不同的連結清單。當一個線程滿足條件時,它首先被挂到目前處理器的一個待配置設定的連結清單,排程器在适當的時候會把待配置設定的連結清單上的線程配置設定到了某個處理器的對應優先級的線程連結清單中。

Windows中程序和線程的資料姐歐冠

微核心層的程序和線程對象

首先看微核心的資料結構,KPROCESS和KTHREAD。這裡以NT6核心為例

nt!_KPROCESS
   +0x000 Header           : _DISPATCHER_HEADER
   +0x018 ProfileListHead  : _LIST_ENTRY
   +0x028 DirectoryTableBase : Uint8B
   +0x030 ThreadListHead   : _LIST_ENTRY
   +0x040 ProcessLock      : Uint8B
   +0x048 Affinity         : _KAFFINITY_EX
   +0x070 ReadyListHead    : _LIST_ENTRY
   +0x080 SwapListEntry    : _SINGLE_LIST_ENTRY
   +0x088 ActiveProcessors : _KAFFINITY_EX
   +0x0b0 AutoAlignment    : Pos 0, 1 Bit
   +0x0b0 DisableBoost     : Pos 1, 1 Bit
   +0x0b0 DisableQuantum   : Pos 2, 1 Bit
   +0x0b0 ActiveGroupsMask : Pos 3, 4 Bits
   +0x0b0 ReservedFlags    : Pos 7, 25 Bits
   +0x0b0 ProcessFlags     : Int4B
   +0x0b4 BasePriority     : Char
   +0x0b5 QuantumReset     : Char
   +0x0b6 Visited          : UChar
   +0x0b7 Unused3          : UChar
   +0x0b8 ThreadSeed       : [4] Uint4B
   +0x0c8 IdealNode        : [4] Uint2B
   +0x0d0 IdealGlobalNode  : Uint2B
   +0x0d2 Flags            : _KEXECUTE_OPTIONS
   +0x0d3 Unused1          : UChar
   +0x0d4 Unused2          : Uint4B
   +0x0d8 Unused4          : Uint4B
   +0x0dc StackCount       : _KSTACK_COUNT
   +0x0e0 ProcessListEntry : _LIST_ENTRY
   +0x0f0 CycleTime        : Uint8B
   +0x0f8 KernelTime       : Uint4B
   +0x0fc UserTime         : Uint4B
   +0x100 InstrumentationCallback : Ptr64 Void
   +0x108 LdtSystemDescriptor : _KGDTENTRY64
   +0x118 LdtBaseAddress   : Ptr64 Void
   +0x120 LdtProcessLock   : _KGUARDED_MUTEX
   +0x158 LdtFreeSelectorHint : Uint2B
   +0x15a LdtTableLength   : Uint2B
           
nt!_KTHREAD
   +0x000 Header           : _DISPATCHER_HEADER
   +0x018 CycleTime        : Uint8B
   +0x020 QuantumTarget    : Uint8B
   +0x028 InitialStack     : Ptr64 Void
   +0x030 StackLimit       : Ptr64 Void
   +0x038 KernelStack      : Ptr64 Void
   +0x040 ThreadLock       : Uint8B
   +0x048 WaitRegister     : _KWAIT_STATUS_REGISTER
   +0x049 Running          : UChar
   +0x04a Alerted          : [2] UChar
   +0x04c KernelStackResident : Pos 0, 1 Bit
   +0x04c ReadyTransition  : Pos 1, 1 Bit
   +0x04c ProcessReadyQueue : Pos 2, 1 Bit
   +0x04c WaitNext         : Pos 3, 1 Bit
   +0x04c SystemAffinityActive : Pos 4, 1 Bit
   +0x04c Alertable        : Pos 5, 1 Bit
   +0x04c GdiFlushActive   : Pos 6, 1 Bit
   +0x04c UserStackWalkActive : Pos 7, 1 Bit
   +0x04c ApcInterruptRequest : Pos 8, 1 Bit
   +0x04c ForceDeferSchedule : Pos 9, 1 Bit
   +0x04c QuantumEndMigrate : Pos 10, 1 Bit
   +0x04c UmsDirectedSwitchEnable : Pos 11, 1 Bit
   +0x04c TimerActive      : Pos 12, 1 Bit
   +0x04c SystemThread     : Pos 13, 1 Bit
   +0x04c Reserved         : Pos 14, 18 Bits
   +0x04c MiscFlags        : Int4B
   +0x050 ApcState         : _KAPC_STATE
   +0x050 ApcStateFill     : [43] UChar
   +0x07b Priority         : Char
   +0x07c NextProcessor    : Uint4B
   +0x080 DeferredProcessor : Uint4B
   +0x088 ApcQueueLock     : Uint8B
   +0x090 WaitStatus       : Int8B
   +0x098 WaitBlockList    : Ptr64 _KWAIT_BLOCK
   +0x0a0 WaitListEntry    : _LIST_ENTRY
   +0x0a0 SwapListEntry    : _SINGLE_LIST_ENTRY
   +0x0b0 Queue            : Ptr64 _KQUEUE
   +0x0b8 Teb              : Ptr64 Void
   +0x0c0 Timer            : _KTIMER
   +0x100 AutoAlignment    : Pos 0, 1 Bit
   +0x100 DisableBoost     : Pos 1, 1 Bit
   +0x100 EtwStackTraceApc1Inserted : Pos 2, 1 Bit
   +0x100 EtwStackTraceApc2Inserted : Pos 3, 1 Bit
   +0x100 CalloutActive    : Pos 4, 1 Bit
   +0x100 ApcQueueable     : Pos 5, 1 Bit
   +0x100 EnableStackSwap  : Pos 6, 1 Bit
   +0x100 GuiThread        : Pos 7, 1 Bit
   +0x100 UmsPerformingSyscall : Pos 8, 1 Bit
   +0x100 VdmSafe          : Pos 9, 1 Bit
   +0x100 UmsDispatched    : Pos 10, 1 Bit
   +0x100 ReservedFlags    : Pos 11, 21 Bits
   +0x100 ThreadFlags      : Int4B
   +0x104 Spare0           : Uint4B
   +0x108 WaitBlock        : [4] _KWAIT_BLOCK
   +0x108 WaitBlockFill4   : [44] UChar
   +0x134 ContextSwitches  : Uint4B
   +0x108 WaitBlockFill5   : [92] UChar
   +0x164 State            : UChar
   +0x165 NpxState         : Char
   +0x166 WaitIrql         : UChar
   +0x167 WaitMode         : Char
   +0x108 WaitBlockFill6   : [140] UChar
   +0x194 WaitTime         : Uint4B
   +0x108 WaitBlockFill7   : [168] UChar
   +0x1b0 TebMappedLowVa   : Ptr64 Void
   +0x1b8 Ucb              : Ptr64 _UMS_CONTROL_BLOCK
   +0x108 WaitBlockFill8   : [188] UChar
   +0x1c4 KernelApcDisable : Int2B
   +0x1c6 SpecialApcDisable : Int2B
   +0x1c4 CombinedApcDisable : Uint4B
   +0x1c8 QueueListEntry   : _LIST_ENTRY
   +0x1d8 TrapFrame        : Ptr64 _KTRAP_FRAME
   +0x1e0 FirstArgument    : Ptr64 Void
   +0x1e8 CallbackStack    : Ptr64 Void
   +0x1e8 CallbackDepth    : Uint8B
   +0x1f0 ApcStateIndex    : UChar
   +0x1f1 BasePriority     : Char
   +0x1f2 PriorityDecrement : Char
   +0x1f2 ForegroundBoost  : Pos 0, 4 Bits
   +0x1f2 UnusualBoost     : Pos 4, 4 Bits
   +0x1f3 Preempted        : UChar
   +0x1f4 AdjustReason     : UChar
   +0x1f5 AdjustIncrement  : Char
   +0x1f6 PreviousMode     : Char
   +0x1f7 Saturation       : Char
   +0x1f8 SystemCallNumber : Uint4B
   +0x1fc FreezeCount      : Uint4B
   +0x200 UserAffinity     : _GROUP_AFFINITY
   +0x210 Process          : Ptr64 _KPROCESS
   +0x218 Affinity         : _GROUP_AFFINITY
   +0x228 IdealProcessor   : Uint4B
   +0x22c UserIdealProcessor : Uint4B
   +0x230 ApcStatePointer  : [2] Ptr64 _KAPC_STATE
   +0x240 SavedApcState    : _KAPC_STATE
   +0x240 SavedApcStateFill : [43] UChar
   +0x26b WaitReason       : UChar
   +0x26c SuspendCount     : Char
   +0x26d Spare1           : Char
   +0x26e CodePatchInProgress : UChar
   +0x270 Win32Thread      : Ptr64 Void
   +0x278 StackBase        : Ptr64 Void
   +0x280 SuspendApc       : _KAPC
   +0x280 SuspendApcFill0  : [1] UChar
   +0x281 ResourceIndex    : UChar
   +0x280 SuspendApcFill1  : [3] UChar
   +0x283 QuantumReset     : UChar
   +0x280 SuspendApcFill2  : [4] UChar
   +0x284 KernelTime       : Uint4B
   +0x280 SuspendApcFill3  : [64] UChar
   +0x2c0 WaitPrcb         : Ptr64 _KPRCB
   +0x280 SuspendApcFill4  : [72] UChar
   +0x2c8 LegoData         : Ptr64 Void
   +0x280 SuspendApcFill5  : [83] UChar
   +0x2d3 LargeStack       : UChar
   +0x2d4 UserTime         : Uint4B
   +0x2d8 SuspendSemaphore : _KSEMAPHORE
   +0x2d8 SuspendSemaphorefill : [28] UChar
   +0x2f4 SListFaultCount  : Uint4B
   +0x2f8 ThreadListEntry  : _LIST_ENTRY
   +0x308 MutantListHead   : _LIST_ENTRY
   +0x318 SListFaultAddress : Ptr64 Void
   +0x320 ReadOperationCount : Int8B
   +0x328 WriteOperationCount : Int8B
   +0x330 OtherOperationCount : Int8B
   +0x338 ReadTransferCount : Int8B
   +0x340 WriteTransferCount : Int8B
   +0x348 OtherTransferCount : Int8B
   +0x350 ThreadCounters   : Ptr64 _KTHREAD_COUNTERS
   +0x358 XStateSave       : Ptr64 _XSTATE_SAVE
           

每個KPROCESS都代表一個程序。ActiveProcessors記錄下了目前程序正在哪些處理器上運作。+0x070 ReadyListHead    : _LIST_ENTRY 代表了雙向連結清單的标頭,該連結清單記錄了這個程序中處于就緒狀态但尚未被加入全局就緒連結清單的線程。該連結清單每一項都是一個指向KTHREAD對象WaitListEntry域的位址。KPROCESS對象中記錄的資訊主要包括兩類:一類跟程序的記憶體環境相關,比如頁目錄表,交換狀态。另一類是與其線程相關的一些屬性,比如線程清單以及線程所需要的優先級、時限設定。

在KTHREAD中我們看到Teb域 +0x0b8 Teb              : Ptr64 Void,TEB指向程序空間中的一個TEB(線程環境塊結構)。TrapFrame域是最重要的部分,它表示當一個線程離開運作狀态時,其目前的執行狀态,比如現在的指令IP在哪裡,各個寄存器中的值是什麼,都必須保留下來,以便下次再輪到這個線程運作時,可以恢複原來的執行狀态。TrapFrame是記錄控制流狀态的資料結構,它是一個指向KTRAP_FRAME類型的指針。

通過KPROCESS和KTHREAD我們看到,核心層的程序和線程對象隻包含了系統資源管理和多控制流并發執行所涉及的基本資訊,沒有包含與應用程式相關聯的資訊。程序對象提供了線程的基本執行環境,包括程序位址空間和一組程序範圍内公用的參數;線程對象提供了為參與線程排程而必須的各種資訊及其維護控制流的狀态。