WDF驱动开发-同步技术

news2025/6/17 12:12:56
使用自动同步

基于框架的驱动程序中几乎所有的代码都驻留在事件回调函数中。 框架会自动同步驱动程序的大部分回调函数,如下所示:

  • 框架始终将 常规设备对象、 功能设备对象 (FDO) 和 物理设备对象 (PDO) 事件回调函数同步,以便每个设备一次只能调用 除 EvtDeviceSurpriseRemoval、 EvtDeviceQueryRemove 和 EvtDeviceQueryStop以外的一个回调 函数。 这些回调函数支持即插即用 PnP和电源管理事件,并在 IRQL = PASSIVE_LEVEL 调用;
  • (可选)框架可以同步处理驱动程序 I/O 请求的回调函数的执行,以便这些回调函数一次运行一个。 具体而言,框架可以同步 队列、 中断、 延迟过程调用 (DPC) 、 计时器、 工作项和 文件 对象的回调函数,以及请求对象的 EvtRequestCancel 回调函数。 框架在 IRQL = DISPATCH_LEVEL 调用其中大多数回调函数,但你可以强制队列和文件对象回调函数在 IRQL = PASSIVE_LEVEL 运行。 工作项回调函数始终在 PASSIVE_LEVEL运行;

框架使用一组内部同步锁实现此自动同步。 框架确保两个或多个线程不能同时调用同一回调函数,因为每个线程必须等到可以获取同步锁后再调用回调函数。

驱动程序应将特定于对象的数据存储在 对象上下文空间中。 如果驱动程序仅使用框架定义的接口,则只有接收对象句柄的回调函数才能访问此数据。 如果框架正在同步对驱动程序回调函数的调用,则一次只会调用一个回调函数,并且一次只能访问一个回调函数的对象的上下文空间。

除非驱动程序实现 被动级中断处理,否则服务中断和访问中断数据的代码必须在设备的 IRQL (DIRQL) 上运行,并且需要额外的同步。 

如果驱动程序启用处理 I/O 请求的回调函数的自动同步,框架将同步这些回调函数,以便一次运行一个回调函数。 下表列出了框架同步的回调函数。

(可选)框架还可以将这些回调函数与驱动程序为设备提供的任何中断、DPC、工作项和计时器对象回调函数同步, 不包括中断对象的 EvtInterruptIsr 回调函数。 若要启用此附加同步,驱动程序必须将这些对象的配置结构的 AutomaticSerialization 成员设置为 TRUE。

总之,框架的自动同步功能提供以下功能:

  • 框架始终同步每个设备的 PnP 和电源管理回调函数;
  • (可选)框架可以同步 I/O 队列的请求处理程序和一些附加回调函数 (查看上表) ;
  • 驱动程序可以要求框架同步中断、DPC、工作项和计时器对象的回调函数;
  • 驱动程序必须使用同步中断代码中所述的技术来同步服务中断和访问 中断数据的代码;
  • 框架不会同步驱动程序的其他回调函数,例如驱动程序的 CompletionRoutine 回调函数或 I/O 目标对象定义的回调函数。 相反,框架提供了驱动程序可用于同步这些回调函数的其他 锁 ;
选择同步范围

可以选择让框架同步与设备的所有 I/O 队列关联的所有回调函数。 或者,可以选择让框架单独同步每个设备的 I/O 队列的回调函数。 驱动程序可用的同步选项如下所示:

  • 设备级同步:框架为设备的所有 I/O 队列同步上表包含的回调函数,以便它们一次运行一个。 框架通过在调用回调函数之前获取设备的同步锁来实现此同步;
  • 队列级同步:框架为每个单独的 I/O 队列同步上表包含的回调函数,以便它们一次运行一个。 框架通过在调用回调函数之前获取队列的同步锁来实现此同步;
  • 无同步

框架不会同步上表包含的回调函数的执行,并且不会在调用回调函数之前获取同步锁。 如果需要同步,驱动程序必须提供同步。

