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.mzph.cn/diannao/6697.shtml

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

相关文章

植物生态化学计量主要理论和假说

1 功能关联假说 描述化学计量特征与植物生长功能的关联, 主要包括: (1) 生长速率假说(Growth Rate Hypothesis) (Sterner & Elser, 2002): 随生长速率增加, 植物N:P和C:P呈降低趋势, 而P 含量呈增加趋势。该假说有助于理解植物生长速率的调控机制, 但受其他因素调控…

EPAI手绘建模APP动画编辑器、信息、工程图

④ 动画&#xff1a;打开关闭动画编辑器。APP中动画包含两个部分&#xff0c;动画编辑器和动画控制器。动画编辑器用来编辑动画。具体来说&#xff0c;选中一个模型后&#xff0c;给模型添加移动、旋转、缩放三种关键帧&#xff0c;不同的模型添加不同的关键帧&#xff0c;实现…

40.乐理基础-拍号-什么是一拍

拍&#xff1a; 首先 以Y分音符的时长为一拍 这一句话&#xff0c;然后拍是音乐中的时长单位&#xff0c;但这个时长单位有点特殊&#xff0c;它并不是完全绝对的某一个时间&#xff0c;而正是因为如此&#xff0c;所以不能用 秒 之类的&#xff0c;已经很确定很绝对的时间单位…

matlab例题大全

1.第1章 MATLAB系统环境 1.1 注&#xff1a;plot函数为画图函数。例plot&#xff08;x1,y1,:,x2,y2,*&#xff09;; 1.2 注&#xff1a;root为求根函数。p为方程变量前面系数矩阵。 1.3 注&#xff1a; 2*x3y-1*z 2; 8*x2*y3*z 4; 45*x3*y9*z 23 求&#xff1a;x,y,z的…

关于位操作符的实际应用<C语言>

前言 位操作符在C语言初学阶段相对其他操作符来说&#xff0c;是一种难度比较大的操作符&#xff0c;且运用较少的一类操作符&#xff0c;但是位操作符并不是“一无是处”&#xff0c;合理运用的位操作符&#xff0c;在某些场景下可以优化算法&#xff0c;提高代码的执行效率&a…

PyQt5:Qt Designer使用重载的自定义类提升控件

1&#xff0c;以QPushButton举例 2&#xff0c;右击需要提升的控件&#xff0c;选择【提升为...】 3&#xff0c;添加自定义类&#xff0c;不用管 .h 的后缀&#xff0c;不影响使用。 4&#xff0c;完成 5&#xff0c;说明&#xff1a;自定义类的&#xff1a;__init__()方法…

基于STC12C5A60S2系列1T 8051单片机的IIC通信的0.96寸4针OLED12864显示16行点x16列点字模的功能

基于STC12C5A60S2系列1T 8051单片机的IIC通信的0.96寸4针OLED12864显示16行点x16列点字模的功能 STC12C5A60S2系列1T 8051单片机管脚图STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式及配置STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式介绍液晶显示器OLED12864简…

抖音直播间小风车怎么挂?直播间小风车跳转微信怎么开通!

抖音直播已经成为了一个非常受欢迎的直播平台&#xff0c;而在直播间引流也是用户非常关注的一个话题。而针对这个问题&#xff0c;抖音也提供了一种非常好用的小工具——小风车&#xff0c;可以帮助用户在直播间进行引流。那么&#xff0c;抖音直播间小风车怎么挂&#xff1f;…

记录几种排序算法

十种常见排序算法可以分类两大类别&#xff1a;比较类排序和非比较类排序。 常见的快速排序、归并排序、堆排序以及冒泡排序等都属于比较类排序算法。比较类排序是通过比较来决定元素间的相对次序&#xff0c;其时间复杂度不能突破 O(nlogn)。在冒泡排序之类的排序中&…

扩展学习|本体研究进展

文献来源&#xff1a; 王向前,张宝隆,李慧宗.本体研究综述[J].情报杂志,2016,35(06):163-170. 一、本体的定义 本体概念被引入人工智能、知识工程等领域后被赋予了新的含义。然而不同的专家学者对本体的理解不同,所给出的定义也有所差异。 人工智能领域的学者Neches(1991)等人对…

