Windows中进程与线程的设置
关于进程与线程
操作系统“复习”
在学习操作系统的时候,有个重点就是进程与线程的区别。最开始进程和线程是没有分开的,由于多数操作系统分开了用户态和内核态,那么用户态就必须和内核态进行交互才能调用系统资源(通过IOCTL交互)。这样每一个进程在内核当中都有一个“进程描述符”的东西来描述这个进程,并根据调度算法完成进程的运行。这里就假设一个进程test.exe调用了0x40大小的内存空间,在只有进程的时候,进程描述符中就会标记这个内存被这个进程使用,同时指令和运行都在其中。
这样有个问题就是,我需要两个这种“进程”来运行,且他们需要的恰好是同一块内存的相同数据,如果只有进程的话,就会存在两个0x40的内存,同时造成不必要的复制粘贴。随后就有了线程这个概念,比如面对上述情况,进程就只含有一个0x40大小的内存,对内存的访问就交给这个线程对应的进程。
进程和程序
Windows的任务调度算法可以很好地适应多处理器和多任务的情形,在windows中的进程也遵守上述的准则。对于Windows内核需要做的事情是:维护一个全局的进程表,记录下当前有哪些进程正 在被执行;把时间分成适当的片段,在现代处理器结构中,这可以通过设置时钟中断来完成,因而每次时钟中断到来时系统就会获得控制权;在进程间实施切换,即保留上一个进 程的环境信息,恢复下一个进程的执行环境。关于Windows的调度算法可以简单理解为时间轮。
如果程序是一个完全的模块,那么他的内存就是我们熟悉的经典内存结构。
但是往往一个最简单的helloworld也会调用CRunTime的代码,所以有进程就能使用 共享内存 ,比如在静态数据区有着一份复制。
线程
线程不仅仅是一个控制流,它还有更多的内容。线程的调用栈(call stack)记录了它 作为控制流的状态信息,包括每一层函数调用和返回的指令地址。线程一定隶属于某个进 程,其控制流可以访问这个进程中的资源,包括所有的内存数据以及系统分配给此进程的 其他资源。一个进程可以有多个线程,由于这些线程隶属于同一个进程,所以它们之间相 互通信要方便得多,毕竟几乎所有的资源(并非全部)对于它们来说都是共享的。
Windows 中进程和线程的数据结构
内核层的进程和线程对象
在内核当中的描述为KPROCESS和KTHREAD。
在WRK中的定义为
typedef struct _KPROCESS { DISPATCHER_HEADER Header; LIST_ENTRY ProfileListHead; ULONG DirectoryTableBase; ULONG Unused0; KGDTENTRY LdtDescriptor; KIDTENTRY Int21Descriptor; WORD IopmOffset; UCHAR Iopl; UCHAR Unused; ULONG ActiveProcessors; ULONG KernelTime; ULONG UserTime; LIST_ENTRY ReadyListHead; SINGLE_LIST_ENTRY SwapListEntry; PVOID VdmTrapcHandler; LIST_ENTRY ThreadListHead; ULONG ProcessLock; ULONG Affinity; union { ULONG AutoAlignment: 1; ULONG DisableBoost: 1; ULONG DisableQuantum: 1; ULONG ReservedFlags: 29; LONG ProcessFlags; }; CHAR BasePriority; CHAR QuantumReset; UCHAR State; UCHAR ThreadSeed; UCHAR PowerState; UCHAR IdealNode; UCHAR Visited; union { KEXECUTE_OPTIONS Flags; UCHAR ExecuteOptions; }; ULONG StackCount; LIST_ENTRY ProcessListEntry; UINT64 CycleTime; } KPROCESS, *PKPROCESS;
|
那么在线程当中
typedef struct _KTHREAD { DISPATCHER_HEADER Header; UINT64 CycleTime; ULONG HighCycleTime; UINT64 QuantumTarget; PVOID InitialStack; PVOID StackLimit; PVOID KernelStack; ULONG ThreadLock; union { KAPC_STATE ApcState; UCHAR ApcStateFill[23]; }; CHAR Priority; WORD NextProcessor; WORD DeferredProcessor; ULONG ApcQueueLock; ULONG ContextSwitches; UCHAR State; UCHAR NpxState; UCHAR WaitIrql; CHAR WaitMode; LONG WaitStatus; union { PKWAIT_BLOCK WaitBlockList; PKGATE GateObject; }; union { ULONG KernelStackResident: 1; ULONG ReadyTransition: 1; ULONG ProcessReadyQueue: 1; ULONG WaitNext: 1; ULONG SystemAffinityActive: 1; ULONG Alertable: 1; ULONG GdiFlushActive: 1; ULONG Reserved: 25; LONG MiscFlags; }; UCHAR WaitReason; UCHAR SwapBusy; UCHAR Alerted[2]; union { LIST_ENTRY WaitListEntry; SINGLE_LIST_ENTRY SwapListEntry; }; PKQUEUE Queue; ULONG WaitTime; union { struct { SHORT KernelApcDisable; SHORT SpecialApcDisable; }; ULONG CombinedApcDisable; }; PVOID Teb; union { KTIMER Timer; UCHAR TimerFill[40]; }; union { ULONG AutoAlignment: 1; ULONG DisableBoost: 1; ULONG EtwStackTraceApc1Inserted: 1; ULONG EtwStackTraceApc2Inserted: 1; ULONG CycleChargePending: 1; ULONG CalloutActive: 1; ULONG ApcQueueable: 1; ULONG EnableStackSwap: 1; ULONG GuiThread: 1; ULONG ReservedFlags: 23; LONG ThreadFlags; }; union { KWAIT_BLOCK WaitBlock[4]; struct { UCHAR WaitBlockFill0[23]; UCHAR IdealProcessor; }; struct { UCHAR WaitBlockFill1[47]; CHAR PreviousMode; }; struct { UCHAR WaitBlockFill2[71]; UCHAR ResourceIndex; }; UCHAR WaitBlockFill3[95]; }; UCHAR LargeStack; LIST_ENTRY QueueListEntry; PKTRAP_FRAME TrapFrame; PVOID FirstArgument; union { PVOID CallbackStack; ULONG CallbackDepth; }; PVOID ServiceTable; UCHAR ApcStateIndex; CHAR BasePriority; CHAR PriorityDecrement; UCHAR Preempted; UCHAR AdjustReason; CHAR AdjustIncrement; UCHAR Spare01; CHAR Saturation; ULONG SystemCallNumber; ULONG Spare02; ULONG UserAffinity; PKPROCESS Process; ULONG Affinity; PKAPC_STATE ApcStatePointer[2]; union { KAPC_STATE SavedApcState; UCHAR SavedApcStateFill[23]; }; CHAR FreezeCount; CHAR SuspendCount; UCHAR UserIdealProcessor; UCHAR Spare03; UCHAR Iopl; PVOID Win32Thread; PVOID StackBase; union { KAPC SuspendApc; struct { UCHAR SuspendApcFill0[1]; CHAR Spare04; }; struct { UCHAR SuspendApcFill1[3]; UCHAR QuantumReset; }; struct { UCHAR SuspendApcFill2[4]; ULONG KernelTime; }; struct { UCHAR SuspendApcFill3[36]; PKPRCB WaitPrcb; }; struct { UCHAR SuspendApcFill4[40]; PVOID LegoData; }; UCHAR SuspendApcFill5[47]; }; UCHAR PowerState; ULONG UserTime; union { KSEMAPHORE SuspendSemaphore; UCHAR SuspendSemaphorefill[20]; }; ULONG SListFaultCount; LIST_ENTRY ThreadListEntry; LIST_ENTRY MutantListHead; PVOID SListFaultAddress; PVOID MdlForLockedTeb; } KTHREAD, *PKTHREAD;
|
Header:说明该对象是一个分发器对象,可以被等待。线程结束时,等待被满足。
MutantListHead:指向一个链表头。链表中包含所有属于该线程的突变体对象(mutant,对应互斥体对象)。
InitialStack:原始栈位置(高地址)
StackLimit:栈低地址
KernelStack:内核调用栈开始位置
StackBase:当前栈的基地址。
ThreadLock:自旋锁,用于保护线程数据成员。
ApcState:KAPC_STATE结构,指定线程的APC信息,包括APC链表,是否有APC正在等待,是否正在处理APC。
ApcQueueable:是否可插入APC
NextProcessor:关于处理器调度的选择。
DeferredProcessor:关于处理器调度的选择。
AdjustReason:优先级调整原因
AdjustIncrement:优先级调整调整量
ApcQueueLock:保护APC队列的自旋锁。
ContextSwitches:记录线程进行了多少次切换。
State:线程当前状态。
NpxState:浮点处理器状态。
Alertable:线程是否可以被唤醒。
WaitNext:
WaitIrql:原先的IRQL。
WaitReason:等待原因
WaitMode:线程等待时的处理器模式,内核or用户
WaitStatus:等待的结果状态。
WaitBlockList:KWAIT_BLOCK为元素的链表,记录线程所有等待的分发器对象。每个分发器对象也有一个KWAIT_BLOCK组成的链表,记录所有等待在该对象的线程。
GateObject:等待的门对象,等待门对象和等待分发器对象不会同时发生。
Priority:动态优先级。
BasePriority:基本优先级。
PriorityDecrement:优先级动态调整过程中的递减值。
Saturation:线程基本优先级调整相对于进程基本优先级是否超过了区间的一半。
EnableStackSwap:内核栈是否准许被换出。
SwapBusy:当前是否正在进程上下文切换。
Alerted:线程在警告模式下是否可以被唤醒。
WaitListEntry:双向链表节点,等待被执行时,作为节点加入某链表
SwapListEntry:单链表节点,内核栈需要被换出时,加入KiStackInSwapListHead为头的链表。另外,线程处于DeferredReady状态时加入DeferredReadyListHead为头的链表。
Queue:队列分发器对象,线程正在处理此队列中的项。
WaitTime:线程进入等待时刻的时间点。
KernelApcDisable/SpecialApcDisable:内核APC和特殊内核APC是否被禁止。
TEB:进程地址空间的一个TEB域
Timer:定时器。
AutoAlignment:与KPROCESS相同
DisableBoost:与KPROCESS相同
WaitBlock:4个KWAIT_BLOCK成员的数组,线程等待的分发器少于4个时,使用这里的空间,不分配新空间。
QueueListEntry:线程处理一个队列项时,加入到队列对象的线程链表中的地址。
TrapFrame:指向KTRAP_FRAME类型的指针。用户保存执行现场。
CallbackStack:线程的回调栈地址,在从内核模式返回用户模式时用。
ServiceTable: 指向系统使用的系统服务表,非GUI线程为KeServiceDescriptorTable,GUI线程为KeServiceDescriptorTableShadow。
IdealProcess:理想处理器
Preempted:是否被高优先级线程抢占了。
ProcessReadyQueue:是否在进程对象的ReadyListHead列表中。
KernelStackResident:线程的内核栈是否驻留在线程中。
Affinity:处理器亲和性,为线程指定的处理器集合必须是该集合的子集。
UserAffinity:线程的用户亲和性。
Process:执行线程的进程对象。
ApcStateIndex:指明当前APC状态在ApcStatePointer域中的索引。
Win32Thread:指向Windows子系统管理的区域的指针。
SuspendApc/SuspendSemaphore:用于支持线程挂起的域。
ThreadListEntry:双链表的节点,线程被创建时,加入到进程的ThreadListHead链表中。
SListFaultAddress:上一次用户模式互锁单链表POP操作发生页面错误的地址。
SuspendSemaphore:与上面有关。