现在的位置: 首页 > 综合 > 正文

IRP 的创建

2013年10月08日 ⁄ 综合 ⁄ 共 1206字 ⁄ 字号 评论关闭
 

1. 有四种方法来创建IRP
Ø IoBuildAsynchronousFsdRequest
创建异步IRP,不需要等待其完成;
Ø IoBuildSynchronousFsdRequest
创建同步IRP, 需要等待其完成,这种方法和上面的只能创建某些特定类型IRP
Ø IoBuildDeviceIoCtontrolRequest
创建一个类型为 IRP_MJ_DEVICE_CONTROL 或者
IRP_MJ_DEVICE_CONTROL 的同步IRP.
Ø IoAllocateIrp
创建任何类型的异步IRP
2. 创建同步IRP
 I/O管理器认为新创建的IRP是属于创建IRP时所处的那个线程,这样,如果这个线程结束了,I/O管理器会自动取消属于它的还处在PENDING状态的IRP.所以,不要在任意上下文状态创建一个IRP,否则,IRP可能被意外的取消了。创建同步IRP时,需要用户提供一个事件对象,要保证在I/O管理器设置该事件对象的信号时,该事件对象还在内存中。只能在PASSIVE_LEVEL 上调用创建同步IRP的函数,因为当IRP完成时,系统派遣一个APC来置位提供的那个事件,以下的code有问题:
PIRP irp = IoBuildSynchronousFsdRequest(...);
ExAcquireFastMutex(...);
NTSTATUS status = IoCallDriver(...);
if (status == STATUS_PENDING)
{
 KeWaitForSingleObject(...); 
}
ExReleaseFastMutex(...);
红色部分会导致死锁,当IRP被完成时,IoCompleteRequest会派遣一个该线程的APC,这个APC会设置用户等待的事件,但是由于开始调用了ExAcquireFastMutex,从而使得该段code处在APC_LEVEL上,这样APC就没法执行了。
有三种方案解决这个问题:
Ø 使用常规互斥对象代替快速互斥对象;
Ø 使用KeEnterCriticalRegion,它不会阻止APC的运行,然后使用ExAcquireFastMutexUnsafe 来获得互斥对象
Ø 创建异步IRP来代替
3.创建异步IRP
可以在非任意上下文和任意上下文中创建异步IRP, 需要提供一个完成回调例程做IRP
的清理工作和调用IoFreeIrp.可以在IRQL <= DISPATCH_LEVEL 的级别来创建
4 派遣IRP
创建完IRP后,使用IoGetNextIrpStackLocation函数来获得第一个堆栈单元的指针,然后初始化这个IRP。
5. 不要以STATUS_PENDING 的状态完成一个IRP, 调用 IoCompleteRequest之前要保证IRP的取消例程为空。把IRP向下层驱动传递的时候,也要保证IRP的取消例程为空。

 

抱歉!评论已关闭.