IoMarkIrpPending的使用

IoMarkIrpPending

VOID 
  IoMarkIrpPending(
  IN OUT PIRP  Irp
  );

IoMarkIrpPending marks the given IRP, indicating that a driver's Dispatch routine returned STATUS_PENDING because further processing is required by other driver routines.

Parameters
Irp
Points to the IRP to be marked as pending.
Include

wdm.h or ntddk.h

Comments

Unless a driver calls IoCompleteRequest from its Dispatch routine with a given IRP or passes the IRP on to lower drivers, it must call IoMarkIrpPending with the IRP. Otherwise, the I/O Manager attempts to complete the IRP as soon as the Dispatch routine returns control.

If a driver queues incoming IRPs, it should call IoMarkIrpPending before it queues each IRP. Otherwise, an IRP could be dequeued, completed by another driver routine, and freed by the system before the call to IoMarkIrpPending occurs, thereby causing a crash.

Any driver that sets an IoCompletion routine in an IRP and then passes the IRP down to a lower driver should check the IRP->PendingReturned flag in the IoCompletion routine. If the flag is set, the IoCompletion routine must call IoMarkIrpPending with the IRP. Note, however, that a driver that passes down the IRP and then waits on an event should not mark the IRP pending. Instead, its IoCompletion routine should signal the event and return STATUS_MORE_PROCESSING_REQUIRED.

A routine that calls IoMarkIrpPending must return STATUS_PENDING.

Callers of IoMarkIrpPending must be running at IRQL <= DISPATCH_LEVEL.

 

 

很多人对于IoMarkIrpPending的使用很困惑。其实IoMarkIrpPending是微软定义的一个宏,它将IRP的当前IO堆栈单元的Control域置成了SL_PENDING_RETURNED,这个值之后会被IO管理器来检查——如果IO管理器没有发现这个值,那么当相关例程返回的时候(例如派遣例程),IO管理器会主动完成这个IRP。引入这个函数最早的意义是为了异步IRP的处理(如IRP排队等)。很多经典书籍包括上面的DDK文档中都指出:如果完成例程不返回STATUS_MORE_PROCESSING_REQUIRED时,在完成例程里要有如下两条语句:

if (Irp->PendingReturned)
IoMarkIrpPending(Irp);

但是上述的这些参考文献都没有真正说清楚原因。真正的原因在于:

因为调用IoCompleteRequest的线程上下文可能与发起IRP的线程上下文不同——前者可能在一个中断处理的DPC线程中,后者可能在一个读写线程中,这个时候为了能在发起IRP的线程上下文中使IRP的不透明域UserEvent受信,一个内核态的APC将被IoCompleteRequest投递。但是在有些情况下,调用IoCompleteRequest的线程上下文可能与发起IRP的线程上下文有可能相同,那么微软为了避免在这种情况下进行没有必要的APC投递,它将IO管理器设计成:检查IRP顶层IO堆栈单元的Control域——如果该域为SL_PENDING_RETURNED,那么进行APC投递,否则不进行投递。由于完成例程是从IO堆栈底部向顶部依次被调用,所以在完成例程里面正好可以做SL_PENDING_RETURNED的传递,这就是那两行代码的来由。(如果发起IRP请求的例程(例如派遣例程)返回的是STATUS_PENDING,那么Irp->PendingReturned就被置为TRUE,这个标志正好给完成例程用来判断原始请求的初始状态是否为PENDING)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值