windows驱动开发-内核调度(二)

这篇文档记录剩下的内核调度对象。

信号灯

任何驱动程序都可以使用信号量对象在其驱动程序创建的线程和其他驱动程序例程之间同步操作。 例如,当驱动程序没有未完成的 I/O 请求时,驱动程序专用线程可能会将自身置于等待状态,并且驱动程序的调度例程可能会在将 IRP 排入队列后将信号量设置为“已信号”状态。

在请求 I/O 操作的线程上下文中运行的最高级别驱动程序的调度例程可能使用信号灯来保护调度例程之间共享的资源。 用于同步 I/O 操作的较低级别的驱动程序调度例程也可能使用信号灯来保护该调度例程子集之间共享的资源或与驱动程序创建的线程共享的资源。

任何使用信号灯对象的驱动程序都必须在等待或释放信号量之前调用 KeInitializeSemaphore 。 下图演示了具有线程的驱动程序如何使用信号灯对象:

如上图所示,此类驱动程序必须为信号灯对象提供存储,该信号量应驻留。 驱动程序可以使用驱动程序创建 的设备对象的设备扩展 、控制器扩展或驱动程序分配的非分页池。

当驱动程序的 AddDevice 例程调用 KeInitializeSemaphore 时,它必须将指针传递给驱动程序的信号灯对象的常驻存储。 此外,调用方必须为信号量对象指定 Count ,如上图所示,该对象确定信号量) 的初始状态 非零。

调用方还必须指定信号灯 的 Limit ,可以是以下任一项:

  • Limit = 1:当此信号灯设置为“已信号”状态时,等待信号灯设置为“已信号”状态的单个线程将有资格执行,并且可以访问信号量保护的任何资源。这种类型的信号灯也称为 二进制信号灯 ,因为线程对信号灯保护的资源具有或没有独占访问权限。
  • Limit > 1: 当此信号灯设置为“已信号”状态时,等待信号量对象设置为“已信号”状态的一些线程将有资格执行,并且可以访问信号量保护的任何资源。这种类型的信号量称为 计数信号灯 ,因为将信号量设置为“已信号”状态的例程还指定有多少等待线程可以将其状态从等待更改为“就绪”。 此类等待线程的数量可以是初始化信号灯时设置的 “限制 ”,也可以是低于此预设 限制的某个数量。

很少有设备或中间驱动程序具有单个驱动程序创建的线程;有一组线程可能等待信号灯被获取或释放,甚至更少。 系统提供的驱动程序很少使用信号灯对象,而在这些驱动程序中,使用二元信号灯的驱动程序甚至更少。 尽管二进制信号灯在功能上可能类似于互斥对象,但二进制信号灯不提供针对 SMP 计算机中运行的系统线程的互斥对象具有的死锁的内置保护。

加载具有已初始化信号灯的驱动程序后,它可以同步保护共享资源的信号量上的操作。 例如,具有管理 IRP 排队的设备专用线程的驱动程序(例如系统软盘控制器驱动程序)可能会在信号灯上同步 IRP 队列,如上图所示:

  • 1. 线程调用 KeWaitForSingleObject ,其中包含指向初始化信号灯对象的驱动程序提供的存储的指针,使自身处于等待状态;
  • 2. 需要设备 I/O 操作的 IRP 开始出现。 驱动程序的调度例程将每个此类 IRP 插入到旋转锁定控制下的互锁队列中,并使用指向信号量对象的指针调用 KeReleaseSemaphore,这是驱动程序确定的线程优先级提升 (增量,如上图) 所示,调整为 1,在每个 IRP 排队时添加到信号灯的 Count 中, 并将布尔等待设置为 FALSE。 非零信号灯计数将信号量对象设置为“已信号”状态,从而将等待线程的状态更改为“就绪”;
  • 3. 当处理器可用时,内核会立即调度线程以执行:也就是说,当前没有其他具有更高优先级的线程处于就绪状态,并且没有内核模式例程可在更高的 IRQL 上运行;
  • 线程在旋转锁定控制下从互锁队列中删除 IRP,将其传递给其他驱动程序例程以供进一步处理,并再次调用 KeWaitForSingleObject 。 如果信号灯仍设置为信号状态 (即,其计数将保持非零值,表示驱动程序的联锁队列) 中存在更多 IRP,内核再次将线程的状态从“等待”更改为“就绪”;
  • 通过以这种方式使用计数信号量,此类驱动程序线程“知道”每当该线程运行时,都会从互锁队列中删除 IRP;

