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

驱动层面的调度和同步一向是内核中比较困难的部分,和应用层不一样,内核位于系统进程下,所以它的调度和同步一旦出现纰漏,那会影响所有的程序,而内核并不具备对于这种情况下的纠错能力,没有异常手段能够让挂起的系统恢复原样,除了关闭电源之外,并且这个过程可能会需要进入安全模式来处理,这对于病毒来说可能是一个好消息,但对于要稳定运行的驱动程序来说,就意味着编写难度的上升。

内核定义一组称为内核调度程序对象的对象类型,或仅定义调度程序对象。分发器对象包括计时器对象、事件对象、信号灯对象、互斥对象和线程对象。

驱动程序可以将调度程序对象用作非比特线程上下文中的同步机制,同时在 IRQL 执行时等于PASSIVE_LEVEL。

内核对象对于windows开发工程师来说并不是很稀奇的名称,在应用层编程的时候,事件、信号量、线程这些对象本身就是内核对象,看起来它们的用法和应用层一样,不过,区别在于,某些情况下使用内核对象不当,后果是灾难性的。

分发器的对象状态

每个内核定义的调度程序对象类型都有一个状态,该状态要么设置为 Signaled,要么设置为 Not-Signaled。

如果一个或多个线程调用 KeWaitForSingleObject、KeWaitForMutexObject 或 KeWaitForMultipleObjects,则一组线程可以同步其操作。 这些函数将调度程序对象指针作为输入并等待,直到另一个例程或线程将一个或多个调度程序对象设置为“已信号”状态。

当线程调用 KeWaitForSingleObject 以等待调度程序对象 (或 KeWaitForMutexObject 以获取互斥) 时,线程将进入等待状态,直到调度程序对象设置为Signaled状态。 线程可以调用 KeWaitForMultipleObjects 来等待一组调度程序对象的任意或全部设置为Signaled。

每当调度程序对象设置为“已发出信号”状态时,内核就会更改等待该对象 就绪的任何线程的状态。 (同步计时器和同步事件是此规则的例外情况;当向同步事件或计时器发出信号时,只会将一个等待线程设置为就绪状态。有关详细信息,请参阅 计时器对象和 DPC 和 事件对象。) 处于就绪状态的线程将根据其当前运行时 线程优先级 和具有该优先级的任何线程的处理器的当前可用性来计划运行。

如何等待分发器对象?

通常,仅当以下至少一种情况为 true 时,驱动程序才能等待调度程序对象设置:

  • 驱动程序在非比特线程上下文中执行,可以标识将进入等待状态的线程。 实际上,在非比特线程上下文中执行的唯一驱动程序例程是任何驱动程序的 DriverEntry、 AddDevice、 Reinitialize 和 Unload 例程,以及最高级别驱动程序的调度例程。 所有这些例程都由系统直接调用。
  • 驱动程序正在执行完全同步的 I/O 请求,在处理 I/O 请求时,没有驱动程序会将任何操作排入队列,并且直到其下面的驱动程序处理完请求,否则不会返回任何驱动程序。

此外,如果驱动程序在 IRQL 或高于等于 DISPATCH_LEVEL 执行,则无法进入等待状态。根据这些限制,必须使用以下规则:

  • 任何驱动程序的 DriverEntry、 AddDevice、 Reinitialize 和 Unload 例程都可以等待调度程序对象;
  • 最高级别驱动程序的调度例程可以等待调度程序对象;
  • 如果 I/O操作是同步的,则较低级别驱动程序的调度例程可以等待调度对象,例如创建、刷新、关闭和关闭操作、某些设备 I/O 控制操作以及某些 PnP 和电源操作;
  • 较低级别驱动程序的调度例程不能等待调度程序对象完成异步 I/O 操作;
  • 在 IRQL DISPATCH_LEVEL或更高位置执行的驱动程序例程不得等待调度程序对象设置为“已信号”状态;
  • 驱动程序不得尝试等待调度程序对象设置为信号状态,以便完成与分页设备的传输操作;
  • 为读/写请求提供服务的驱动程序调度例程通常不能等待调度程序对象设置为“已信号”状态;
  • 仅当 I/O 控制代码的传输类型METHOD_BUFFERED时,设备 I/O 控制请求的调度例程才能等待调度程序对象设置为“已信号”状态;
  • SCSI 微型端口驱动程序不应使用内核调度程序对象。 SCSI 微型端口驱动程序应仅调用 SCSI 端口库例程;

