zoukankan      html  css  js  c++  java
  • 39、总结IRP,Forward IRP,Part I,all two parts

    An IRP completion routine can return either STATUS_MORE_PROCESSING_REQUIRED or STATUS_SUCCESS. 

    The I/O manager uses the following rules when it examines the status:  

    · If the status is STATUS_MORE_PROCESSING_REQUIRED, stop completing the IRP, leave the stack location unchanged and return. 

    · If the status is anything other than STATUS_MORE_PROCESSING_REQUIRED, continue completing the IRP upward.(向上) 

    Because the I/O Manager does not have to know which non-STATUS_MORE_PROCESSING_REQUIRED value is used, use STATUS_SUCCESS (because the value 0 is efficiently loadable on most processor architectures).  

    1、转发IRP 

    1)不向下层驱动转发,直接在派遣函数中完成IRP 

    Important When you complete an IRP in the dispatch routine, the return status of the dispatch routine should match the status of the value that is set in the IoStatus block of the IRP (Irp->IoStatus.Status). 

    代码
    NTSTATUS
    DispatchRoutine_5(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )
    {
    //
    // <-- Process the IRP here.
    //
    Irp->IoStatus.Status = STATUS_XXX;
    Irp
    ->IoStatus.Information = YYY;
    IoCompletRequest(Irp, IO_NO_INCREMENT);
    return STATUS_XXX;
    }

    2)直接转发

    将驱动传来的IRP直接转发给低层驱动。Use the following code if a driver just wants to forward the IRP down and take no additional action. The driver does not have to set a completion routine in this case. If the driver is a top level driver, the IRP can be completed synchronously or asynchronously, depending on the status that is returned by the lower driver. 

    代码
    NTSTATUS
    DispatchRoutine_1(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )
    {
    // You are not setting a completion routine, so just skip the stack
    // location because it provides better performance.
    IoSkipCurrentIrpStackLocation (Irp);
    return IoCallDriver(TopOfDeviceStack, Irp);
    }

    3)转发并且等待

    将传入的IRP转发向底层驱动,并且等待底层驱动将IRP处理完毕,这时驱动可以重新获得IRP的控制权,这主要依靠一个同步事件,并设置IRP的完成例程。如果本层驱动想重新获取IRP的控制,必须在完成例程后返回STATUS_MORE_PROCESSING_REQUIRED,这时候IRP需要重新被完成。这种情况多出于IRP_MN_START_DEVICE IRP等的处理情况。

    Use the following code if a driver wants to forward the IRP to a lower driver and wait for it to return so that it can process the IRP. This is frequently done when handling PNP IRPs. For example, when you receive a IRP_MN_START_DEVICE IRP, you must forward the IRP down to the bus driver and wait for it to complete before you can start your device. The Windows XP system has a new function named IoForwardIrpSynchronously that you can use to do this operation easily.

    代码
    NTSTATUS
    DispatchRoutine_2(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )
    {
    KEVENT
    event;
    NTSTATUS status;

    KeInitializeEvent(
    &event, NotificationEvent, FALSE);
    //
    // You are setting completion routine, so you must copy
    // current stack location to the next. You cannot skip a location
    // here.
    //
    IoCopyCurrentIrpStackLocationToNext(Irp);

    IoSetCompletionRoutine(Irp,
    CompletionRoutine_2,
    &event,
    TRUE,
    TRUE,
    TRUE
    );

    status
    = IoCallDriver(TopOfDeviceStack, Irp);

    if (status == STATUS_PENDING) {

    KeWaitForSingleObject(
    &event,
    Executive,
    // WaitReason
    KernelMode, // must be Kernelmode to prevent the stack getting paged out
    FALSE,
    NULL
    // indefinite wait
    );
    status
    = Irp->IoStatus.Status;
    }

    // <---- Do your own work here.

    // Because you stopped the completion of the IRP in the CompletionRoutine
    // by returning STATUS_MORE_PROCESSING_REQUIRED, you must call
    // IoCompleteRequest here.
    //
    IoCompleteRequest (Irp, IO_NO_INCREMENT);
    return status;
    }
    NTSTATUS
    CompletionRoutine_2(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp,
    IN PVOID Context
    )
    {
    if (Irp->PendingReturned == TRUE) {
    //
    // You will set the event only if the lower driver has returned
    // STATUS_PENDING earlier. This optimization removes the need to
    // call KeSetEvent unnecessarily and improves performance because the
    // system does not have to acquire an internal lock.
    //
    KeSetEvent ((PKEVENT) Context, IO_NO_INCREMENT, FALSE);
    }
    // This is the only status you can return.
    return STATUS_MORE_PROCESSING_REQUIRED;
    }

    3)转发并且设置完成例程,Forward with a completion routine

    In this case, the driver sets a completion routine, forwards the IRP down, and then returns the status of lower driver as is. The purpose of setting the completion routine is to modify the content of the IRP on its way back.

    代码
    NTSTATUS
    DispathRoutine_3(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )
    {
    NTSTATUS status;

    //
    // Because you are setting completion routine, you must copy the
    // current stack location to the next. You cannot skip a location
    // here.
    //
    IoCopyCurrentIrpStackLocationToNext(Irp);

    IoSetCompletionRoutine(Irp,
    CompletionRoutine_31,
    // or CompletionRoutine_32
    NULL,
    TRUE,
    TRUE,
    TRUE
    );

    return IoCallDriver(TopOfDeviceStack, Irp);

    }

    If you return the status of the lower driver from your dispatch routine:

    · You must not change the status of the IRP in the completion routine. This is to make sure that the status values set in the IRP's IoStatus block (Irp->IoStatus.Status) are the same as the return status of the lower drivers.

    · You must propagate the pending status of the IRP as indicated by Irp->PendingReturned.

    · You must not change the synchronicity of the IRP.

    两种编写方法:

    代码
    NTSTATUS
    CompletionRoutine_31 (
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp,
    IN PVOID Context
    )
    {

    //
    // Because the dispatch routine is returning the status of lower driver
    // as is, you must do the following:
    //
    if (Irp->PendingReturned) {

    IoMarkIrpPending( Irp );
    }

    return STATUS_CONTINUE_COMPLETION ; // Make sure of same synchronicity
    }

    NTSTATUS
    CompletionRoutine_32 (
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp,
    IN PVOID Context
    )
    {
    //
    // Because the dispatch routine is returning the status of lower driver
    // as is, you must do the following:
    //
    if (Irp->PendingReturned) {

    IoMarkIrpPending( Irp );
    }

    //
    // To make sure of the same synchronicity, complete the IRP here.
    // You cannot complete the IRP later in another thread because the
    // the dispatch routine is returning the status returned by the lower
    // driver as is.
    //
    IoCompleteRequest( Irp, IO_NO_INCREMENT);

    //
    // Although this is an unusual completion routine that you rarely see,
    // it is discussed here to address all possible ways to handle IRPs.
    //
    return STATUS_MORE_PROCESSING_REQUIRED;
    }

    4)暂时挂起当前IRP

    Use the following code snippet in a situation where the driver wants to either queue an IRP and process it later or forward the IRP to the lower driver and reuse it for a specific number of times before completing the IRP. The dispatch routine marks the IRP pending and returns STATUS_PENDING because the IRP is going to be completed later in a different thread. Here, the completion routine can change the status of the IRP if necessary

    代码
    NTSTATUS
    DispathRoutine_4(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )
    {
    NTSTATUS status;

    //
    // You mark the IRP pending if you are intending to queue the IRP
    // and process it later. If you are intending to forward the IRP
    // directly, use one of the methods discussed earlier in this article.
    //
    IoMarkIrpPending( Irp );

    //
    // For demonstration purposes: this IRP is forwarded to the lower driver.
    //
    IoCopyCurrentIrpStackLocationToNext(Irp);

    IoSetCompletionRoutine(Irp,
    CompletionRoutine_41,
    // or CompletionRoutine_42
    NULL,
    TRUE,
    TRUE,
    TRUE
    );
    IoCallDriver(TopOfDeviceStack, Irp);

    //
    // Because you marked the IRP pending, you must return pending,
    // regardless of the status of returned by IoCallDriver.
    //
    return STATUS_PENDING ;

    }

    The completion routine can either return STATUS_CONTINUE_COMPLETION or STATUS_MORE_PROCESSING_REQUIRED. You return STATUS_MORE_PROCESSING_REQUIRED only if you intend to reuse the IRP from another thread and complete it later.

    代码
    NTSTATUS
    CompletionRoutine_41(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp,
    IN PVOID Context
    )
    {
    //
    // By returning STATUS_CONTINUE_COMPLETION , you are relinquishing the
    // ownership of the IRP. You cannot touch the IRP after this.
    //
    return STATUS_CONTINUE_COMPLETION ;
    }
    NTSTATUS
    CompletionRoutine_42 (
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp,
    IN PVOID Context
    )
    {
    //
    // Because you are stopping the completion of the IRP by returning the
    // following status, you must complete the IRP later.
    //
    return STATUS_MORE_PROCESSING_REQUIRED ;
    }

    这种情况多发生在多个IRP并发的状态,在驱动程序运行中,需要将其串行化处理,可以采用StartIo,也可以自己将IRP依次插入到队列,然后在适当时候依次处理这些IRP。

    Get step by step guidance on how to
    ...

    参考

    [1] http://support.microsoft.com/kb/320275

    [2] Windows驱动开发技术详解,张帆

    [3] Walter Oney. Programming Windows Driver Model, Second Edition, Chapter 5.

  • 相关阅读:
    数组作业:例题5.1.一个10个元素一维数组的赋值与遍历
    java子父类初始化顺序 (1)父类静态代码块(2)父类静态变量初始化(3)子类静态代码块(4)子类静态变量初始化(5)main(6)有对象开辟空间都为0(7)父类显示初始化(8)父类构造(9)子类显示初始化(10)子类构造
    如果实现接口的类只使用一次用处不大换为如下简便写法——匿名内部类
    1、实现接口的抽象类——适配器;2、代理公司的方法——功能更强大的包装类;3、接口的使用——工厂模式(高内聚低耦合)
    内部类的作用?1、抽象类中包含一个内部接口如何实现与调用 ;2、接口中包含一个内部抽象类如何调用
    接口的多态使用; 接口应用实例:U盘、打印机可以使用共同的USB接口,插入到电脑上实现各自的功能。
    接口的定义——默认加public abstract默认全局常量;与继承不同,子类可以同时实现多个接口;抽象类实现接口;接口继承接口
    EBCDIC to ASCII
    how to pass variable from shell script to sqlplus
    关于Insufficient space for shared memory file解决办法
  • 原文地址:https://www.cnblogs.com/mydomain/p/1903695.html
Copyright © 2011-2022 走看看