在大于 PASSIVE_LEVEL 的 IRQL 上运行的任何标准驱动程序例程都不能等待任何调度程序对象的非零间隔,而不会关闭系统,但是此类例程可以在 IRQL 小于或等于 DISPATCH_LEVEL 的情况下调用 KeReleaseSemaphore 。

互斥体

顾名思义,互斥对象是一种同步机制,旨在确保对一组内核模式线程之间共享的单个资源进行互斥访问。 只有使用执行工作线程的高级驱动程序,例如文件系统驱动程序 (FSD) 才可能使用互斥对象。

可能具有驱动程序创建的线程或工作线程回调例程的最高级别驱动程序也会使用互斥对象。 但是,任何具有可分页线程或工作线程回调例程的驱动程序都必须非常小心地管理其互斥对象的获取、等待和发布。

互斥对象具有内置功能,仅线程可以互斥、无死锁方式访问 SMP 计算机中的共享资源,互斥对象提供系统内核模式,内核一次将互斥体的所有权分配给单个线程。

获取互斥体的所有权会阻止 (APC) 传递正常的内核模式异步过程调用。 除非内核发出APC_LEVEL软件中断以运行特殊内核 APC(例如 I/O 管理器的 IRP 完成例程,该例程将结果返回到 I/O 操作的原始请求者)时,线程才不会被 APC 抢占。

线程可以获取它已拥有的互斥对象 (递归所有权) ,但在线程完全释放其所有权之前,递归获取的互斥对象不会设置为 Signaled 状态。 此类线程必须在获得所有权后多次显式释放互斥体,然后另一个线程才能获取互斥体。

内核绝不允许拥有互斥锁的线程在不首先释放互斥体并将其设置为“已信号”状态的情况下转换到用户模式。 如果拥有互斥体的任何 FSD 创建或驱动程序创建的线程在释放互斥体的所有权之前尝试将控制权返回到 I/O 管理器,则内核会关闭系统。

任何使用互斥对象的驱动程序都必须调用 KeInitializeMutex 一次,然后才能等待或释放其互斥对象。 下图演示了两个系统线程如何使用互斥体对象:

如上图所示,使用互斥对象的驱动程序必须为互斥对象提供存储,该互斥对象必须是驻留的。 驱动程序可以使用驱动程序创建 的设备对象的设备扩展 、控制器扩展或驱动程序分配的非分页池。

当驱动程序调用 KeInitializeMutex,通常从其 AddDevice 例程 时,它必须将指向驱动程序存储的指针传递给互斥对象,内核会将其初始化为 Signaled 状态。

在这样一个最高级别的驱动程序初始化后,它可以管理对共享资源的互斥访问,如上图所示。 例如,用于固有同步操作和线程的驱动程序调度例程可能会使用互斥体来保护驱动程序创建的 IRP 队列。