Docker Compose 部署若依前后端分离版

准备一台服务器 本次使用虚拟机&#xff0c;虚拟机系统 Ubuntu20.04&#xff0c;内存 4G&#xff0c;4核。 确保虚拟机能连接互联网。 Ubuntu20.04 安装 Docker 添加 Docker 的官方 GPG key&#xff1a; sudo apt-get update sudo apt-get install ca-certificates curl su…

初始面相对象

初始面向对象 类和对象的关系 类&#xff1a;对对象向上抽取出像的部分、公共的部分以此形成类&#xff0c;类就相当于一个模版。 对象&#xff1a;在某个模版下的具体的产物可以理解为对象&#xff0c;对象就是一个一个具体的实例&#xff0c;就相当于这个模版下具体的产品&…

RabbitMQ之生产批量发送

为什么要用生产批量发送&#xff1f; 批量发送消息&#xff0c;可以提高MQ发送性能。但是 RabbitMQ 并没有提供了批量发送消息的 API 接口,使用 spring-amqp 的 BatchingRabbitTemplate 实现批量能力。 SimpleBatchingStrategy 发送策略满足以下规则会进行发送&#xff1a; ba…

梅大(龙)高速周边地形

最近广东高速的事故很受关注&#xff0c;我下载了这个高速的地形数据。查看了一下高速周围的地形情况。确实地形很险要&#xff0c;开车还是不要太快&#xff01;尤其南方的路基不稳&#xff01;这样险要的地形很危险&#xff01; 高速周围的地形情况 梅大&#xff08;龙&…

eNSP-动态路由(ospf协议)

一、拓扑结构搭建 二、主机配置 pc1 pc2 三、路由器配置 1.AR2配置 <Huawei>sys #进入系统视图 [Huawei]int g0/0/0 #进入接口 [Huawei-GigabitEthernet0/0/0]ip address 192.168.0.2 24 #设置ip地址 [Huawei-GigabitEthernet0/0/0]q #返回上一级 [Huawei]int g0/0/1 …

关于 Vue.js 双向数据绑定基本实现认知

写在前面 很早的一篇博客&#xff0c;整理了部分&#xff0c;蹭假期整理完博文内容涉及:双向数据绑定 实现方式简单介绍基于发布订阅、数据劫持的双向数据绑定两种不同实现(ES5/ES6) Demo&#xff0c;以及代码简单分析Object.defineProperty && Proxy API 介绍以及特性…

Libcity笔记:原子文件

1 介绍 Libcity中的数据以原子文件的形式存在 2 原子文件类别 对于不同的交通预测任务&#xff0c;可能用到不同的原子文件&#xff0c;同一个数据集不一定包含全部六种原子文件 网格数据需要按照先行后列的顺序遍历OD数据需要按照先起点后终点的顺序遍历 2.1 geo 存储地理…

opengauss概述-基础知识篇-备考华为高斯

目录 &#x1f9e8;考前准备: &#x1f3a1;数据库操作语言 ✨OLTP和OLAP &#x1f3af;常用函数 &#x1f9f2;字符处理函数 关于 left 和 right 特别重点的字符串函数 &#x1f9f2;数字操作函数 关于 ceil 和 floor &#x1f9f2;时间和日期处理函数 &#x1f9f…

专项技能训练五《云计算网络技术与应用》实训7-1:安装mininet

文章目录 mininet安装1. 按6-1教程安装opendaylight控制器。2. 按6-2教程安装RYU控制器。3. 按5-1教程安装openvswitch虚拟交换机并开启服务。4. 将老师所给mininet安装包试用winSCP传送至电脑端。5. 安装net-tools。6. 安装mininet7. 安装完成后&#xff0c;使用命令建立拓扑&…

【网络安全产品】---应用防火墙(WAF)

what Web应用防火墙&#xff08;Web Application Firewall) WAF可对网站或者App的业务流量进行恶意特征识别及防护&#xff0c;在对流量清洗和过滤后&#xff0c;将正常、安全的流量返回给服务器&#xff0c;避免网站服务器被恶意入侵导致性能异常等问题&#xff0c;从而保障…