若要指定是希望框架为驱动程序提供设备级同步、队列级同步还是不同步,可以为驱动程序对象、设备对象或队列对象指定 同步范围 。 对象的WDF_OBJECT_ATTRIBUTES结构的 SynchronizationScope 成员标识对象的同步范围。 驱动程序可以指定的同步范围值包括:

  • WdfSynchronizationScopeDevice框架通过获取设备对象的同步锁进行同步;
  • WdfSynchronizationScopeQueue框架通过获取队列对象的同步锁进行同步;
  • WdfSynchronizationScopeNone框架不会同步,也不会获取同步锁;
  • WdfSynchronizationScopeInheritFromParent框架从对象的父对象获取对象的 SynchronizationScope 值;

通常,不建议使用设备级同步。

驱动程序对象的默认同步作用域为 WdfSynchronizationScopeNone。 设备和队列对象的默认同步作用域为 WdfSynchronizationScopeInheritFromParent。

如果希望框架为所有设备提供设备级同步,可以使用以下步骤:

在驱动程序的驱动程序对象的WDF_OBJECT_ATTRIBUTES结构中,将 SynchronizationScope 设置为 WdfSynchronizationScopeDevice。

为每个设备对象使用默认的 WdfSynchronizationScopeInheritFromParent 值。

或者,若要为单个设备提供设备级同步,可以使用以下步骤:

1. 对驱动程序对象使用默认的 WdfSynchronizationScopeNone 值。

2. 在单个设备对象的WDF_OBJECT_ATTRIBUTES结构中,将 SynchronizationScope 设置为 WdfSynchronizationScopeDevice。

如果希望框架为设备提供队列级同步,可以使用以下技术:

1. 对于框架版本 1.9 及更高版本,应通过在队列对象的WDF_OBJECT_ATTRIBUTES结构中设置 WdfSynchronizationScopeQueue,为单个队列启用队列级同步。 这是首选技术。

2. 或者,可以在所有框架版本中使用以下步骤:

  • 在设备对象的WDF_OBJECT_ATTRIBUTES结构中,将 SynchronizationScope 设置为 WdfSynchronizationScopeQueue;
  • 为每个设备的队列对象使用默认的 WdfSynchronizationScopeInheritFromParent 值;

如果不希望框架同步处理驱动程序 I/O 请求的回调函数,请使用驱动程序、设备和队列对象的默认 SynchronizationScope 值。 在这种情况下,框架不会自动同步驱动程序的 I/O 请求相关的回调函数,并且可以在 IRQL <= DISPATCH_LEVEL调用回调函数。

请注意,设置 SynchronizationScope 值只会同步上一个表包含的回调函数。 如果希望框架同时同步驱动程序的中断、DPC、工作项和计时器对象回调函数,驱动程序必须将这些对象的配置结构的 AutomaticSerialization 成员设置为 TRUE。

但是,仅当要同步的所有回调函数都在同一 IRQL 上运行时,才能将 AutomaticSerialization 设置为 TRUE 。 选择 执行级别可能会导致不兼容的 IRQL 级别。 在这种情况下,驱动程序必须使用 框架锁 ,而不是设置 AutomaticSerialization。 

如果将 AutomaticSerialization 设置为 TRUE,则应选择队列级同步。

选择执行级别

当驱动程序创建某些类型的框架对象时,它可以指定对象的 执行级别 。 执行级别指定 IRQL,框架将在其中调用对象的事件回调函数,用于处理驱动程序的 I/O 请求。

如果驱动程序提供执行级别,则提供的级别会影响队列和文件对象的回调函数。 通常,如果驱动程序使用自动同步,框架会在 IRQL = DISPATCH_LEVEL调用这些回调函数。 通过指定执行级别,驱动程序可以强制框架在 IRQL = PASSIVE_LEVEL 调用这些回调函数。 在设置调用队列和文件对象回调函数的 IRQL 时,框架使用以下规则:

  • 如果驱动程序使用自动同步,则其队列和文件对象回调函数在 IRQL = DISPATCH_LEVEL调用,除非驱动程序要求框架在 IRQL = PASSIVE_LEVEL 调用其回调函数;
  • 如果驱动程序未使用自动同步并且未指定执行级别,则可以在 IRQL <= DISPATCH_LEVEL调用驱动程序的队列和文件对象回调函数;

请注意,如果驱动程序提供文件对象回调函数,则很可能希望框架在 IRQL = PASSIVE_LEVEL 调用这些回调函数,因为某些文件数据(如文件名)可分页。

若要提供执行级别,驱动程序必须为对象的WDF_OBJECT_ATTRIBUTES结构的 ExecutionLevel 成员指定值。 驱动程序可以指定的执行级别值包括:

  • WdfExecutionLevelPassive:框架在 IRQL = PASSIVE_LEVEL 调用对象的回调函数;
  • WdfExecutionLevelDispatch:框架可以在 IRQL <= DISPATCH_LEVEL 调用对象的回调函数。 如果驱动程序使用自动同步,框架始终在 IRQL = DISPATCH_LEVEL调用回调函数;
  • WdfExecutionLevelInheritFromParent:框架从对象的父级获取对象的 ExecutionLevel 值;

驱动程序对象的默认执行级别为 WdfExecutionLevelDispatch。 所有其他对象的默认执行级别为 WdfExecutionLevelInheritFromParent。

下表显示了框架可以调用队列对象和文件对象的驱动程序回调函数的 IRQL 级别。

可以将驱动程序、设备、文件、队列、计时器和常规对象的执行级别设置为 WdfExecutionLevelPassive 或 WdfExecutionLevelDispatch 。 对于其他对象,仅允许 WdfExecutionLevelInheritFromParent 。

在以下的情况下,应指定 WdfExecutionLevelPassive :

  • 驱动程序的回调函数必须调用框架方法或 Windows 驱动程序模型 (WDM) 例程,这些例程只能在 IRQL = PASSIVE_LEVEL 调用;
  • 驱动程序的回调函数必须访问可分页代码或数据。 例如,文件对象回调函数通常访问可分页的 data;

驱动程序可以设置 WdfExecutionLevelDispatch,并提供回调函数,如果它必须在 IRQL = PASSIVE_LEVEL 处理某些操作,则创建工作项,而不是设置 WdfExecutionLevelPassive。

在决定驱动程序是否应将对象的执行级别设置为 WdfExecutionLevelPassive 之前,应确定调用驱动程序和驱动程序堆栈中其他驱动程序的 IRQL。 请考虑以下情况:

  • 如果驱动程序位于内核模式驱动程序堆栈的顶部,则系统通常会在 IRQL = PASSIVE_LEVEL 调用驱动程序。 此类驱动程序的客户端可能是基于 UMDF 的驱动程序或用户模式应用程序。 指定 WdfExecutionLevelPassive 不会对驱动程序的性能产生负面影响,因为框架不必将驱动程序对 IRQL = PASSIVE_LEVEL 调用的工作项的调用排队;
  • 如果驱动程序不在堆栈顶部,系统可能不会在 IRQL = PASSIVE_LEVEL 调用驱动程序。 因此,框架必须将驱动程序对工作项的调用排队,这些工作项稍后在 IRQL = PASSIVE_LEVEL调用。 与允许在 IRQL <= DISPATCH_LEVEL 调用驱动程序的回调函数相比,此过程可能会导致驱动程序性能不佳;

对于 DPC 对象以及不表示被动级别计时器的计时器对象,请注意,如果将父设备的执行级别设置为 WdfExecutionLevelPassive,则无法将配置结构的 AutomaticSerialization 成员设置为 TRUE。 这是因为框架将在 IRQL = PASSIVE_LEVEL 获取设备对象的 回调同步锁 ,因此锁不能用于同步 DPC 或计时器对象回调函数,这些函数必须在 IRQL = DISPATCH_LEVEL执行。 在这种情况下,驱动程序应在必须彼此同步的任何设备、DPC 或计时器对象回调函数中使用 框架旋转锁 。

另请注意,对于表示被动级别计时器的计时器对象,仅当父设备的执行级别设置为 WdfExecutionLevelPassive 时,才能将配置结构的 AutomaticSerialization 成员设置为 TRUE。

使用框架锁

有时,驱动程序必须提供与 I/O 请求相关的回调函数的特定于驱动程序的同步,或者作为框架提供的同步的替代。 驱动程序可以使用回调同步锁、旋转锁、等待锁和中断锁来同步驱动程序代码。

回调同步锁

如果已将驱动程序设置为使用框架的 自动同步 功能,则框架在调用驱动程序的 I/O 请求相关事件回调函数之前获取同步锁。

驱动程序也可以获取与框架设备对象和队列对象关联的 这些回调同步锁。 若要获取同步锁,驱动程序会调用 WdfObjectAcquireLock。 若要释放锁,驱动程序会调用 WdfObjectReleaseLock。

如果驱动程序使用框架的设备级或队列级 I/O 请求相关回调函数同步,但必须将在 IRQL = PASSIVE_LEVEL 上运行的某些代码与在 IRQL = DISPATCH_LEVEL 运行的回调函数同步,则你可能希望驱动程序使用回调同步锁。 这是因为驱动程序只能对在同一 IRQL 处执行的回调函数使用自动同步。

例如,仅当工作项对象的父对象的执行级别为 WdfExecutionLevelPassive (时,驱动程序才能对工作项对象使用自动同步,因为工作项的回调函数始终在 IRQL= PASSIVE_LEVEL) 执行。 因此,如果驱动程序在设备对象的 WDF_OBJECT_ATTRIBUTES 结构的 ExecutionLevel 成员中指定 WdfExecutionLevelDispatch,则驱动程序无法设置子工作项对象的配置结构的 AutomaticSerialization 成员。 相反,驱动程序必须获取回调同步锁才能将 EvtWorkItem 回调函数与父设备对象的回调函数同步。

框架等待锁

使用框架等待锁从 IRQL = PASSIVE_LEVEL 运行的代码同步对驱动程序数据的访问。 在驱动程序可以使用框架等待锁之前,它必须调用 WdfWaitLockCreate 来创建等待锁对象。 然后,驱动程序可以调用 WdfWaitLockAcquire 来获取锁,并 调用 WdfWaitLockRelease 来释放它。

框架旋转锁

使用框架旋转锁从 IRQL <= DISPATCH_LEVEL 运行的代码同步对驱动程序数据的访问。 当驱动程序线程获取旋转锁时,系统会将线程的 IRQL 设置为DISPATCH_LEVEL。 当线程释放锁时,系统会将线程的 IRQL 还原到其以前的级别。

如果未使用自动框架同步的驱动程序,则如果上下文空间可写且驱动程序的事件回调函数不止一个访问空间,则可以使用旋转锁来同步对设备对象的上下文空间的访问。

在驱动程序可以使用框架旋转锁之前,它必须调用 WdfSpinLockCreate 来创建旋转锁对象。 然后,驱动程序可以调用 WdfSpinLockAcquire 来获取锁,并 调用 WdfSpinLockRelease 来释放它。

框架中断锁

对于支持 DIRQL 中断处理的中断对象,框架中断锁是旋转锁。 在驱动程序获取中断旋转锁后,驱动程序会在设备的 DIRQL 处执行,直到它释放该锁。 有

对于支持被动级别处理的中断对象,框架中断锁是等待锁。 驱动程序获取中断等待锁后,驱动程序会在 IRQL = PASSIVE_LEVEL处执行,直到释放该锁。 有

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

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

相关文章

内网安全【2】-域防火墙

1.判断什么时候用代理 2.判断什么时候用隧道 3.判断出网和不出网协议 4.如何使用代理建立节点并连接 5.如何使用隧道技术封装协议上线 6.判断哪些代理或隧道情况选择放弃 代理技术&#xff1a;解决网络通讯不通的问题(利用跳板机建立节点后续操作)&#xff08;网络设置导…

【SpringBoot】深入分析 SpringApplication 源码:彻底理解 SpringBoot 启动流程

在黄昏的余晖里&#xff0c;梦境渐浓&#xff0c;如烟如雾。心随星辰&#xff0c;徜徉远方&#xff0c;岁月静好&#xff0c;愿如此刻般绵长。 文章目录 前言一、SpringBoot 应用二、SpringApplication2.1 SpringApplication 中的属性2.2 SpringApplication 的构造器2.3 Sprin…

高压消防接力泵的工作原理_鼎跃安全

森林消防工作是一项艰巨的任务&#xff0c;森林火灾具有蔓延快、控制难和燃烧剧烈等特点&#xff1b;同时&#xff0c;森林具有复杂的峡谷、山坡和陡峭等复杂情况&#xff0c;传统的消防设备难以深入火场&#xff0c;高压消防接力泵通过便携灵活性&#xff0c;深入火场助力消防…

【TF-IDF算法】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

基于LangChain-Chatchat实现的RAG-本地知识库的问答应用[2]-简洁部署版

基于LangChain-Chatchat实现的RAG-本地知识库的问答应用[2]-简洁部署版 1.环境要求 1.1 软件要求 要顺利运行本代码,请按照以下系统要求进行配置 已经测试过的系统 Linux Ubuntu 22.04.5 kernel version 6.7其他系统可能出现系统兼容性问题。 最低要求 该要求仅针对标准模…

C++的map

作用&#xff1a; 映射&#xff0c;相当于python的字典&#xff0c;使用一个key来寻找value&#xff0c;m[key]value; 生成&#xff1a; map<int,string> m;//无参生成&#xff0c;key是int类型&#xff0c;value是string类型 map<int,string> m{{1,"hello…

手把手教你入门vue+springboot开发(三)--登录功能后端

文章目录 前言一、redis安装二、后端代码1.修改application.yml文件2.增加utils文件3.增加Result类4.修改UserController类5.修改UserMapper类6.修改UserService和UserServiceImpl类7.增加LoginInterceptor类8.增加WebConfig类9.修改pom.xml文件 前言 前两篇我们用vuespringbo…

内网不能访问网站怎么办?

内网不能访问网站是在网络使用过程中常见的问题之一。当我们使用局域网连接时&#xff0c;有时候会遇到无法访问特定网站的情况。这可能是因为网络环境复杂&#xff0c;或者受到了某些限制。本篇文章将介绍一种解决内网不能访问网站问题的产品——天联组网。 天联组网是一款由…

非计算机专业可以考“软考”吗?

全国计算机软件水平考试对报名条件没有学历、资历、年龄以及专业等限制&#xff0c;非计算机专业的人员也可以报考。证书长期有效&#xff0c;考生可根据个人需求选择合适的级别和资格进行报考。报名方式包括网上报名和考生本人到指定地点报名两种。 考试范围 (1) 高级资格包括…

RS485和CAN电路中的TVS管选择

在RS485和CAN电路设计中&#xff0c;经常要考虑“静电和浪涌保护”&#xff0c;怎么选择TVS管&#xff0c;很少有人讲解。 1、先了解TVS管 TVS管有单向管和双向管&#xff0c;通常后缀为CA的是双向TVS管&#xff0c;只有字母A的是单向TVS管。见下图&#xff1a; 2、TVS选择依…

C++11列表初始化{}

列表初始化 C11后为了能让自定义类型也能够快速被初始化新增 {} 内置类型变量 int a1 { 10 };int a2{ 11 };int a3 { 1 2 };int a4{ 1 2 }; 注意&#xff1a;列表初始化可以在{}之前使用等号&#xff0c;其效果与不使用没有什么区别。 内置类型数组 int arr1[] { 1,2,3…

安装前端依赖node-sass报错

文章目录 问题1&#xff1a;node-sass报错问题2&#xff1a;node-gyp报错问题3&#xff1a;node-sass再次报错问题4&#xff1a;node-sass三次报错 问题1&#xff1a;node-sass报错 问题描述&#xff1a;经常会碰到一个新的项目安装依赖时&#xff0c;会报node-sass版本的问题…

白嫖Cloudflare Workers 搭建 Docker Hub镜像加速服务

简介 基于Cloudflare Workers 搭建 Docker Hub镜像加速服务。 首先要注册一个Cloudflare账号。 Cloudflare账号下域名的一级域名&#xff0c;推荐万网注册个top域名&#xff0c;再转移到Cloudflare&#xff0c;很便宜的。 注意 Worker 每天每免费账号有次数限制&#xff0c;…

文件简单做二维码的方法,几步就能够完成操作

怎样用二维码来查看文件内容&#xff1f;随着网络的快速发展&#xff0c;通过二维码来查看文件是现在很常用的一种形式&#xff0c;能够更快让其他人获取文件内容&#xff0c;从而提升传播的速度和效率。比如用这种方式来下发通知文件、分享学习资料、浏览海报图片、传递个人简…

[Java基本语法] 数组及其应用

&#x1f338;个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 &#x1f3f5;️热门专栏:&#x1f355; Collection与数据结构 (92平均质量分)https://blog.csdn.net/2301_80050796/category_12621348.html?spm1001.2014.3001.5482 &#x1f9c0;线程与…

zookeeper介绍 和 编译踩坑

zookeeper 分布式协调服务 ZooKeeper原理及介绍 - 鹿泉 - 博客园 Zookeeper是在分布式环境中应用非常广泛&#xff0c;它的优秀功能很多&#xff0c;比如分布式环境中全局命名服务&#xff0c;服务注册中心&#xff0c;全局分布式锁等等。 本项目使用其分布式服务配置中心&am…

Qt 非圆角图片裁剪为圆角图片

将Qt非圆角图片裁剪为圆角图片,步骤如下&#xff1a; 1、按照原始图片尺寸定义一张透明的新图形 2、使用画家工具在新图形上绘制一个圆角矩形线路 3、绘制图片 4、使用圆角矩形切割图片边角 封装成函数如下&#xff1a; QPixmap Widget::getRoundedPixmap(const QPixmap srcPix…

注解 - @ControllerAdvice

注解简介 在今天的每日一注解中&#xff0c;我们将探讨ControllerAdvice注解。ControllerAdvice是Spring框架中的一个注解&#xff0c;用于集中处理应用程序中所有控制器的全局异常处理、数据绑定和数据预处理。 注解定义 ControllerAdvice注解用于定义一个全局的异常处理、数…

PyQt5学习系列之新项目创建并使用widget

PyQt5学习系列之新项目创建并使用widget 前言报错新建项目程序完整程序总结 前言 新建项目&#xff0c;再使用ui转py&#xff0c;无论怎么样都打不开py文件&#xff0c;直接报错。 报错 Connected to pydev debugger (build 233.11799.298)新建项目程序 # Press ShiftF10 to…

[C++][数据结构][二叉搜索树]详细讲解

目录 1.概念2.二叉搜索树操作1.查找2.插入3.删除 3.二叉搜索树的实现4.二叉搜索树的应用1.K模型2.KV模型 5.二叉搜索树的性能分析 1.概念 二叉搜索树又称二叉排序树&#xff0c;具有以下性质 若它的左子树不为空&#xff0c;则左子树上所有节点的值都小于根节点的值若它的右子…