微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

reactos操作系统实现(44)

前面分析了怎么样把一个线程放到延迟就绪队列,接着下来的问题就是这些在就绪队列里的线程什么时候开始运行呢?又是怎么样把就绪队列的线程取出来运行的呢?线程调度的触发事件有以下四种:

1) 线程进入就绪状态,如一个刚创建的线程,或者一个刚结束的线程。

2) 线程的时间片用完。

3) 线程调用系统服务发生等待,或者被系统改变其优先级。

4) 线程改变自己运行的处理器。

先来分析第一种情况,当线程结束时产生的调度。可以从ReactosAPI里知道,终止一个线程可以使用API函数TerminateThread,而这个函数就是通过系统调用转换后,调用内核的函数NtTerminateThread,而NtTerminateThread调用线程结束函数PspTerminateThreadByPointer,紧接着它又调用函数PspExitThread在这函数调用内核线程结束函数KeTerminateThread。在内核函数调用函数KiSwapThread来进行线程调度切换。

第二种情况,就是线程的时间片用完。当每次时间中断后,就会调用时钟处理函数HalpClockInterrupt,最后依次调用下面的函数

KeUpdateSystemTime 更新系统时钟函数

HalRequestSoftwareInterrupt 请求软件中断函数

HalEndSystemInterrupt 处理软件中断结束。

SoftIntHandlerTable2 通过中断表调用KidispatchInterrupt函数

KiSwapContextInternal 进行线程的上下文切换,也就是切换线程。

第三种情况,当系统发生等待时,比如调用内核函数KeWaitForSingleObject等待时,就会调用函数KiSwapThread来进行线程切换。

可以看到好几个地方都需要调用函数KiSwapThread来切换线程,其实它就是把延迟就绪队列里的线程选择合适的线程来运行。它的代码如下:

#001 NTSTATUS

#002 FASTCALL

#003 KiSwapThread(IN PKTHREAD CurrentThread,

#004 IN PKPRCB Prcb)

#005 {

#006 BOOLEAN ApcState = FALSE;

#007 KIRQL WaitIrql;

#008 LONG_PTR WaitStatus;

#009 PKTHREAD NextThread;

#010 ASSERT(KeGetCurrentIrql() >= disPATCH_LEVEL);

#011

获取PRCB的锁。

#012 /* Acquire the PRCB lock */

#013 KiAcquirePrcbLock(Prcb);

#014

获取当前处理器的下一个运行的线程。

#015 /* Get the next thread */

#016 NextThread = Prcb->NextThread;

#017 if (NextThread)

#018 {

如果处理器对象里已经有一个准备好运行的线程,就立即运行它,设置线程的运行状态为运行。

#019 /* Already got a thread,set it up */

#020 Prcb->NextThread = NULL;

#021 Prcb->CurrentThread = NextThread;

#022 NextThread->State = Running;

#023 }

#024 else

#025 {

当前处理器对象里没有就绪线程,就从延迟队列里查找到合适的线程来运行。

#026 /* Try to find a ready thread */

#027 NextThread = KiSelectReadyThread(0,Prcb);

#028 if (NextThread)

#029 {

找到了可以运行的线程,设置这个线程为运行状态。

#030 /* Switch to it */

#031 Prcb->CurrentThread = NextThread;

#032 NextThread->State = Running;

#033 }

#034 else

#035 {

如果线程延迟就绪队列里没有可以运行的线程,就设置当前cpu为空闲状态。

#036 /* Set the idle summary */

#037 InterlockedOr((PLONG)&KiIdleSummary,Prcb->SetMember);

#038

选择处理器缺省的空闲线程来运行。

#039 /* Schedule the idle thread */

#040 NextThread = Prcb->IdleThread;

#041 Prcb->CurrentThread = NextThread;

#042 NextThread->State = Running;

#043 }

#044 }

#045

释放处理器锁。

#046 /* Sanity check and release the PRCB */

#047 ASSERT(CurrentThread != Prcb->IdleThread);

#048 KiReleasePrcbLock(Prcb);

#049

保存当前的IRQL

#050 /* Save the wait IRQL */

#051 WaitIrql = CurrentThread->WaitIrql;

#052

更新下一个运行线程的内存空间。

#053 /* REACTOS Mm Hack of Doom */

#054 MisyncForContextSwitch(NextThread);

#055

调用函数KiSwapContext来切换线程的运行环境。

#056 /* Swap contexts */

#057 ApcState = KiSwapContext(CurrentThread,NextThread);

#058

#059 /* Get the wait status */

#060 WaitStatus = CurrentThread->WaitStatus;

#061

检查是否需要进行异步调用

#062 /* Check if we need to deliver APCs */

#063 if (ApcState)

#064 {

#065 /* Lower to APC_LEVEL */

#066 KeLowerIrql(APC_LEVEL);

#067

#068 /* Deliver APCs */

#069 KiDeliverApc(KernelMode,NULL,NULL);

#070 ASSERT(WaitIrql == 0);

#071 }

#072

设置为低的优先级。

#073 /* Lower IRQL back to what it was and return the wait status */

#074 KeLowerIrql(WaitIrql);

#075 return WaitStatus;

#076}

原文地址:https://www.jb51.cc/react/308489.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