所有其他标准驱动程序例程在任意线程上下文中执行:调用驱动程序例程处理排队操作或处理设备中断时,任何线程的线程都恰好是当前线程。 此外,大多数标准驱动程序例程都是在引发的 IRQL 中运行,无论是在 DISPATCH_LEVEL还是DIRQL 。

如有必要,驱动程序可以创建设备专用线程,该线程可以等待驱动程序的其他例程 ,但 ISR 或 SynchCritSection 例程除外, 将调度程序对象设置为信号状态并重置为Not-Signaled状态。

一般指导原则是,如果预计新设备驱动程序在 I/O 操作期间等待设备状态更改时通常需要停止超过 50 微秒,请考虑使用设备专用线程实现驱动程序。 如果设备驱动程序也是最高级别的驱动程序,请考虑使用 系统工作线程 并实现一个或多个工作线程回调例程。 

事件

任何使用事件对象的驱动程序都必须调用 KeInitializeEvent、 IoCreateNotificationEvent 或 IoCreateSynchronizationEvent ,然后才能等待、设置、清除或重置事件。 下图演示了具有线程的驱动程序如何使用事件对象进行同步:

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

当驱动程序调用 KeInitializeEvent 时,它必须传递指向事件对象的驱动程序常驻存储的指针。 此外,调用方必须为事件对象指定初始状态 (已发出信号或未发出信号) 。 调用方还必须指定事件类型,可以是以下任一类型:

  • SynchronizationEvent: 当同步事件设置为“已信号”状态时,等待事件重置为Not-Signaled的单个线程将有资格执行,并且事件的状态会自动重置为“未发出信号”。这种类型的事件有时称为 自动清理事件,因为每次满足等待时,其信号状态都会自动重置。
  • NotificationEvent:当通知事件设置为“已信号”状态时,等待事件重置为Not-Signaled的所有线程都将符合执行条件,并且事件将保持为“已信号”状态,直到发生显式重置Not-Signaled:也就是说,使用给定的事件指针调用 KeClearEvent 或 KeResetEvent。

很少有设备或中间驱动程序具有单个驱动程序专用线程,更不用说一组线程,这些线程可能会通过等待保护共享资源的事件来同步其操作。

大多数使用事件对象等待 I/O操作完成的驱动程序在调用 KeInitializeEvent 时将输入类型设置为 NotificationEvent。 为驱动程序使用 IoBuildSynchronousFsdRequest 或 IoBuildDeviceIoControlRequest 创建的 IRP 设置的事件对象几乎总是初始化为 NotificationEvent, 因为调用方将等待事件的通知,指示其请求已被一个或多个较低级别的驱动程序满足。

驱动程序初始化自身后,其驱动程序专用线程(如果有)和其他例程可以同步其在事件上的操作。 例如,具有管理 IRP 排队的线程的驱动程序(例如系统软盘控制器驱动程序)可能会同步事件上的 IRP 处理,如上图所示:

  • 1. 线程已取消排队以在设备上处理 IRP,它使用指向初始化事件对象的驱动程序提供的存储的指针调用 KeWaitForSingleObject ;
  • 2. 其他驱动程序例程执行满足 IRP 所需的 I/O 操作,当这些操作完成时,驱动程序的 DpcForIsr 例程使用指向事件对象的指针调用 KeSetEvent ,驱动程序确定的线程优先级提升 (增量,如上图) 所示,布尔 等待 设置为 FALSE。 调用 KeSetEvent 会将事件对象设置为“已信号”状态,从而将等待线程的状态更改为“就绪”;
  • 3. 当处理器可用时,内核会立即调度线程以执行:也就是说,当前没有其他具有更高优先级的线程处于就绪状态,并且没有内核模式例程可在更高的IRQL上运行。如果DpcForIsr尚未使用 IRP 调用 IoCompleteRequest ,线程现在可以完成 IRP,并且可以取消排队以在设备上处理的另一个 IRP;

