IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 29.Windows线程切换之被动切换(KiDispatchInterrupt) -> 正文阅读

[嵌入式]29.Windows线程切换之被动切换(KiDispatchInterrupt)

目录

前言

CPU时钟中断(HalpHpetClockInterrupt)

KiDispatchInterrupt


前言

在分析Windows线程主动切换时得知调用API时会触发线程切换,假设当前线程不调用API,操作系统如果实现线程切换呢?

  • 异常 (缺页异常)...
  • 中断 (时钟中断)...

CPU时钟中断(HalpHpetClockInterrupt)

Windbg输入!IDT 获取时钟中断函数

Windbg输入 bp HalpHpetClockInterrupt断点查看相关数据

时钟中断发生时IRQL等级1Fh.

Windbg输入kv获取调用堆栈,可以看出已经不再nt模块了.

时钟中断调用流程(Win7 x86 不同系统版本都会存在差异)如下:

HalpHpetClockInterrupt(hal) —— KeUpdateSystemTimeAssis(nt) —— KeUpdateSystemTime(nt) —— KeUpdateRunTime(nt) —— HalRequestSoftwareInterrupt(hal) —— KfLowerIrql(hal) —— HalpCheckForSoftwareInterrupt(hal) —— HalpDispatchSoftwareInterrupt(hal) —— KiDispatchInterrupt(nt)

KiDispatchInterrupt最终也会调用SwapContext来切换线程.

至此得知线程切换机制:

  • 主动调用API函数
  • 时钟中断
  • 异常处理

KiDispatchInterrupt

首先判断时间碎片是否到期

到期跳转执行KiQuantumEnd,此函数会重设时间碎片,并切换线程.

如果时间碎片未到期会继续判断当前核有无下个执行线程,有的话也会触发线程切换.

参考WRK实现:

VOID
KiQuantumEnd (
    VOID
    )

/*++

Routine Description:

    This function is called when a quantum end event occurs on the current
    processor. Its function is to determine whether the thread priority should
    be decremented and whether a redispatch of the processor should occur.

    N.B. This function is called at DISPATCH level and returns at DISPATCH
         level.

Arguments:

    None.

Return Value:

    None.

--*/

{

    PKPRCB Prcb;
    PKPROCESS Process;
    PRKTHREAD Thread;
    PRKTHREAD NewThread;

    //
    // If DPC thread activation is requested, then set the DPC event.
    //

    Prcb = KeGetCurrentPrcb();
    Thread = KeGetCurrentThread();
    if (InterlockedExchange(&Prcb->DpcSetEventRequest, FALSE) == TRUE) {
        KeSetEvent(&Prcb->DpcEvent, 0, FALSE);
    }

    //
    // Raise IRQL to SYNCH level, acquire the thread lock, and acquire the
    // PRCB lock.
    //
    // If the quantum has expired for the current thread, then update its
    // quantum and priority.
    //

    KeRaiseIrqlToSynchLevel();
    KiAcquireThreadLock(Thread);
    KiAcquirePrcbLock(Prcb);
    if (Thread->Quantum <= 0) { //判断时间碎片

        //
        // If quantum runout is disabled for the thread's process and
        // the thread is running at a realtime priority, then set the
        // thread quantum to the highest value and do not round robin
        // at the thread's priority level. Otherwise, reset the thread
        // quantum and decay the thread's priority as appropriate.
        //

        Process = Thread->ApcState.Process;
        if ((Process->DisableQuantum != FALSE) &&
            (Thread->Priority >= LOW_REALTIME_PRIORITY)) { //优先级

            Thread->Quantum = MAXCHAR; //重新赋值时间碎片

        } else {
            Thread->Quantum = Thread->QuantumReset; //线程时间碎片默认值

            //
            // Compute the new thread priority and attempt to reschedule the
            // current processor.
            //
            // N.B. The new priority will never be greater than the previous
            //      priority.
            //

            Thread->Priority = KiComputeNewPriority(Thread, 1); //调整线程优先级
            if (Prcb->NextThread == NULL) {
                if ((NewThread = KiSelectReadyThread(Thread->Priority, Prcb)) != NULL) {
                    NewThread->State = Standby;
                    Prcb->NextThread = NewThread;
                }

            } else {
                Thread->Preempted = FALSE; //抢占
            }
        }
    }

    //
    // Release the thread lock.
    //
    // If a thread was scheduled for execution on the current processor, then
    // acquire the PRCB lock, set the current thread to the new thread, set
    // next thread to NULL, set the thread state to running, release the PRCB
    // lock, set the wait reason, ready the old thread, and swap context to
    // the new thread.
    //

    KiReleaseThreadLock(Thread);
    if (Prcb->NextThread != NULL) {
        KiSetContextSwapBusy(Thread);
        NewThread = Prcb->NextThread;
        Prcb->NextThread = NULL;
        Prcb->CurrentThread = NewThread;
        NewThread->State = Running;
        Thread->WaitReason = WrQuantumEnd;
        KxQueueReadyThread(Thread, Prcb);
        Thread->WaitIrql = APC_LEVEL;
        KiSwapContext(Thread, NewThread);

    } else {
        KiReleasePrcbLock(Prcb);
    }

    //
    // Lower IRQL to DISPATCH level and return.
    //

    KeLowerIrql(DISPATCH_LEVEL);
    return;
}

并没有内核解析出来全面,但是核心处理还在,首先判断是否碎片是否到期,到期通过线程优先级以及是否关闭时间碎片来决定重设时间碎片大小,如果时间碎片未到期通过判断当前核是否有下个执行线程来决定是否切换线程.

线程切换的三种情况:

  • 当前线程主动调用API: API函数 KiSwapThread KiSwapContext SwapContext
  • 当前线程时间片到期: KiDispatchInterrupt KiQuantumEnd SwapContext
  • 有备用线程(KPCR.PrcbData.NextThread) KiDispatchInterrupt SwapContext
  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-11-22 12:30:12  更:2021-11-22 12:32:48 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 11:37:52-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码