由于 KeInitializeMutex始终将互斥对象的初始状态设置为 Signaled (如上图所示) :

  1. 调度例程使用 Mutex 指针对 KeWaitForSingleObject 进行的初始调用会将当前线程立即进入就绪状态,授予互斥锁的线程所有权,并将互斥状态重置为 Not-Signaled。 调度例程恢复运行后,就可以安全地将 IRP 插入互斥保护的队列中;
  2. 当第二个线程 (另一个调度例程、驱动程序提供的工作线程回调例程或驱动程序创建的线程) 使用 Mutex 指针调用 KeWaitForSingleObject 时,第二个线程将进入等待状态;
  3. 当调度例程按照步骤 1 中所述完成对 IRP 的排队时,它会使用 Mutex 指针和布尔等待值调用 KeReleaseMutex,该值指示它打算在 KeReleaseMutex 返回控件后立即调用 KeWaitForSingleObject (还是 KeWaitForMutexObject) ;
  4. 假设调度例程在步骤 3 中释放了互斥体的所有权, Wait 设置为 FALSE),则 KeReleaseMutex 将互斥体设置为 Signaled 状态。 互斥体当前没有所有者,因此内核确定另一个线程是否正在等待该互斥体。 如果是这样,内核会使第二个线程 () 互斥体所有者看到步骤 2,可能会将线程的优先级提升到最低实时优先级值,并将其状态更改为就绪;
  5. 当处理器可用时,内核会立即调度第二个线程以供执行:也就是说,当前没有其他具有更高优先级的线程处于就绪状态,并且没有内核模式例程可在更高的 IRQL 上运行。 第二个线程 (调度例程排队 IRP 或驱动程序的工作线程回调例程或驱动程序创建的线程取消排队 IRP) 现在可以安全地访问受互斥保护的 IRP 队列,直到它调用 KeReleaseMutex;

如果线程以递归方式获取互斥对象的所有权,则该线程必须显式调用 KeReleaseMutex 的次数与它在互斥上等待的次数一样多,以便将互斥对象设置为 Signaled 状态。 例如,如果线程使用同一 Mutex 指针调用 KeWaitForSingleObject,然后调用 KeWaitForMutexObject,则在获取 mutex 时,它必须调用 KeReleaseMutex 两次,以便将互斥对象设置为 Signaled 状态。

使用 Wait 参数设置为 TRUE 调用 KeReleaseMutex 表示调用方打算在从 KeReleaseMutex 返回时立即调用 KeWait Xxx 支持例程。

对于将 Wait 参数设置为 KeReleaseMutex,请考虑以下准则:

  • 在 IRQL PASSIVE_LEVEL运行的可分页线程或可分页驱动程序例程不应调用将 Wait 参数设置为 TRUE 的 KeReleaseMutex。 如果调用方恰好在 调用 KeReleaseMutex 和 KeWaitXxx对象 之间分页,则此类调用会导致严重页面错误;
  • 在大于 PASSIVE_LEVEL 的IRQL上运行的任何标准驱动程序例程都不能等待任何调度程序对象的非零间隔,而不会关闭系统。 但是,如果此类例程在IRQL小于或等于 DISPATCH_LEVEL 运行时拥有互斥体,则可以调用 KeReleaseMutex ;
互斥体的替代

从 Windows 2000 开始,如果驱动程序要求以 IRQL <= APC_LEVEL 运行的代码采用低开销互斥形式,则可以使用快速互斥。 快速互斥可以保护一次只能由一个线程输入的代码路径。 若要输入受保护的代码路径,线程将获取互斥体。 如果另一个线程已获取互斥体,则当前线程的执行将暂停,直到释放互斥体。 若要退出受保护的代码路径,线程 会释放互斥体。

从 Windows Server 2003 开始,驱动程序还可以使用受保护的互斥体。 受保护的互斥体是快速互斥的替代项,但性能更好。 与快速互斥体一样,受保护的互斥体可以保护一次只能由一个线程输入的代码路径。 但是,与使用快速互斥体的代码相比,使用受保护的互斥体的代码的运行速度要快。

在Windows 8之前的 Windows 版本中,受保护的互斥体的实现方式与快速互斥体不同。 受快速互斥锁保护的代码路径在 IRQL = APC_LEVEL运行。 受受保护的互斥锁保护的代码路径在 IRQL <= APC_LEVEL运行,但禁用了所有 APC。 在这些早期版本的 Windows 中,获取受保护的互斥体比获取快速互斥体要快。 但是,这两种类型的互斥体的行为相同,并受到相同的限制。 具体而言,不应从受快速互斥体或受保护的互斥体保护的代码路径调用在 IRQL = APC_LEVEL 时非法调用的内核例程。

从Windows 8开始,受保护的互斥体作为快速互斥体实现。 在受受保护的互斥体或快速互斥体保护的代码路径中, 驱动程序验证程序 将内核例程的调用视为发生在 IRQL = APC_LEVEL。 与早期版本的 Windows 一样,在APC_LEVEL非法调用在受受保护的互斥体或快速互斥体保护的代码路径中是非法的。

