zoukankan      html  css  js  c++  java
  • [转]分层驱动模型中IRP的传递与完成

    在Windows分层驱动模型中,设备栈中的设备一般都是通过对上层传来的IRP做相应的处理来实现驱动的功能。这里对常用的几种IRP传递及完成的方式进行归纳和总结:

    1. 在本层驱动中完成

    1.1 在本层驱动中以同步方式完成
    在本层同步完成一般做完相应处理后,设置Irp->IoStatus.Status和Irp->IoStatus.Information,调用IoCompleteRequest完成该IRP,return IRP的完成状态即可。

    1.2 在本层驱动中以异步方式完成
    在本层异步完成一般是得到IRP后将其入队/起线程另行处理,同时调用IoMarkIrpPending将该IRP标记为Pending,之后即可return STATUS_PENDING。此时该IRP并未真正完成,需待未决的操作在他处完成后调用IoCompleteRequest才真正完成。


    2. 转发至下层驱动

    2.1 本层不作处理
    有时对于某些IRP,本层驱动不需要做任何处理。此时可调用IoSkipCurrentIrpStackLocation跳过当前设备栈,然后调用IoCallDriver将IRP转发至下层驱动,并将转发的结果直接返回。此种处理方式并不需要关心下层驱动处理IRP的方式究竟是同步还是异步。IRP转发至下层后就与己无关了。

    2.2 同步转发方式
    有时IRP在本层无法直接处理,需要将其转发至下层,待下层处理完后在其结果上进行修改再将其返回。这时可以采用同步转发方式进行处理。首先在相应dispatch routine中初始化一个未激发的event,调用IoCopyCurrentIrpStackLocationToNext将本层设备栈参数复制到下层。然后设置一个CompletionRoutine,将刚才初始化过的event作为context传给它。之后调用IoCallDriver转发IRP至下层,并判断返回值是否为STATUS_PENDING。是则wait之前的event。在CompletionRoutine中判断该IRP是否PendingReturned,是则说明之前IoCallDriver返回了STATUS_PENDING,于是激发event。CompletionRoutine返回STATUS_MORE_PROCESSING_REQUIRED使我们的dispatch routine重新取得对该IRP的控制权。本层dispatch等待结束再次获得控制权后,进行相应处理,之后需再次调用IoCompleteRequest完成该IRP。
    同步转发是驱动中常用的一种IRP处理方式。一般会将本层dispatch转发IRP至下层并等待CompletionRoutine激发event的行为独立成一个ForwardIrpSynchronous的函数。几个dispatch只需一个ForwardIrpSynchronous,代码相对简单。
    注意不要在本层dispatch中调用IoMarkIrpPending,因为上层的请求在本层被同步处理了。在同步转发中,如果下层驱动也采用同步方式处理,则本层dispatch不会(也不需要)wait,IoCallDriver返回时CompletionRoutine已经被调用,性能上也没有什么损失。

    2.3 异步转发方式
    异步转发也能在下层驱动完成IRP时获得处理的机会,其主要是采用了异步处理机制。首先本层dispatch调用IoCopyCurrentIrpStackLocationToNext将本层设备栈参数复制到下层,设置相应的CompletionRoutine,然后调用IoCallDriver将IRP转发至下层驱动,并将转发的结果直接return给上层调用者。在CompletionRoutine中再判断该IRP是否PendingReturned,是则需要调用IoMarkIrpPending。之后可对下层驱动处理该IRP的结果进行相应操作。最后返回STATUS_CONTINUE_COMPLETION(同STATUS_SUCCESS)。
    异步转发在异步处理时性能最佳,但处理的逻辑放在了CompletionRoutine中,因此多个dispatch需要编写多个CompletionRoutine。而同步转发往往几个dispatch只需一个ForwardIrpSynchronous即可,代码相对简单。


    值得注意的是,各个dispatch routine运行的IRQL是由调用关系决定的。如果上层调用者有运行在DISPATCH_LEVEL的可能,则本层的dispatch也需要按照运行在DISPATCH_LEVEL来设计。比如传递至本层dispatch的IRP是在上层驱动的StartIO例程中转发的,则本层处理该类IRP的代码就可能运行在DISPATCH_LEVEL。

  • 相关阅读:
    java并发容器
    实现个简单的线程池
    【hdu 3501 (数论、欧拉函数)】
    【关于Java学习的几点看法】
    【乘法游戏】
    【hdu 1280 前m大的数】
    【最大因子数】
    【ECJTU_ACM 11级队员2012年暑假训练赛(7) C Fire Net】
    【ACM ICPC Fighting!!!!!!!!!!!!!】
    【firefly 默默最喜欢的歌】
  • 原文地址:https://www.cnblogs.com/spinsoft/p/2563808.html
Copyright © 2011-2022 走看看