线程被动切换(时间碎片) - KiReadyThread函数详细分析
Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.html
线程被动切换(时间碎片) - KiReadyThread函数详细分析
每个线程都存在自己的时间碎片(_KTHREAD+0x6f QuanTum),当时间到了之后,其会让其他线程运行,现在我们就来详细分析一下其有关细节。
时间片更新函数:
HalpHpetClockInterrupt->KeUpdateSystemTime->KeUpdateRunTime
时间片检查函数:
HalEndSystemInterrupt->KiDispatchInterrupt
时间更新是利用CPU的DPC机制,所谓DPC就是类似于看门狗,CPU运行一定时间就会调用DPC运行某个DPC函数,之后我们再来详细分析DPC这块的内容。
1)_KiDispatchInterrupt 函数分析
时钟中断最后会调用 _KiDispatchInterrupt 这个函数,该函数思路比较清晰,判断时间碎片等有关函数。
其中关键的说Windows是采用抢占模式的其实就看一行代码:
“②”中如果其不存在下一个线程 KPCR.NextThread,其并不会去主动去找,而是继续运行原来线程,所以是主动抢占式的;其不存在一个队列,每个线程有序运行。
操作系统就看一个KPCR.NextThread,如果该值为空就继续运行原来的线程。
2)_KiReadyThread 函数分析
该函数是对于原来老的线程的处理,通过分析它你可以清楚地理解线程切换更详细的过程,但同时其也做了很多额外工作,比如线程的进程不在内存中,其会映射进内存。
我们应该分析其主干,对于涉及的额外的工作,我们并不要花过多精力去分析,这一点我们首先是要明确的。
(1)其先找到合适的CPU,在我们单核情况下其就存在单独一个CPU;
(2)判断CPU的 KPRCB.NextThread是否为空:
当为空时:
① 判断当前线程优先级和老的线程优先级的大小;
② 如果老的线程优先级比较大,则直接放入KPCR.NextThread中;否则放入线程的等待队列中 - KThread.WaitListEntry中;
③ 其中老线程是被抢占的(preemted),则放入 KThread.WaitListEntry头部,作为补偿,否则放入尾部。
当不为空时:
① 比较NextThread和老线程的优先级大小;
② 如果老的线程比较大,则放入KPCR.NextThread,而原来的老线程会设置有关标志位再去找自己合适的位置。
③ 否则放入线程的等待队列中 - KThread.WaitListEntry中,
其中老线程是被抢占的(preemted),则放入 KThread.WaitListEntry头部,作为补偿,否则放入尾部。
注释:在分析中会涉及到大量的进程与线程状态转换,我们从WRK中找到下列的有关定义,结合这个能帮助我们的理解。
3)_KiReadyThread 函数分析逆向细节
这函数分支比较庞大,我们在这里就按照上面所说的,简要的画出其步骤流程图,很多地方已经加了注释,比较好理解的。