快速互斥

快速互斥体由 FAST_MUTEX 结构表示。 驱动程序为 FAST_MUTEX 结构分配自己的存储,然后调用 ExInitializeFastMutex 例程来初始化该结构。

线程通过执行以下操作之一获取快速互斥体:

  • 调用 ExAcquireFastMutex 例程。 如果互斥体已被另一个线程获取,则调用线程的执行将暂停,直到互斥锁可用;
  • 调用 ExTryToAcquireFastMutex 例程以尝试在不挂起当前线程的情况下获取快速互斥体。 无论是否已获取互斥体,例程都会立即返回。 如果 ExTryToAcquireFastMutex 成功获取调用方互斥体,则返回 TRUE;否则返回 FALSE;

线程调用 ExReleaseFastMutex 来释放由 ExAcquireFastMutex 或 ExTryToAcquireFastMutex 获取的快速互斥体。

受快速互斥锁保护的代码路径在 IRQL = APC_LEVEL运行。 ExAcquireFastMutex 和 ExTryToAcquireFastMutex 将当前 IRQL 提升为 APC_LEVEL, ExReleaseFastMutex 还原原始 IRQL。 因此,当线程持有快速互斥体时,将禁用所有 APC。

如果保证代码路径始终在 APC_LEVEL 运行,则驱动程序可以改为调用 ExAcquireFastMutexUnsafe 和 ExReleaseFastMutexUnsafe 来获取和释放快速互斥。 这些例程不会更改当前 IRQL,仅当当前 IRQL APC_LEVEL时才能安全使用。

快速互斥体不能以递归方式获取。 如果已持有快速互斥锁的线程尝试获取它,该线程将死锁。 快速互斥只能在 IRQL <= APC_LEVEL 下运行的代码中使用。

受保护的互斥体

从 Windows Server 2003 开始提供的受保护的互斥体与快速互斥体具有相同的功能,但性能更高。

从Windows 8开始,受保护的互斥体和快速互斥体的实现方式相同。

在Windows 8之前的 Windows 版本中,受保护的互斥体的实现方式与快速互斥体不同。 获取快速互斥体会将当前 IRQL 提升为APC_LEVEL,而获取受保护的互斥体会进入受保护的区域,这是一个更快的操作。

受保护的互斥体由 KGUARDED_MUTEX 结构表示。 驱动程序为 KGUARDED_MUTEX 结构分配自己的存储,然后调用 KeInitializeGuardedMutex 例程来初始化该结构。

线程通过执行以下操作之一获取受保护的互斥体:

  • 调用 KeAcquireGuardedMutex。 如果互斥体已被另一个线程获取,则调用线程的执行将暂停,直到互斥锁可用;
  • 调用 KeTryToAcquireGuardedMutex 以尝试在不暂停当前线程的情况下获取受保护的互斥体。 无论是否已获取互斥体,例程都会立即返回。 如果 KeTryToAcquireGuardedMutex 成功获取调用方互斥体,则返回 TRUE ;否则返回 FALSE;

线程调用 KeReleaseGuardedMutex 以释放 KeAcquireGuardedMutex 或 KeTryToAcquireGuardedMutex 获取的受保护的互斥体。

保存受保护的互斥锁的线程在受保护的区域内隐式运行。 KeAcquireGuardedMutex 和 KeTryToAcquireGuardedMutex 进入受保护的区域,而 KeReleaseGuardedMutex 退出该区域。 当线程持有受保护的互斥体时,将禁用所有 APC。

如果保证代码路径在禁用所有 APC 的情况下运行,则驱动程序可以改用 KeAcquireGuardedMutexUnsafe 和 KeReleaseGuardedMutexUnsafe 来获取和释放受保护的互斥体。 这些例程不会进入或退出受保护的区域,只能在已存在的受保护区域中使用,或者在 IRQL = APC_LEVEL 中使用。