调用将 Wait 参数设置为 TRUE 的 KeSetEvent 表示调用方打算在从 KeSetEvent 返回时立即调用 KeWaitForSingleObject 或 KeWaitForMultipleObjects 支持例程。

请考虑以下有关将Wait参数设置为KeSetEvent 的准则:

  • 在 IRQL < DISPATCH_LEVEL运行的可分页线程或可分页驱动程序例程不应调用将 Wait 参数设置为 TRUE 的 KeSetEvent。 如果调用方碰巧在调用 KeSetEvent 和 KeWaitForSingleObject 或KeWaitForMultipleObjects 之间分页,则此类调用会导致严重页面错误;
  • 在 IRQL = DISPATCH_LEVEL 下运行的任何标准驱动程序例程都不能等待任何调度程序对象的非零间隔,而不会关闭系统。 但是,此类例程可以在 IRQL 小于或等于 DISPATCH_LEVEL 运行时调用 KeSetEvent ;
  • KeResetEvent 返回给定 事件的先前状态:调用 KeResetEvent 时,它是否设置为 Signaled。 KeClearEvent 只是将给定 事件 的状态设置为“未发出信号”;

对于何时调用上述支持例程,请考虑以下准则:

为了提高性能,每个驱动程序都应调用 KeClearEvent ,除非调用方需要 KeResetEvent 返回的信息来确定接下来要执行的操作。

标准事件

系统提供多个标准事件对象。 驱动程序可以使用这些事件对象,每当出现某些情况时,系统就会收到通知。 以下列出了系统包含标准事件对象:

\KernelObjects\HighMemoryCondition:每当可用物理内存量超过系统定义的量时,将设置此事件。 驱动程序可以等待将此事件设置为主动分配内存的信号。

\KernelObjects\LowMemoryCondition:每当可用物理内存量低于系统定义的量时,将设置此事件。 已分配大量内存的驱动程序可以等待将此事件设置为释放未使用的内存的信号。

对于 Microsoft Windows Server 2003 及更高版本的 Windows,驱动程序还可以使用以下其他标准事件对象:

\KernelObjects\HighPagedPoolCondition:每当可用分页池的数量超过系统定义的量时,将设置此事件。 驱动程序可以等待将此事件设置为主动从分页池分配内存的信号。

\KernelObjects\LowPagedPoolCondition:每当可用分页池的数量低于系统定义的量时,将设置此事件。 已分配大量内存的驱动程序可以等待将此事件设置为从分页池中释放未使用的内存的信号。

\KernelObjects\HighNonPagedPoolCondition:每当可用非分页池的数量超过系统定义的量时,将设置此事件。 驱动程序可以等待将此事件设置为主动分配非分页池内存的信号。

\KernelObjects\LowNonPagedPoolCondition:每当可用非分页池的数量低于系统定义的量时,将设置此事件。 已分配大量内存的驱动程序可以等待将此事件设置为从非分页池中释放未使用的内存的信号。

对于 Windows Vista 和更高版本的 Windows,驱动程序还可以使用以下其他标准事件对象:

\KernelObjects\LowCommitCondition:当操作系统的 提交费用 相对于 当前提交限制较低时,将设置此事件。 换句话说,内存使用率较低,物理内存或分页文件中有大量可用空间。

\KernelObjects\HighCommitCondition:当操作系统的提交费用相对于当前提交限制较高时,将设置此事件。 换句话说,内存使用率较高,物理内存或分页文件中的可用空间非常少,但操作系统可能能够增加其分页文件的大小。

\KernelObjects\MaximumCommitCondition:当操作系统的提交费用接近 最大提交限制时,将设置此事件。 换句话说,内存使用率非常高,物理内存或分页文件中的可用空间非常少,操作系统无法增加其分页文件的大小。 如果存在足够的存储资源,系统管理员始终可以增加分页文件的大小或数量,而无需重新启动计算机。

