有关编写 DPC 例程的指导原则
编写 DpcForIsr 或 CustomDpc 例程时,请记住以下几点:
DpcForIsr 或 CustomDpc 例程必须将其对物理设备以及驱动程序维护的任何共享状态信息或资源的访问权限与访问相同设备或内存位置的驱动程序的其他例程同步。
如果 DpcForIsr 或 CustomDpc 例程与 ISR 共享设备或状态,则必须调用 KeSynchronizeExecution,并提供驱动程序提供的 SynchCritSection 例程的地址,该例程对设备进行编程或访问共享状态。 有关详细信息,请参阅 使用关键部分。
如果 DpcForIsr 或 CustomDpc 例程与 ISR 以外的例程共享状态或资源(如互锁队列或计时器对象),则必须使用驱动程序初始化的执行旋转锁保护共享状态或资源。 有关详细信息,请参阅 旋转锁。
DpcForIsr 和 CustomDpc 例程在 IRQL = DISPATCH_LEVEL 运行,这会限制它们可调用的支持例程集。
例如, DpcForIsr 和 CustomDpc 例程既不能访问也不能分配可分页内存,也不能等待 内核调度程序对象 设置为信号状态。 另一方面,他们可以使用 KeAcquireSpinLockAtDpcLevel 和 KeReleaseSpinLockFromDpcLevel 获取和释放驱动程序的执行旋转锁,这些锁的运行速度比 KeAcquireSpinLock 和 KeReleaseSpinLock 更快。
尽管 DPC 例程无法发出阻止调用,但它可以将工作项排入队列,以在以 IRQL 等于PASSIVE_LEVEL运行的 系统工作线程 中运行。 工作项可以发出等待调度程序对象的阻止调用。 为了对工作项进行排队, DpcForIsr 例程通常调用 IoQueueWorkItem 等例程, 而 CustomDpc 例程通常调用 ExQueueWorkItem 例程。
DpcForIsr 和 CustomDpc 例程通常负责在设备上启动下一个 I/O 操作。
对于使用直接 I/O 的最低级别物理设备驱动程序,此责任可能包括使用 SynchCritSection 例程对设备进行编程以传输更多数据,以便在驱动程序调用 IoStartNextPacket 之前满足当前 IRP。
DpcForIsr 和 CustomDpc 例程应仅在短时间内运行,并且应将尽可能多的处理委托给工作线程。
当 DPC 例程在处理器上运行时,阻止所有线程在同一处理器上运行。 在当前 DPC 例程完成之前,可能会阻止其他已排队并准备运行的 DPC 例程执行。 为了避免降低系统响应能力,典型的 DPC 例程每次调用时应运行不超过 100 微秒。 如果任务需要超过 100 微秒,并且必须在等于 DISPATCH_LEVEL 的 IRQL 下执行,则 DPC 例程应在 100 微秒后结束,并计划一个或多个 CustomTimerDpc 例程以在以后完成任务。 有关 CustomTimerDpc 例程的详细信息,请参阅 计时器对象和 DPC。
DPC 例程应仅执行必须在DISPATCH_LEVEL运行的任务,然后将任何剩余的与中断相关的工作委托给在 IRQL = PASSIVE_LEVEL 运行的线程。 例如,DPC 例程可以将工作项排队,以便在 系统工作线程中运行。
调用 KeStallExecutionProcessor 例程来延迟执行的 DPC 例程不得指定超过 100 微秒的延迟。
使用 WDK 中的性能分析工具评估 DPC 例程的执行时间。 有关使用 Tracelog 工具监视 DPC 执行时间的示例,请参阅 示例 15:测量 DPC/ISR 时间。
如果驱动程序使用 DMA 及其 AdapterControl 例程返回 KeepObject 或 DeallocateObjectKeepRegisters (从而保留系统 DMA 控制器通道或总线-主适配器以用于其他传输操作) , DpcForIsr 或 CustomDpc 例程负责在完成当前 IRP 并返回控件之前,向 FreeAdapterChannel 或 FreeMapRegisters 释放适配器对象或映射寄存器。
如果最低级别的物理设备驱动程序设置 控制器对象 以通过控制器将 I/O 操作同步到附加设备,则其 DpcForIsr 或 CustomDpc 例程负责在完成当前 IRP 并返回控制权之前使用 IoFreeController 释放控制器对象。
DpcForIsr 和 CustomDpc 例程通常负责记录处理给定请求期间发生的任何设备错误,在必要时并可能重试当前请求,以及为当前 IRP 设置 I/O 状态块和调用 IoCompleteRequest 。
如果驱动程序和设备支持重叠的 I/O 操作,则驱动程序必须遵循 处理重叠 I/O 操作的规则。
任何驱动程序的 DpcForIsr 或 CustomDpc 例程通常仅完成驱动程序必须支持的公共 I/O 控件代码子集的 I/O 处理。 具体而言,DPC 例程完成具有以下特征的设备控制请求的操作:
更改物理设备状态的请求
需要返回有关物理设备的固有易失性信息的请求