因为Windows是抢占的多任务操作系统,多个线程可以并发地访问共享数据结构或资源,而多个驱动例程会并发运行。为了保证数据完整,所有驱动必须同步共享数据结构的访问。正确实现这样的同步在WDM驱动中很困难。
对于KMDF驱动,要保证合理的同步处理需要注意几个地方:
· 从特定队列派遣的并发活动请求数量。
· 特定对象的并发活动回调数量。
· 访问对象特定数据的驱动工具函数。
· 对象回调函数运行的IRQL。
I/O队列的派遣方法控制了驱动中能够并发的来自该队列的活动请求数量,如前面“派遣类型”所述。但是限制并发请求并不能解决所有潜在的同步问题。同一对象的并发活动回调函数可能需要访问共享的对象特定数据,比如存储在对象上下文域的信息。相似地,驱动工具函数可能和回调函数一起共享对象特定数据。进一步,驱动必须留意回调函数调用时的IRQL。处于DISPATCH_LEVEL及以上,驱动不允许访问分页数据,也不允许发生线程竞争。
KMDF提供回调函数的自动同步,简化了驱动的同步操作。对大多数PDO,FDO,PNP和电源事件回调函数的调用都是同步的,所以对每个设备同时只有一个这样的回调函数在调用。这些回调函数调用时,IRQL为PASSIVE_LEVEL。然而,要注意调用EvtDeviceSurpriseRemoval,EvtDeviceQueryRemove和EvtDeviceQueryStop回调函数并不和其他回调同步,所以它们可能在设备改变电源状态或出于非工作状态时调用。
对于其他回调类型——主要是I/O相关的回调——驱动可以指定同步域(并发的程度)和最大执行等级(IRQL)。
KMDF提供以下可配置的同步特性:
· 同步域
· 执行等级
· 锁
虽然KMDF驱动比WDM驱动实现同步要简单地多,但是你仍然应该熟悉这些基础,Windows IRQL,同步和锁,在文章“Scheduling, Thread Context, and IRQL”和“Locks, Deadlocks, and Synchronization”中描述,这些文章在本文最后的资源中列出。
KMDF为几种对象类型的回调函数提供可配置的并发控制,称为同步域。对象的同步域确定了KMDF是否并发地调用对象的某个事件回调函数。
KMDF定义了以下同步域:
· 设备域,意味着KMDF不会为单个设备对象或文件对象或设备对象子队列并发地调用特定I/O事件回调函数。设备域特别应用于下列回调函数:EvtDeviceFileCreate,EvtFileCleanup,EvtFileClose,EvtIoDefault,EvtIoRead,EvtIoWrite,EvtIoDeviceControl,EvtIoInternalDeviceControl,EvtIoStop,EvtIoResume,EvtIoQueueState,EvtIoCanceledOnQueue,和EvtRequestCancel。
但是同一驱动对象创建的不同设备对象的回调能被并发调用。KMDF内部为每个设备对象创建了同步锁。为了实现设备的同步域,KMDF在调用设备对象的回调前要获取锁。
· 队列域,意味着KMDF不会并发地调用单个队列的特定I/O回调函数。如果内核模式驱动给设备对象指定了队列域,设备对象和队列的某些回调函数可以并发运行。但是下列单独队列对象的回调函数不能并发调用:EvtIoDefault,EvtIoRead,EvtIoWrite,EvtIoDeviceControl,EvtIoInternalDeviceControl,EvtIoStop,EvtIoResume,EvtIoQueueState,EvtIoCanceledOnQueue,和EvtRequestCancel。如果驱动指定了队列域,KMDF为每个队列对象创建同步锁并在调用其回调函数前先获取锁。