其中每个事件都是通知事件。 只要触发条件保持为 true,它们就会保持设置。

若要打开其中任何事件的句柄,请使用 IoCreateNotificationEvent 例程。 等待其中任何事件的驱动程序应创建一个专用线程来执行等待。 线程可以通过调用 KeWaitForSingleObject 或 KeWaitForMultipleObjects 来等待其中一个或多个事件。

 

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

深究muduo网络库的Buffer类!!!

最近在学习了muduo库的Buffer类&#xff0c;因为这个编程思想&#xff0c;今后在各个需要缓冲区的项目编程中都可以用到&#xff0c;所以今天来总结一下&#xff01; Buffer的数据结构 muduo的Buffer的定义如下&#xff0c;其内部是 一个 std::vector&#xff0c;且还存在两个…

kubectl_进阶_安全

安全 在前面的学习中&#xff0c;我们知道对于资源对象的操作都是通过 APIServer 进行的&#xff0c;那么集群是怎样知道我们的请求就是合法的请求呢&#xff1f; 这就涉及到k8s的安全相关的知识了。 1. API对象 Kubernetes有一个很基本的特性就是它的所有资源对象都是模型…

bitset(位图)

文章目录 位图的引入位图的概念位图的模拟实现 位图的引入 我们用一道面试题来引入位图 给40亿个不重复的无符号整数&#xff0c;没排过序。给一个无符号整数&#xff0c;如何快速判断一个数是否在 这40亿个数中。【腾讯】 我们会想到一下几种方法&#xff1a; 遍历一遍&#…

【LAMMPS学习】八、基础知识(5.7)Drude感应偶极子

8. 基础知识 此部分描述了如何使用 LAMMPS 为用户和开发人员执行各种任务。术语表页面还列出了 MD 术语&#xff0c;以及相应 LAMMPS 手册页的链接。 LAMMPS 源代码分发的 examples 目录中包含的示例输入脚本以及示例脚本页面上突出显示的示例输入脚本还展示了如何设置和运行各…

42.WEB渗透测试-信息收集-域名、指纹收集(4)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;41.WEB渗透测试-信息收集-域名、指纹收集&#xff08;3&#xff09; 关于单域名收集内容…

智能网联汽车网络和数据安全态势分析

文章目录 前言一、我国智能网联汽车安全态势分析(一)我国高度重视智能网联汽车安全发展(二)产业高速发展伴随网络安全隐患(三)网络和数据安全风险事件威胁加剧二、智能网联汽车网络和数据安全典型实践剖析(一)立标准规范,把牢安全发展“方向盘”(二)强车主服务,系好…

【计算机科学速成课】笔记二

笔记一 文章目录 7.CPU阶段一&#xff1a;取指令阶段阶段二&#xff1a;解码阶段阶段三&#xff1a;执行阶段 8.指令和程序9.高级CPU设计——流水线与缓存 7.CPU CPU也叫中央处理器&#xff0c;下面我们要用ALU&#xff08;输入二进制&#xff0c;会执行计算&#xff09;、两种…

88、动态规划-乘积最大子数组

思路&#xff1a; 首先使用递归来解&#xff0c;从0开始到N&#xff0c;每次都从index开始到N的求出最大值。然后再次递归index1到N的最大值&#xff0c;再求max。代码如下&#xff1a; // 方法一&#xff1a;使用递归方式找出最大乘积public static int maxProduct(int[] num…

网络基础「HTTPS」

✨个人主页&#xff1a; 北 海 &#x1f389;所属专栏&#xff1a; Linux学习之旅 &#x1f383;操作环境&#xff1a; CentOS 7.6 腾讯云远程服务器 文章目录 1.基本概念1.1.HTTP协议面临的问题1.2.加密与解密1.3.数字摘要1.4.数字签名 2.解决方案2.1.「对称式加密」2.2.「非对…

江湖有法受邀参加第四届中国创始人IP生态大会