无法以递归方式获取受保护的互斥体。 如果已持有受保护的互斥锁的线程尝试获取它,该线程将死锁。 受保护的互斥体只能在 IRQL <= APC_LEVEL 下运行的代码中使用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/8941.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

javaWeb入门(自用)

1. vue学习 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title><script src"https://unpkg.com/vue2"></script> </head> <body><div id"…

Python 使用 WeChatFerry 搭建部署微信机器人详细教程(更新中)

下载安装 wcferry 库 通过 pip 快速安装 wcferry pip install wcferry免责声明&#xff1a;仅供学习和技术研究使用&#xff0c;不得用于任何商业或非法行为&#xff0c;否则后果自负。 基本原理 当微信收到消息时&#xff0c;抢在微信处理&#xff08;显示到页面&#xff0…

C++与java回调函数用法区别实例(二百七十一)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

Netty 实现dubbo rpc

一、RPC 的基本介绍 RPC (Remote Procedure Call) 远程过程调用&#xff0c;是一个计算机通信协议。该协议允许运行于一台计算机的程序调用另一台计算机的子程序&#xff0c;而程序员无需额外的为这个交互编程。也就是说可以达到两个或者多个应用程序部署在不同的服务器上&…

HOOPS Visualize:工业级3D可视化SDK,打造移动端和PC端工程应用程序

HOOPS Visualize是一种高性能的软件开发工具包&#xff08;SDK&#xff09;&#xff0c;旨在帮助开发人员轻松构建和集成高质量的3D可视化功能。这是一种全功能的&#xff0c;以工程为重点的场景图技术&#xff0c;我们称为Core Graphics。Core Graphics可集成到一个框架中&…

webpack从零到1 构建 vue3

为什么要手写webpack 不用cli &#xff08;无的放矢&#xff09;并不是 其实是为了加深我们对webpack 的了解方便以后灵活运用webpack 的技术 初始化项目结构&#xff08;跟cli 结构保持一致&#xff09; 新建 public src 等文件夹npm init -y 创建package.json文件tsc --init…

opencv基础篇 ——(十一)常用照片处理函数

改善图像的亮度(illuminationChange) 用于改善光照条件不佳导致的图像对比度低下或局部过暗/过亮的问题。该函数通过模拟全局和局部光照变化&#xff0c;旨在提高图像的整体视觉质量&#xff0c;特别是在低光照条件下&#xff0c;使得图像中的重要细节更加清晰可见。 函数原型…

IDEA Maven项目,控制台出现乱码的问题

前言 使用idea进行maven项目的编译时&#xff0c;控制台输出中文的时候出现乱码的情况。 通常出现这样的问题&#xff0c;都是因为编码格式不一样导致的。既然是maven出的问题&#xff0c;我们在idea中查找下看可以如何设置文件编码。 第一种方式 在pom.xml文件中&#xff…

nginx--系统参数优化telenct

系统参数 在生产环境中&#xff0c;根据自己的需求在/etc/sysctl.conf来更改内核参数 net.ipv4.ip_nonlocal_bind 1 允许非本地IP地址socket监听 net.ipv4.ip_forward 1 开启IPv4转发 net.ipv4.tcp_timestamps 0 是否开启数据包时间戳 net.ipv4.tcp_tw_reuse 0 端⼝口复⽤…

企业外贸邮箱有哪些?国内五大外贸邮箱排行榜

外贸公司在进行跨国业务的时候&#xff0c;需要一个稳定安全的企业邮箱。国内的企业外贸邮箱提供商有很多&#xff0c;目前排行在前五的有Zoho Mail企业邮箱、阿里企业邮箱、网易企业邮箱、腾讯企业邮箱、新浪企业邮箱&#xff0c;今天我们就来详细了解下这些邮箱产品。 一、Z…

【yolov8 项目打包】pyinstaller 打包pyQt5 界面为exe

创建一篇博客文章&#xff0c;介绍如何使用PyInstaller将PyQt5界面打包为exe文件&#xff0c;并且处理与YOLOv8模型相关的文件&#xff0c;可以按照以下结构进行&#xff1a; 标题&#xff1a;使用PyInstaller将PyQt5界面与YOLOv8模型打包为Windows可执行文件 引言 在机器学习…

