4.线程到底是如何调度和切换的?
本节内容将作为本篇文章最重要的部分来讲述,源代码才是我们的王道,在WRK-v1.2\base\ntos\ke\Yield.c文件里,我们终于看到代码了,需要说明的是这个部分并非是完整的调度,我们是从这个入手来看整个的过程,没有源代码的原理就是空中楼阁。
NTSTATUS NtYieldExecution (VOID)
{
KIRQL OldIrql;
PKTHREAD NewThread;
PRKPRCB Prcb;
NTSTATUS Status;
PKTHREAD Thread;
if (KiGetCurrentReadySummary() ==0) { //如果当前CPU没有就绪线程
return STATUS_NO_YIELD_PERFORMED;
} else {
Status =STATUS_NO_YIELD_PERFORMED;
Thread =KeGetCurrentThread(); //获取当前线程
OldIrql =KeRaiseIrqlToSynchLevel();//将运行级别提高到DISPATCH_LEVEL级别
Prcb = KeGetCurrentPrcb();//获取重要的PRCB机构
if (Prcb->ReadySummary !=0) { //如果有就绪线程
KiAcquireThreadLock(Thread);//锁定当前线程
KiAcquirePrcbLock(Prcb);//锁定当前PRCB
if (Prcb->NextThread== NULL) {
Prcb->NextThread =KiSelectReadyThread(1, Prcb);
} //如果没有线程准备好运行的话就向前找下一个可以运行的线程
if ((NewThread =Prcb->NextThread) != NULL) {
Thread->Quantum =Thread->QuantumReset; //前面讲了很久的时限了,看到源代码的时候还是惊喜了一些
Thread->Priority =KiComputeNewPriority(Thread, 1); //这里很有趣哦,下面会专门讲这个函数的。
KiReleaseThreadLock(Thread);//释放线程锁
KiSetContextSwapBusy(Thread);//将SwapBusy设置成TURE
//将新线程设置成正在运行
Prcb->NextThread =NULL;
Prcb->CurrentThread = NewThread;
NewThread->State =Running;
Thread->WaitReason= WrY