上篇:Windows内核学习笔记之线程(中)
一旦系统中存在多个线程,则这些线程将共享物理的处理器资源,它们实际上只得到了一部分处理器时间。如果线程的个数大于处理器的数量,则自然地,哪些线程先执行,哪些线程后执行,这需要由系统的线程调度器来决定。
Windows的线程调度器建立在线程的优先级的基础上,它允许一个高优先级的线程将CPU资源从低优先级的线程上抢过来,而线程的优先级并不是绝对一成不变,在系统执行过程中有些线程的优先级会动态地变化。另外,有些线程具有处理器亲和性,即只能在某些处理器上运行;而有些线程对特定的处理器更具有倾向性。
Windows内核将线程的优先级分为32级,其值从0到31。其中0级为最低,31级为最高,16级以上用于实时线程,16级以下则用于普通线程。因此,这32个值被分成了三种类别:
实时类别:16~31
动态类别:1~15
系统类别:0
在源码中,由如下的宏定义说明了这3个类别
进程对象KPROCESS结构的BasePriority域指定了一个进程的基本优先级,由于进程本身并不参与调度,所以这个值的意义在于该进程中的每个线程在初始化时都可以直接从该进程对象中获得基本的优先级。而线程对象KTHREAD结构的BasePriority和Priority域则分别定义了一个线程的静态和动态优先级。进程和线程的基本优先级是保持不变的,除非是通过调用函数KeSetPriorityAndQuantumProcess或KeSetBasePriorityThread来显式地改变。
运行在动态优先级类别中的线程,它们的实际优先级可能会根据特定的情形而作调整,所以,KTHREAD结构的Priority域记录了一个线程当前实际优先级。它往往是在BasePriority域的基础上提升一定的优先级增量。但是,无论怎么调整,Prioriry域值的范围都在1~15。
执行体层提供了6个优先级分类:
实时:Realtime
高:High
普通之上:Above Normal
普通:Normal
普通之下:Below Normal
低:Low
执行体运行按着6个类别来设置进程的优先级,这些选择项对应的优先级分别是24,13,10,8,6和4。执行体在创建进程时,调用PspComputeQuantumAndPriority来计算优先级,而PspComputerQuantumAndPriority函数根据进程EPROCESS对象中的PriorityClass域来查表以便获得内核层的优先级定义。此对照表定义在全局变量 PspPriorityTable中。以下是一些相关定义:
执行体层的优先级类别经过全局表PspPriorityTable变换后,就变成了内核层上的0~31优先级值。另外,在执行体层上,除了通过优先级类别的方式来设置一个进程的基本优先级以外,还可以通过NtSetInformationProcess函数对基本优先级进行微调,并非绝对由全局表PspPriorityTable决定的。
从这里对进程优先级的控制也可看到,执行体层的职能是提供管理和策略支持,并为上层应用程序提供服务,而内核层提供的是基本的线程调度机制。这正是策略与机制相分离的设计思想。
Windows提供的函数中,有不少带有"KPRIORITY Increment"参数,它代表了优先级提升量。优先级提升应该发生在该线程作出调度决定(即插入到对应优先级的调度链表中)以前。内核提供的带Increment参数的函数包括:
KeInsertQueueApc
KePulseEvent
KeSetEvent
KeReleaseMutant
KeReleaseSemaphore
KeSetProcess
KeBoostPriorityThread
KeTeriminateThread
下面这些是优先级提升的典型情形:
当一个I/O操作完成时,正在等待此I/O线程有更多的机会被立即执行。IoCompleteRequest函数有一个参数是优先级提升值,至于具体的提升量则由负责I/O的驱动程序来完成
一个线程在等待事件和信号量以后,其优先级得到提升
前台线程从等待状态中醒来时,有一点小小的优先级提升
在平衡集管理器系统线程中,扫描那些已进入就绪状态4s,但尚未被执行的线程,将它们的优先级提升至15。其用意在于避免优先级反转情形的长时间出现
窗口线程因窗口的活动而醒来时,会得到一个额外的优先级提升。这是窗口管理系统在调用KeSetEvent函数时设置的
KTHREAD的State域是一个跟线程调度有关的成员,反映了线程的当前调度状态,其类型是枚举类型KTHREAD_STATE,定义如下:
下图是这些状态的转移图:
在一个线程的生命周期中,它从完成初始化开始进入到线程调度器的视野中,之后,一直到完成所有预定的功能,最后终止并被销毁。
在通过系统调用NtCreateThread创建线程的过程中,会调用KeReadyThread来改变线程的状态,让线程进入就绪状态,由该函数的反汇编结果可以得知,该函数的实现是通过调用KiReadyThread来实现的,在该函数中同时会完成线程的调度。由于KiReadyThread的函数声明是fastcall,所以在调用之前会将线程对象作为参数赋给ecx
KiReadyThread函数执行过程中会用到比较多结构体的成员
以下是用到的线程对象中的成员
以下是用到的进程对象中的成员
每个CPU都有一个KPCR结构体,那也就有KPCB结构体,在一个多核环境下就会有多个KPCB结构体,而全局变量KiProcessorBlock保存的就是不同的核对应的KPCB结构体地址。全局变量kiReadySummary则保存了这些处理器的使用情况,当相应处理器没有被使用到的时候全局变量KiReadySummary中相应的位就会是0,否则是1
完成变量的赋值以后,判断进程状态是否为ProcessInMemory
如果不是,修改线程状态为Ready,ProcessReadyQueue为TRUE,将线程对象的WaitListEntry域链接到所属进程对象的WaitListEntry域中
判断进程对象是否为ProcessOutOfMemory,如果不是则退出函数
如果是则将进程的SwapListEntry域加入到链表KiProcessInSwapListHead中
调用KiSetSwapEvent通知交换线程执行换入操作然后退出函数
如果进程状态是ProcessInMemory,判断KernelStackResident是否为0
如果为0,修改进程与线程对象中的成员,将线程对象的SwapListEntry域加入到链表KiStackInSwapListHead中,调用KiSetSwapEvent后退出函数
如果KernelStackResident不为0,接下来会将线程状态该位Standby,线程中的Affinity与线程中的SoftAffinity与的结果如果不为0,就会将结果与全局变量KiIdelSummary进行与操作,如果为0就会将Affinity与全局变量KiIdleSummary进行与操作,结果保留在edx中
如果满足条件,接下来就会从KiProcessorBlock中获取相应的KPCB,此时ecx保存的是线程的IdealProcessor
判断获取的KPCB是否有下一线程
如果有下一线程,就会判断下一线程的优先级是否小于要设置状态的线程的优先级,此时的eax保存的是调度的线程的优先级
如果小于,就会将调度线程赋值到KPCB的下一线程中
如果获取的KPCB不存在下一线程,就会判断调度线程的优先级是否大于获取的KPCB的正在运行的线程的优先级
如果大于,就会将调度线程赋值给下一线程
如果调度线程优先级小于当前线程的优先级,就会将线程状态设置为Ready,将esi指向线程对象的WaitListEntry地址,从全局链表KiDispatcherReadyListHead中根据优先级获取调度链表,此时的eax代表了调度线程的优先级,判断Preempted是否为0
如果不为0,就会将调度线程加到调度链表头部
如果为0,则将调度线程加到调度链表尾部
根据调度线程优先级,将KiReadySummary相应的位置1,这里的edx等于1,eax为调度线程的优先级
由此可以知道,在KiDispatcherReadyListHead保存了需要被调度的不同优先级的线程的链表,不同的下标代表了不同的优先级。
有两种情况会发生线程切换,分为主动切换和被动切换。主动切换是通过调用一些系统提供的API,在这些API中会调用KiSwapThread,而该函数通过调用SwapContext来实现线程切换。被动切换则发生在线程分配的时限用完或者被抢占的时候,此时KiDispatchInter会处理这两种情况,而无论哪种情况,最后都会通过调用函数SwapContext来切换线程,具体情况如下图所示:
在KiSwapThread中首先会判断下一线程是否为NULL
如果不为NULL,则将其清空,然后跳转到loc_40AB3B处执行
如果没有下一线程,就会调用KiFindReadyThread来获取要切换的线程,接下来和上面一样开始运行loc_40AB3B的代码
loc_40AB3B的代码就是通过调用KiSwapContext来完成线程切换,此时eax保存的是要切换的线程对象,调用前会将其赋给ecx,判断返回值是否为0
如果不为0,则调用KiDeliverApc来交付APC队列
如果为0,退出函数执行
KiSwapContext函数则将要切换的线程对象赋值到当前KPCR的当前线程中,通过调用函数SwapContext来完成切换
在SwapContext中,首先就将目标线程的状态改为Running
判断NpxState是否为0
如果为0,就会修改Cr0
将当前栈顶地址赋给当前线程的KernelStack,将目标线程的栈底和栈边界分别赋值到KPCR相应的位置中,将栈底赋给eax后再提升0x210
再次将eax提升0x10以后赋值给TSS中的esp0供线程进行模式切换使用
将栈顶地址修改为目标线程的KernelStack,将目标线程的Teb
判断当前线程和目标线程的所属进程是否相同
如果不同会清空gs寄存器,修改cr3寄存器的内容为目标进程的页表基地址
为了让fs:[0]指向的地址是正确的KPCR地址,需要将当前KPCR地址赋给fs寄存器段选择子对应的段描述符中,此时GDT表基址偏移0x38的地址对应的段描述符就是fs寄存器的段选择子对应的段描述符
最后退出函数
《Windows内核原理与实现》
《Windows内核源码情景分析》(上册)
KPRIORITY PspPriorityTable[PROCESS_PRIORITY_CLASS_REALTIME
+
1
]
=
{
8
,
4
,
8
,
13
,
24
,
6
,
10
};
KPRIORITY PspPriorityTable[PROCESS_PRIORITY_CLASS_REALTIME
+
1
]
=
{
8
,
4
,
8
,
13
,
24
,
6
,
10
};
typedef enum _KTHREAD_STATE {
Initialized,
Ready,
Running,
Standby,
Terminated,
Waiting,
Transition
} KTHREAD_STATE;
typedef enum _KTHREAD_STATE {
Initialized,
Ready,
Running,
Standby,
Terminated,
Waiting,
Transition
} KTHREAD_STATE;
名称 |
含义 |
Initialized |
已初始化:说明一个线程对象的内部状态已初始化,这是线程创建过程中的一个内部状态,此时线程尚未加入到进程的链表中,没有启动 |
Ready |
就绪:代表该线程已经准备就绪,等待被调度执行。当线程调度器选择一个线程来执行时,它只考虑处于就绪状态的线程。此时,线程已被加入到某个处理器的就绪线程链表中 |
Running |
运行:线程正在运行。该线程一直占有处理器,直到分到的时限结束,或者被一个更高优先级的线程抢占,或者线程终止,或者主动放弃处理器执行权,或者进入等待状态 |
Standby |
备用:处于备用状态的线程已经被选中作为某个处理器上下一个要运行的线程。对于系统中的每个处理器,只能有一个线程可以处于备用状态。然而,一个处于备用状态的线程在真正被执行以前,有可能被被更高优先级的线程抢占 |
Terminated |
已终止:表示线程已完成任务,正在进行资源回收。可以通过使用函数KeterminateThread来设置此状态 |
Waiting |
等待:表示一个线程正在等待某个条件,比如等待一个分发器对象变成有信号状态,也可以等待多个对象。当等待的条件满足时,线程或者立即开始执行,或者回到就绪状态 |
Transition |
转移:处于转移状态的线程已经准备好运行,但是它的内核栈不在内存中。一旦它的内核栈被换入内存,则该线程进入就绪状态 |
DeferredReady |
延迟的就绪:处于延迟的就绪状态的线程也已经准备好可以运行了,但是,与就绪状态不同的是,它尚未确定在哪个处理器上运行。当有机会被调度时,或者直接转入备用状态,或者转到就绪状态。因此,此状态是为了多级处理器而引入的,对于单处理器系统没有意义 |
GateWait |
门等待:线程正在等待一个门对象。此状态与等待状态类似,只不过它是专门针对门对象而设计 |
.text:
0041501A
;
int
__stdcall KeReadyThread(PETHREAD Thread)
.text:
0041501A
_KeReadyThread@
4
proc near ; CODE XREF: PspCreateThread(x,x,x,x,x,x,x,x,x,x,x)
+
3AD
↓p
.text:
0041501A
; PspCreateThread(x,x,x,x,x,x,x,x,x,x,x)
+
8EFD9
↓p ...
.text:
0041501A
.text:
0041501A
Thread
=
dword ptr
8
.text:
0041501A
.text:
0041501A
mov edi, edi
.text:
0041501C
push ebp
.text:
0041501D
mov ebp, esp
.text:
0041501F
push ebx
.text:
00415020
xor ecx, ecx
.text:
00415022
call ds:__imp_@KeAcquireQueuedSpinLockRaiseToSynch@
4
; KeAcquireQueuedSpinLockRaiseToSynch(x)
.text:
00415028
mov ecx, [ebp
+
Thread] ; 将线程对象赋给ecx
.text:
0041502B
mov bl, al
.text:
0041502D
call @KiReadyThread@
4
; KiReadyThread(x)
.text:
00415032
mov cl, bl
.text:
00415034
call @KiUnlockDispatcherDatabase@
4
; KiUnlockDispatcherDatabase(x)
.text:
00415039
pop ebx
.text:
0041503A
pop ebp
.text:
0041503B
retn
4
.text:
0041503B
_KeReadyThread@
4
endp
.text:
0041501A
;
int
__stdcall KeReadyThread(PETHREAD Thread)
.text:
0041501A
_KeReadyThread@
4
proc near ; CODE XREF: PspCreateThread(x,x,x,x,x,x,x,x,x,x,x)
+
3AD
↓p
.text:
0041501A
; PspCreateThread(x,x,x,x,x,x,x,x,x,x,x)
+
8EFD9
↓p ...
.text:
0041501A
.text:
0041501A
Thread
=
dword ptr
8
.text:
0041501A
.text:
0041501A
mov edi, edi
.text:
0041501C
push ebp
.text:
0041501D
mov ebp, esp
.text:
0041501F
push ebx
.text:
00415020
xor ecx, ecx
.text:
00415022
call ds:__imp_@KeAcquireQueuedSpinLockRaiseToSynch@
4
; KeAcquireQueuedSpinLockRaiseToSynch(x)
.text:
00415028
mov ecx, [ebp
+
Thread] ; 将线程对象赋给ecx
.text:
0041502B
mov bl, al
.text:
0041502D
call @KiReadyThread@
4
; KiReadyThread(x)
.text:
00415032
mov cl, bl
.text:
00415034
call @KiUnlockDispatcherDatabase@
4
; KiUnlockDispatcherDatabase(x)
.text:
00415039
pop ebx
.text:
0041503A
pop ebp
.text:
0041503B
retn
4
.text:
0041503B
_KeReadyThread@
4
endp
偏移 |
名称 |
含义 |
0x128 |
Preempted |
布尔值,说明这个线程是否被高优先级的线程抢占了,只有当一个线程正在运行或者正在等待运行而被高优先级线程抢占的时候,此值才会是TRUE |
0x033 |
Priority |
指明了线程的优先级 |
0x02D |
State |
反映了当前线程的状态 |
0x129 |
ProcessReadyQueue |
布尔值,说明线程是否在所属进程的KPROCESS对象的ReadyListEntry链表中,TRUE表示在此链表中,FALSE表示不在此链表中 |
0x60 |
WaitListEntry |
双向链表节点,当一个线程正在等待被执行时,该域作为一个线程节点加入到某个链表中 |
0x60 |
SwapListEntry |
单链表节点,当线程的内核栈需要被换入时,插入到以全局变量KiStackInSwapListHead为链表头的单链表中 |
0x12A |
KernelStackResident |
布尔值,说明该线程的内核栈是否驻留在内存中,当内核栈被换出内存时,此值将被设置成FALSE;当换入内存时,在设置成TRUE |
0x124 |
Affinity |
指定了线程的处理器亲和性,此值初始继承自进程对象的Affinity值 |
0x1BA |
IdealProcessor |
指明了在多处理器上该线程的理想处理器 |
0x12B |
NextProcessor |
指明了该线程开始运行时的处理器 |
偏移 |
名称 |
作用 |
0x65 |
State |
说明了进程是否在内存中,共有六种可能的状态:ProcessInMemory, ProcessOutOfMemory, ProcessInTransition, ProcessOutTransition, ProcessInSwap, ProcessOutSwap |
0x40 |
ReadyListHead |
是一个双向链表头,记录了进程中处于就绪状态但尚未被加入全局就绪链表的线程,这个域的意义在于,当一个进程被换出内存后,它所属的线程一旦就绪,则被挂到此链表中,并要求换入该进程。此后,当该进程被换入内存时,ReadyListHead中的所有线程被加入到系统全局的就绪线程链表中 |
0x48 |
SwapListEntry |
单链表项,当一个进程要被换出内存时,它通过此域加入到KiProcessOutSwapListHead为链头的单链表中;当一个进程被换入内存时,它通过此域加入到以KiProcessInSwapListHead为链头的单链表中 |
0x60 |
StackCount |
记录当前由多少线程栈位于内存中 |
.text:
00405667
;
int
__fastcall KiReadyThread(PKTHREAD Thread)
.text:
00405667
@KiReadyThread@
4
proc near ; CODE XREF: KiInsertQueue(x,x,x)
+
7B
↑p
.text:
00405667
; KiUnwaitThread(x,x,x,x)
-
7671
↑p ...
.text:
00405667
.text:
00405667
var_8
=
dword ptr
-
8
.text:
00405667
var_Preempted
=
byte ptr
-
1
.text:
00405667
Thread
=
dword ptr
8
.text:
00405667
.text:
00405667
mov edi, edi
.text:
00405669
push ebp
.text:
0040566A
mov ebp, esp
.text:
0040566C
push ecx
.text:
0040566D
push ecx
.text:
0040566E
push ebx
.text:
0040566F
push esi
.text:
00405670
mov esi, ecx ; 将线程对象赋给esi
.text:
00405672
lea ecx, [esi
+
_KTHREAD.Preempted] ; 将Preempted地址赋给ecx
.text:
00405678
mov al, [ecx] ; 将Preempted地址中的内容赋给al
.text:
0040567A
mov byte ptr [ecx],
0
; 将Preempted赋值为
0
.text:
0040567D
mov ecx, ds:_KeTickCount.LowPart ; 将时间赋给ecx
.text:
00405683
push edi
.text:
00405684
mov edi, [esi
+
_KTHREAD.ApcState.Process]
.text:
00405687
mov [ebp
+
var_Preempted], al ; 将al赋给局部变量
.text:
0040568A
movsx eax, [esi
+
_KTHREAD.Priority] ; 将线程优先级赋给eax
.text:
0040568E
mov [esi
+
_KTHREAD.WaitTime], ecx ; 为WaitTime赋值
.text:
00405691
.text:
00405691
loc_405691: ; CODE XREF: KiReadyThread(x)
+
9817
↓j
.text:
00405691
cmp
[edi
+
_KPROCESS.State],
0
; 判断进程状态是否为ProcessInMemory
.text:
00405695
jnz loc_432827
.text:
00405667
;
int
__fastcall KiReadyThread(PKTHREAD Thread)
.text:
00405667
@KiReadyThread@
4
proc near ; CODE XREF: KiInsertQueue(x,x,x)
+
7B
↑p
.text:
00405667
; KiUnwaitThread(x,x,x,x)
-
7671
↑p ...
.text:
00405667
.text:
00405667
var_8
=
dword ptr
-
8
.text:
00405667
var_Preempted
=
byte ptr
-
1
.text:
00405667
Thread
=
dword ptr
8
.text:
00405667
.text:
00405667
mov edi, edi
.text:
00405669
push ebp
.text:
0040566A
mov ebp, esp
.text:
0040566C
push ecx
.text:
0040566D
push ecx
.text:
0040566E
push ebx
.text:
0040566F
push esi
.text:
00405670
mov esi, ecx ; 将线程对象赋给esi
.text:
00405672
lea ecx, [esi
+
_KTHREAD.Preempted] ; 将Preempted地址赋给ecx
.text:
00405678
mov al, [ecx] ; 将Preempted地址中的内容赋给al
.text:
0040567A
mov byte ptr [ecx],
0
; 将Preempted赋值为
0
.text:
0040567D
mov ecx, ds:_KeTickCount.LowPart ; 将时间赋给ecx
.text:
00405683
push edi
.text:
00405684
mov edi, [esi
+
_KTHREAD.ApcState.Process]
.text:
00405687
mov [ebp
+
var_Preempted], al ; 将al赋给局部变量
.text:
0040568A
movsx eax, [esi
+
_KTHREAD.Priority] ; 将线程优先级赋给eax
.text:
0040568E
mov [esi
+
_KTHREAD.WaitTime], ecx ; 为WaitTime赋值
.text:
00405691
.text:
00405691
loc_405691: ; CODE XREF: KiReadyThread(x)
+
9817
↓j
.text:
00405691
cmp
[edi
+
_KPROCESS.State],
0
; 判断进程状态是否为ProcessInMemory
.text:
00405695
jnz loc_432827
.text:
00432827
loc_432827: ; CODE XREF: KiReadyThread(x)
+
2E
↑j
.text:
00432827
mov [esi
+
_KTHREAD.State],
1
; 将线程State赋值为Ready
.text:
0043282B
mov [esi
+
_KTHREAD.ProcessReadyQueue],
1
; 将线程ProcessReadyQueue赋值为TRUE
.text:
00432832
lea ecx, [edi
+
_KPROCESS.ReadyListHead] ; 将进程ReadListHead地址赋给ecx
.text:
00432835
mov edx, [ecx
+
LIST_ENTRY.Blink]
.text:
00432838
lea eax, [esi
+
60h
] ; 取出WaitListEntry地址赋给eax
.text:
0043283B
mov [eax
+
LIST_ENTRY.Flink], ecx
.text:
0043283D
mov [eax
+
LIST_ENTRY.Blink], edx
.text:
00432840
mov [edx
+
LIST_ENTRY.Flink], eax
.text:
00432842
mov [ecx
+
LIST_ENTRY.Blink], eax
.text:
00432827
loc_432827: ; CODE XREF: KiReadyThread(x)
+
2E
↑j
.text:
00432827
mov [esi
+
_KTHREAD.State],
1
; 将线程State赋值为Ready
.text:
0043282B
mov [esi
+
_KTHREAD.ProcessReadyQueue],
1
; 将线程ProcessReadyQueue赋值为TRUE
.text:
00432832
lea ecx, [edi
+
_KPROCESS.ReadyListHead] ; 将进程ReadListHead地址赋给ecx
.text:
00432835
mov edx, [ecx
+
LIST_ENTRY.Blink]
.text:
00432838
lea eax, [esi
+
60h
] ; 取出WaitListEntry地址赋给eax
.text:
0043283B
mov [eax
+
LIST_ENTRY.Flink], ecx
.text:
0043283D
mov [eax
+
LIST_ENTRY.Blink], edx
.text:
00432840
mov [edx
+
LIST_ENTRY.Flink], eax
.text:
00432842
mov [ecx
+
LIST_ENTRY.Blink], eax
.text:
00432845
cmp
[edi
+
_KPROCESS.State],
1
; 判断进程状态是否为ProcessOutOfMemory
.text:
00432849
jnz loc_405745
.text:
00432845
cmp
[edi
+
_KPROCESS.State],
1
; 判断进程状态是否为ProcessOutOfMemory
.text:
00432849
jnz loc_405745
.text:
00432853
mov eax, ds:_KiProcessInSwapListHead
.text:
00432858
lea ecx, [edi
+
_KPROCESS.SwapListEntry]
.text:
0043285B
.text:
0043285B
loc_43285B: ; CODE XREF: KiReadyThread(x)
+
2D20B
↓j
.text:
0043285B
mov [ecx], eax
.text:
0043285D
mov edx, eax
.text:
0043285F
mov esi, ecx
.text:
00432861
mov edi, offset _KiProcessInSwapListHead
.text:
00432866
lock cmpxchg [edi], esi
.text:
0043286A
cmp
eax, edx
.text:
0043286C
jz loc_41475D
.text:
00432872
jmp short loc_43285B
.text:
00432853
mov eax, ds:_KiProcessInSwapListHead
.text:
00432858
lea ecx, [edi
+
_KPROCESS.SwapListEntry]
.text:
0043285B
.text:
0043285B
loc_43285B: ; CODE XREF: KiReadyThread(x)
+
2D20B
↓j
.text:
0043285B
mov [ecx], eax
.text:
0043285D
mov edx, eax
.text:
0043285F
mov esi, ecx
.text:
00432861
mov edi, offset _KiProcessInSwapListHead
.text:
00432866
lock cmpxchg [edi], esi
.text:
0043286A
cmp
eax, edx
.text:
0043286C
jz loc_41475D
.text:
00432872
jmp short loc_43285B
.text:
0041475D
loc_41475D: ; CODE XREF: KiReadyThread(x)
+
2D205
↓j
.text:
0041475D
; .text:
0044B716
↓j
.text:
0041475D
call _KiSetSwapEvent@
0
; KiSetSwapEvent()
.text:
00414762
jmp loc_405745
.text:
0041475D
loc_41475D: ; CODE XREF: KiReadyThread(x)
+
2D205
↓j
.text:
0041475D
; .text:
0044B716
↓j
.text:
0041475D
call _KiSetSwapEvent@
0
; KiSetSwapEvent()
.text:
00414762
jmp loc_405745
.text:
0040569B
cmp
[esi
+
_KTHREAD.KernelStackResident],
0
.text:
004056A2
jz loc_41473A
.text:
0040569B
cmp
[esi
+
_KTHREAD.KernelStackResident],
0
.text:
004056A2
jz loc_41473A
.text:
0041473A
loc_41473A: ; CODE XREF: KiReadyThread(x)
+
3B
↑j
.text:
0041473A
inc [edi
+
_KPROCESS.StackCount] ; StackCount加
1
.text:
0041473E
mov [esi
+
_KTHREAD.State],
6
; 线程状态赋值为Transition
.text:
00414742
mov eax, ds:_KiStackInSwapListHead
.text:
00414747
lea ecx, [esi
+
60h
] ; 将线程对象的SwapListEntry地址赋给ecx
.text:
0041474A
.text:
0041474A
loc_41474A: ; CODE XREF: KiReadyThread(x)
+
F0F4↓j
.text:
0041474A
mov [ecx], eax
.text:
0041474C
mov edx, eax
.text:
0041474E
mov esi, ecx
.text:
00414750
mov edi, offset _KiStackInSwapListHead
.text:
00414755
lock cmpxchg [edi], esi
.text:
00414759
cmp
eax, edx
.text:
0041475B
jnz short loc_41474A
.text:
0041475D
.text:
0041475D
loc_41475D: ; CODE XREF: KiReadyThread(x)
+
2D205
↓j
.text:
0041475D
; .text:
0044B716
↓j
.text:
0041475D
call _KiSetSwapEvent@
0
; KiSetSwapEvent()
.text:
00414762
jmp loc_405745
.text:
0041473A
loc_41473A: ; CODE XREF: KiReadyThread(x)
+
3B
↑j
.text:
0041473A
inc [edi
+
_KPROCESS.StackCount] ; StackCount加
1
.text:
0041473E
mov [esi
+
_KTHREAD.State],
6
; 线程状态赋值为Transition
.text:
00414742
mov eax, ds:_KiStackInSwapListHead
.text:
00414747
lea ecx, [esi
+
60h
] ; 将线程对象的SwapListEntry地址赋给ecx
.text:
0041474A
.text:
0041474A
loc_41474A: ; CODE XREF: KiReadyThread(x)
+
F0F4↓j
.text:
0041474A
mov [ecx], eax
.text:
0041474C
mov edx, eax
.text:
0041474E
mov esi, ecx
.text:
00414750
mov edi, offset _KiStackInSwapListHead
.text:
00414755
lock cmpxchg [edi], esi
.text:
00414759
cmp
eax, edx
.text:
0041475B
jnz short loc_41474A
.text:
0041475D
.text:
0041475D
loc_41475D: ; CODE XREF: KiReadyThread(x)
+
2D205
↓j
.text:
0041475D
; .text:
0044B716
↓j
.text:
0041475D
call _KiSetSwapEvent@
0
; KiSetSwapEvent()
.text:
00414762
jmp loc_405745
.text:
004056A8
movzx ecx, [esi
+
_KTHREAD.IdealProcessor] ; 将IdealProcessor赋给ecx
.text:
004056AF
mov edi, [esi
+
_KTHREAD.Affinity] ; 将Affinity赋给edi
.text:
004056B5
mov [esi
+
_KTHREAD.State],
3
; 将线程状态改为Standby
.text:
004056B9
mov edx, ds:_KiProcessorBlock[ecx
*
4
]
.text:
004056C0
mov ebx, [edx
+
4D0h
] ; 将MultiThreadSetMaster赋给ebx
.text:
004056C6
mov edx, [esi
+
_KTHREAD.SoftAffinity]
.text:
004056CC
and
edx, edi
.text:
004056CE
jz short loc_4056D2
.text:
004056D0
mov edi, edx
.text:
004056D2
.text:
004056D2
loc_4056D2: ; CODE XREF: KiReadyThread(x)
+
67
↑j
.text:
004056D2
mov edx, ds:_KiIdleSummary
.text:
004056D8
and
edx, edi
.text:
004056DA
jnz loc_4106D5
.text:
004056A8
movzx ecx, [esi
+
_KTHREAD.IdealProcessor] ; 将IdealProcessor赋给ecx
.text:
004056AF
mov edi, [esi
+
_KTHREAD.Affinity] ; 将Affinity赋给edi
.text:
004056B5
mov [esi
+
_KTHREAD.State],
3
; 将线程状态改为Standby
.text:
004056B9
mov edx, ds:_KiProcessorBlock[ecx
*
4
]
.text:
004056C0
mov ebx, [edx
+
4D0h
] ; 将MultiThreadSetMaster赋给ebx
.text:
004056C6
mov edx, [esi
+
_KTHREAD.SoftAffinity]
.text:
004056CC
and
edx, edi
.text:
004056CE
jz short loc_4056D2
.text:
004056D0
mov edi, edx
.text:
004056D2
.text:
004056D2
loc_4056D2: ; CODE XREF: KiReadyThread(x)
+
67
↑j
.text:
004056D2
mov edx, ds:_KiIdleSummary
.text:
004056D8
and
edx, edi
.text:
004056DA
jnz loc_4106D5
.text:
004056E0
xor edx, edx
.text:
004056E2
inc edx ; edx赋值为
1
.text:
004056E3
mov ebx, edx ; 将edx赋给ebx
.text:
004056E5
shl ebx, cl
.text:
004056E7
test edi, ebx
.text:
004056E9
jz loc_441903
.text:
004056EF
.text:
004056EF
loc_4056EF: ; CODE XREF: KiReadyThread(x)
+
3C2A9
↓j
.text:
004056EF
; KiReadyThread(x)
+
3C2D6
↓j
.text:
004056EF
mov [esi
+
_KTHREAD.NextProcessor], cl
.text:
004056F5
mov ebx, ds:_KiProcessorBlock[ecx
*
4
] ; 取出KPCB地址赋给ebx
.text:
004056E0
xor edx, edx
.text:
004056E2
inc edx ; edx赋值为
1
.text:
004056E3
mov ebx, edx ; 将edx赋给ebx
.text:
004056E5
shl ebx, cl
.text:
004056E7
test edi, ebx
.text:
004056E9
jz loc_441903
.text:
004056EF
.text:
004056EF
loc_4056EF: ; CODE XREF: KiReadyThread(x)
+
3C2A9
↓j
.text:
004056EF
; KiReadyThread(x)
+
3C2D6
↓j
.text:
004056EF
mov [esi
+
_KTHREAD.NextProcessor], cl
.text:
004056F5
mov ebx, ds:_KiProcessorBlock[ecx
*
4
] ; 取出KPCB地址赋给ebx
.text:
004056FC
mov edi, [ebx
+
8
] ; 将下一线程对象地址赋给edi
.text:
004056FF
test edi, edi
.text:
00405701
jnz loc_40EE20
.text:
004056FC
mov edi, [ebx
+
8
] ; 将下一线程对象地址赋给edi
.text:
004056FF
test edi, edi
.text:
00405701
jnz loc_40EE20
.text:
0040EE20
loc_40EE20: ; CODE XREF: KiReadyThread(x)
+
9A
↑j
.text:
0040EE20
movsx ecx, [edi
+
_KTHREAD.Priority]
.text:
0040EE24
cmp
eax, ecx
.text:
0040EE26
jle loc_405716
.text:
0040EE20
loc_40EE20: ; CODE XREF: KiReadyThread(x)
+
9A
↑j
.text:
0040EE20
movsx ecx, [edi
+
_KTHREAD.Priority]
.text:
0040EE24
cmp
eax, ecx
.text:
0040EE26
jle loc_405716
.text:
0041232E
loc_41232E: ; CODE XREF: KiReadyThread(x)
+
97E7
↑j
.text:
0041232E
call @KeReleaseQueuedSpinLockFromDpcLevel@
4
; KeReleaseQueuedSpinLockFromDpcLevel(x)
.text:
00412333
mov [ebx
+
8
], esi ; 将调度线程赋值给下一线程
.text:
00412336
mov eax, large fs:
20h
.text:
0041233C
mov cl, [esi
+
_KTHREAD.NextProcessor]
.text:
00412342
cmp
[eax
+
10h
], cl ; 将cl赋值给Number
.text:
00412345
jz loc_405745
.text:
0041234B
xor eax, eax
.text:
0041234D
inc eax ; eax
=
1
.text:
0041234E
jmp loc_40EB31
.text:
0041232E
loc_41232E: ; CODE XREF: KiReadyThread(x)
+
97E7
↑j
.text:
0041232E
call @KeReleaseQueuedSpinLockFromDpcLevel@
4
; KeReleaseQueuedSpinLockFromDpcLevel(x)
.text:
00412333
mov [ebx
+
8
], esi ; 将调度线程赋值给下一线程
.text:
00412336
mov eax, large fs:
20h
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2021-12-24 11:26
被1900编辑
,原因: