WDM驱动程序设计.ppt
《WDM驱动程序设计.ppt》由会员分享,可在线阅读,更多相关《WDM驱动程序设计.ppt(40页珍藏版)》请在三一办公上搜索。
1、WDM驱动程序设计,同步技术,第 5 讲,主要内容,一个同步问题的例子中断请求级自旋锁内核同步对象其它内核同步原语,一个同步问题的例子,下面利用静态变量lActiveRequests记录当前未完成的I/O请求数:,static LONG lActiveRequests;NTSTATUS DispatchPnp(PDEVICE_OBJECT fdo,PIRP Irp)+lActiveRequests;./process PNP request-lActiveRequests;,有什么问题?,关于语句“+lActiveRequests”在X86处理器上汇编程序生成如下代码:,/+lActiveRe
2、quests;mov eax,lActiveRequests add eax,1 mov lActiveRequests,eax,上述代码的第三条指令被执行之前如果被同一CPU上的其它执行线程打断,或者在不同CPU上有完全相同的代码在同时运行都会引起+lActiveRequests的计数错误。,解决的办法,把load/add/store和load/subtract/store指令序列替换为原子指令:,/+lActiveRequests;inc lActiveRequests/-lActiveRequests;dec lActiveRequests,INC和DEC指令不能被中断,但是多处理器环境
3、中仍然是不安全的,因为这两个指令都是由几条微代码实现的。,最终解决办法,/+lActiveRequests;lock inc lActiveRequests/-lActiveRequests;lock dec lActiveRequests,LOCK指令前缀可以使当前执行多微码指令的CPU锁定总线,从而保证数据访问的完整性。,两个最差的假定,驱动程序开发者必须做如下两个最差的假定:操作系统可以在任何时间抢先任何例程并停留任何长的时间,所以我们不能保证自己的任务不被干扰或延迟。即使我们能防止被抢先,但其它CPU上执行的代码也会干扰我们代码的执行,甚至一个程序的代码可以在两个不同线程的上下文中并发
4、执行。,同步请求级,一个确定的CPU上的活动仅能被拥有更高IRQL的活动抢先。,IRQL与线程优先级,线程优先级是与IRQL非常不同的概念。线程优先级控制着OS线程调度器的调度动作,决定何时抢先运行线程以及下一次运行什么线程。当IRQL级高于或等于DISPATCH_LEVEL级时线程切换停止,无论当前活动的是什么线程都将保持活动状态直到IRQL降到DISPATCH_LEVEL级之下。在进行线程调度时会切换线程上下文;按照IRQL进行活动抢先时不会切换线程上下文。,利用IRQL进行同步,方法:将所有对共享数据的访问都应该在同一(提升的,高于PASSIVE_LEVEL级的)IRQL上进行。上述方法
5、只适用于单CPU。可利用KeRaiseIrql和KeLowerIrql函数改变当前IRQL。,KIRQL oldirql;ASSERT(KeGetCurrentIrql()=DISPATCH_LEVEL);KeRaiseIrql(DISPATCH_LEVEL,自旋锁(spin lock),利用自旋锁可以解决多处理器平台上的同步问题。一个自旋锁对应一个内存变量。为了获得一个自旋锁,在某CPU上运行的代码需先执行一个原子操作,该操作测试并设置(test-and-set)某个内存变量,由于它是原子操作,所以在该操作完成之前其它CPU不可能访问这个内存变量。如果测试结果表明锁已经空闲,则程序获得这个自
6、旋锁并继续执行。如果测试结果表明锁仍被占用,程序将在一个小的循环内重复这个“测试并设置(test-and-set)”操作,即开始“自旋”。最后,锁的所有者通过重置该变量释放这个自旋锁,于是,某个等待的test-and-set操作向其调用者报告该自旋锁已释放。,使用自旋锁时的注意事项,第一,如果一个已经拥有某个自旋锁的CPU想第二次获得这个自旋锁,则该CPU将死锁(deadlock)。第二,CPU在等待自旋锁时不做任何有用的工作,仅仅是等待。所以,为了避免影响性能,你应该在拥有自旋锁时做尽量少的操作,因为此时某个CPU可能正在等待这个自旋锁。第三,仅能在低于或等于DISPATCH_LEVEL级上
7、请求自旋锁,在你拥有自旋锁期间,内核将把你的代码提升到DISPATCH_LEVEL级上运行。,如何使用自旋锁,首先,在非分页内存中为一个KSPIN_LOCK对象分配存储空间。然后调用KeInitializeSpinLock初始化这个对象。,typedef struct _DEVICE_EXTENSION.KSPIN_LOCK QLock;DEVICE_EXTENSION,*PDEVICE_EXTENSION;NTSTATUS AddDevice(.)PDEVICE_EXTENSION pdx=.;KeInitializeSpinLock(.,如何使用自旋锁,当代码运行在低于或等于DISPATC
8、H_LEVEL级时获取这个锁,并执行需要保护的代码,最后释放自旋锁。,NTSTATUS DispatchSomething(.)KIRQL oldirql;PDEVICE_EXTENSION pdx=.;KeAcquireSpinLock(,如何使用自旋锁,如果知道代码已经处在DISPATCH_LEVEL级上,如DPC、StartIo,和其它执行在DISPATCH_LEVEL级上的驱动程序例程,可以调用两个专用函数来操作自旋锁:,KeAcquireSpinLockAtDpcLevel(,内核同步对象,利用内核同步对象可以暂时阻塞一个线程的执行,同步不同线程的执行动作。内核同步对象仅影响OS线程
9、调度器的调度动作,因此一般只在低于DISPATCH_LEVEL级的代码中用于阻塞线程。在驱动程序中,只能在“非任意线程上下文”条件下利用内核同步对象阻塞调用者的线程或产生该请求的线程。在“任意线程上下文”调用等待原语只会阻塞一个“无辜”的线程。,非任意线程上下文,如果驱动程序的回调例程能确切知道处于哪个线程上下文中,则称处于“非任意线程上下文”;大部分时间里,驱动程序无法知道这个事实,即处于“任意线程上下文”中。非任意线程上下文的例子:设备的最高级驱动程序的IRP处理函数可以确切地知道它执行在发出该I/O请求的应用程序线程的上下文中。PNP类IRP的处理函数可以确切地知道它执行在一个系统线程(
10、System Thread)中。在你自己创建的内核模式系统线程中。(PsCreateSystemThread)DriverEntry、AddDevice、DriverUnload等函数执行在一个系统线程(System Thread)中。,常用的内核同步对象,在单同步对象上等待,在任何时刻,任何对象都处于两种状态中的一种:信号态(signaled)或非信号态(not signaled)。调用KeWaitForSingleObject或KeWaitForMultipleObjects函数可以使代码(以及背景线程)在一个或多个同步对象上等待,等待它们进入信号态。,ASSERT(KeGetCurren
11、tIrql()=DISPATCH_LEVEL);LARGE_INTEGER timeout;NTSTATUS status=KeWaitForSingleObject(object,WaitReason,WaitMode,Alertable,KeWaitForSingleObject参数含义,object 指向要等待的对象,它应该指向一个上面表中列出的同步对象。该对象必须在非分页内存中。WaitReason 是一个纯粹建议性的值,KWAIT_REASON枚举型,一般取值为Executive。WaitMode 是MODE枚举类型,该枚举类型仅有两个值:KernelMode和UserMode。一般
12、取值为KernelMode。Alertable 参数一般指定为FALSE。timeout 是一个64位超时值的地址,单位为100纳秒。正数的超时表示一个从1601年1月1日起的绝对时间。负数代表相对于当前时间的时间间隔。指定为0将使等待函数立即返回。指定为NULL代表无限期等待。,KeWaitForSingleObject(object,WaitReason,WaitMode,Alertable,KeWaitForSingleObject返回值含义,STATUS_SUCCESS,表示等待被满足。即你调用KeWaitForSingleObject时,对象或者已经进入信号态,或者在等待中进入信号态
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- WDM 驱动程序 设计

链接地址:https://www.31ppt.com/p-5452689.html