四月的杭城春意盎然、微风轻拂,到处洋溢着一派欣欣向荣、百花争艳的美好景象。2024 年 4 月 27 日下午 1:30,备受瞩目的第四届中国创始人 IP 生态大会在杭州华礼宴国际礼宴中心盛大开幕。本次大会由“大咖会”主办,以“打造一个圈层,影响一座城”为主题,吸引了众多行业大咖齐聚…

AI+新零售的行业落地应用

一、新零售行业变迁 传统零售线上线下数据未打通&#xff0c;新零售实现用户数据全打通。新零售&#xff08;如盒马鲜生&#xff09;&#xff0c;用户进入盒马鲜生后&#xff0c;连接店内wifi后&#xff0c;即可获取用户mac地址&#xff0c;wifi探针可以获取用户诸多数据&#…

【stm32-2】按键控制LED光敏传感器控制蜂鸣器

1.按键控制LED uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); //读取输入数据寄存器某一个端口的输入值 uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx); //读取整个输入数据寄存器 uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDe…

【Linux】进程间通信 - 管道

文章目录 1. 进程间通信介绍1.1 进程间通信目的1.2 进程间通信发展1.3 进程间通信分类 2. 管道2.1 什么是管道2.2 匿名管道2.3 用 fork 来共享管道原理2.4 站在文件描述符角度 - 深入理解管道2.5 站在内核角度 - 管道本质2.6 管道读写规则2.7 管道特点 3. 命名管道3.1 匿名管道…

2024全域数字化转型评估模型研究报告

来源&#xff1a;伏羲智库&腾讯智慧零售 智慧零售逐渐成为发展趋势 随着技术突破、商业创新和监管制度的发展演进,零售业数字化转型的内涵随实践延展而不断丰富,智慧零售逐渐成为零售业数字化转型的新趋势。 在技术层面,零售业数字化转型呈现出三大变化与趋势: 一是数字技…

【吃透Java手写】- Spring(上)-启动-扫描-依赖注入-初始化-后置处理器

【吃透Java手写】Spring&#xff08;上&#xff09;启动-扫描-依赖注入-初始化-后置处理器 1 准备工作1.1 创建自己的Spring容器类1.2 创建自己的配置类 ComponentScan1.3 ComponentScan1.3.1 Retention1.3.2 Target 1.4 用户类UserService Component1.5 Component1.6 测试类 2…

未来人类文明的可持续发展

未来人类文明若要实现永远延续,建立一个演化模型确实是一个有远见的想法。演化模型可以帮助我们预测和规划未来,从而更好地应对可能出现的挑战。以下是对这个想法的展开论述: 建立演化模型:首先,我们需要收集当前节点的人类文明数据,包括科技、经济、政治、文化、环境等方…

【手撸RPC框架】netty入门

&#x1f43c;作者简介&#xff1a;一名大三在校生&#x1f38b; 空有想法&#xff0c;没有实践&#xff0c;难成大事 专栏前言&#xff1a;探索RPC框架的奥秘 简介&#xff1a;在现代软件开发中&#xff0c;随着微服务架构的普及&#xff0c;远程过程调用&#xff08;RPC&…

配置网关,解决本地连接不上Linux虚拟机的问题

在Window环境下&#xff0c;使用远程终端工具连接不了VMware搭建的Linux虚拟机&#xff08;CentOS 7&#xff09;&#xff0c;并且在命令行ping不通该Linux虚拟机的IP地址。下面通过配置网关解决本地与Linux虚拟机连接问题&#xff1a; 1 查看虚拟机网关地址 在VMware虚拟机上…

Cocos2d,一个能实现梦想的 Python 库

大家好&#xff01;我是爱摸鱼的小鸿&#xff0c;关注我&#xff0c;收看每期的编程干货。 一个简单的库&#xff0c;也许能够开启我们的智慧之门&#xff0c; 一个普通的方法&#xff0c;也许能在危急时刻挽救我们于水深火热&#xff0c; 一个新颖的思维方式&#xff0c;也许能…