以下针对WindowsXP
线程三种状态:运行、等待、就绪。
(1)处于运行态的线程存储在KPCR中
(2)处于就绪态和等待态的线程处于另外33个链表中,其中1个是等待链表,32个是就绪链表。(Win7、WIn10 64个)。这些链表使用_KTHREAD(+0x60)追踪线程,即线程在某一时刻,只能属于其中一个圈。(不管是就绪态还是等待态都挂在_KTHREAD(+0x60),即在_KTHREAD中用一块地址,指向等待链表和就绪链表

等待链表/调度链表

(1)若线程调用了Sleep()或者WaitForSingleObject()等函数,线程就挂到等待链表中,处于挂起态。
(2)32个调度链表,每个链表优先级不同
windbg使用如下命令查看等待链表头:

dd KiWaitListHead

windbg使用如下命令查看调度链表(32个):

dd KiDispatcherReadyListHead L50

Windows内核-线程

线程切换

每个线程有自己的内核堆栈,线程内核堆栈如下:
Windows内核-线程
每个内核堆栈具体如下:InitialStack开始的0x210字节存储浮点寄存器的时,从0x210开始到KernelStack存储_Trap_Frame结构。
Windows内核-线程

线程切换有三种方式(1)主动切换(2)时钟中断(3)异常

主动切换

执行流程:API函数---->KiSwapThread---->KiSwapContext---->SwapContext

线程调用SwapContext内核函数进行线程切换。
         (1)Windows中大部分API调用SwapContext函数,该函数用于线程切换(内部是将下一个线程的栈顶指向KPCR中的当前线程的栈顶)
         (2)线程切换时会边角是否属于同一个进程,若不是则切换Cr3.

时钟中断

具备以下两个条件通过调用SwapContext()内核函数切换线程:
         (1)当前CPU时间片到期
         执行流程:KiDispatchInterrupt---->KiQuantumEnd---->SwapContext
         (2)有备用线程(即KPCR.PrcbData.NextThread存在)
         执行流程:KiDispatchInterrupt---->SwapContext

CPU时间片
         (1)一个新的线程开始时,线程初始化程序会为_KTHREAD.Quantum赋初始值,该值的大小由_KPROCESS.ThreadQuantum决定。
         (2)每次时钟中断调用KeUpdateRuntime函数,该函数每次将当前线程Quantum减少3个单位(例如若Quantum=6,需要2个时钟中断才可以让CPU时间片到期),若Quantum=0,则将KPCR.PrcbData.QuantumEnd设为非0(代表该线程时间片到期)
         (3)函数KiDispatchInterrup判断时间片到期,调用KiQuantumEnd重新设置时间片,在KiQuantumEnd中通过KiFindReadyThread找到下一个线程,进行线程切换。当前线程被挂到调度链表

备用线程
若当前CPU时间片没到期,但是当前线程有备用线程,即KPCR.PrcbData.NextThread存在,线程也会发生切换。

异常处理

也是通过调用SwapContext()内核函数

相关文章:

  • 2022-12-23
  • 2022-02-13
  • 2021-11-30
  • 2021-08-30
  • 2021-12-21
  • 2021-11-04
  • 2022-01-29
  • 2022-12-23
猜你喜欢
  • 2022-12-23
  • 2021-09-07
  • 2022-01-07
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
相关资源
相似解决方案