進程的一些基本概念
操作系統需要做的事情是:維護一個全局的進程表,記錄下當前有哪些進程正在被執行,把時間分成適當的片段,設置時鐘中斷來完成,因而每次時鐘中斷到來時系統就會獲得控制權,在進程間實施切換,即保留上一個進程的環境信息,恢復下一個執行環境。
一個典型佈局的程序結構是這樣的:
內存高地址 命令行 環境信息(隨運行時確定)
調用棧(隨控制流而變化)
堆(動態數據區)
未初始化的數據 喜聞樂見的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我們看到,內核層的進程和線程對象只包含了系統資源管理和多控制流併發執行所涉及的基本信息,沒有包含與應用程序相關聯的信息。進程對象提供了線程的基本執行環境,包括進程地址空間和一組進程範圍內公用的參數;線程對象提供了爲參與線程調度而必須的各種信息及其維護控制流的狀態。