Unity Material(材质)、Texture(纹理)、Shader(着色器)简介

文章目录 一、概念二、Rendering Mode三、Main Maps三、参考文章 一、概念 Material(材质)&#xff1a;物体的“色彩”、“纹理”、“光滑度”、“透明度”、“反射率”、“折射率”、“发光度”等&#xff0c;材质的本质是shader的实例(载体)Texture(贴图)&#xff1a;附件到…

Python通过定义类实现增删改查(期末考试)

python高级编程期末测试 别看我挣的少&#xff0c;但是我省的多&#xff0c;昨天法拉利又省下两百多万。 一、通过创建自己类来实现增删改查 我们已经利用模型实现单表的增删改查了 现在 我们不想使用模型来操作数据库 我们可以自己定义模型 那么 如何通过自己创建的类实现增…

计算机SCI期刊,IF=9.657,1区TOP,2周内出版!

一、期刊名称 Neural Networks 二、期刊简介概况 期刊类型&#xff1a;SCI 学科领域&#xff1a;计算机科学 影响因子&#xff1a;7.8 中科院分区&#xff1a;1区TOP 出版方式&#xff1a;订阅模式/开放出版 版面费&#xff1a;选择开放出版需支付$3350 三、期刊简介 神…

美国原装二手keysight86122c安捷伦86122C波长计

是德KEYSIGHT 86122C 波长计 主要功能和规格 特征&#xff1a; 增强型&#xff0c;稳定的HeNe参考激光器&#xff0c;使用寿命更长 包括五年保修&#xff0c;涵盖整个仪器&#xff0c;所有零件 绝对波长精度&#xff1a;0.2 ppm 差分波长精度&#xff1a;0.15 ppm 不到0.…

Springboot+vue项目影城管理系统

摘 要 本论文主要论述了如何使用JAVA语言开发一个影城管理系统&#xff0c;本系统将严格按照软件开发流程进行各个阶段的工作&#xff0c;采用B/S架构&#xff0c;面向对象编程思想进行项目开发。在引言中&#xff0c;作者将论述影城管理系统的当前背景以及系统开发的目的&…

正点原子Linux学习笔记(六)在 LCD 上显示 jpeg 图像

在 LCD 上显示 jpeg 图像 20.1 JPEG 简介20.2 libjpeg 简介20.3 libjpeg 移植下载源码包编译源码安装目录下的文件夹介绍移植到开发板 20.4 libjpeg 使用说明错误处理创建解码对象设置数据源读取 jpeg 文件的头信息设置解码处理参数开始解码读取数据结束解码释放/销毁解码对象 …

【动态规划】子数组、子串系列I|最大子数组和|环形子数组的最大和|乘积最大子数组|乘积为正数的最长子数组长度

一、最大子数组和 最大子数组和 算法原理&#xff1a; &#x1f4a1;细节&#xff1a; 1.返回值为dp表每个位置的最大值&#xff0c;而不是只看最后一个位置&#xff0c;因为可能最后一个位置都不选 2.可以直接在填dp表的时候就进行返回值的比较 3.如果初始化选择多开一个位…

2024最新版JavaScript逆向爬虫教程-------基础篇之无限debugger的原理与绕过

目录 一、无限debugger的原理与绕过1.1 案例介绍1.2 实现原理1.3 绕过debugger方法1.3.1 禁用所有断点1.3.2 禁用局部断点1.3.3 替换文件1.3.4 函数置空与hook 二、补充2.1 改写JavaScript文件2.2 浏览器开发者工具中出现的VM开头的JS文件是什么&#xff1f; 一、无限debugger的…

520送男士内裤给男朋友好吗?五大男士内裤测评种草

相信有很多朋友都选在520这个特殊的日子里为心爱的人挑选一份特别的礼物吧&#xff01;如果送礼给男朋友或老公&#xff0c;一份实用的礼物肯定是最佳选择哦&#xff01;很多男性朋友每条内裤都穿很久&#xff0c;如果给男朋友挑选合适的男士内裤&#xff0c;也是一种关心体贴的…