Handling IRPs 7: IoCompletion Routines and Asynchronous I/O Responses

来源:互联网 发布:金蝶软件连接数据库 编辑:程序博客网 时间:2024/06/05 22:28

IoCompletion Routines and Asynchronous I/O Responses

If a driver sets an IoCompletion routine for an IRP, theIoCompletion routine can check the value of the Irp->PendingReturned field to determine whether the IRP will be completed asynchronously.

If the value of the Irp->PendingReturned field is TRUE, theIoCallDriver routine will return (or has already returned) STATUS_PENDING. IfIrp‑>PendingReturned is FALSE, IoCallDriver has already returned with the value in theIrp‑>IoStatus.Status field. IoCompletion routines for intermediate drivers can similarly testIrp‑>PendingReturned to determine how the result of their forwarded request is being handled.

Drivers that complete I/O requests asynchronously sometimes must perform additional processing as the IRP moves back up the device stack. The following code sets anIoCompletion routine when it forwards an IRP to the next lower driver, then waits on an event. Thus, it handles an asynchronous response in the same manner as a synchronous one:

KEVENT   event;

 

KeInitializeEvent(&event, NotificationEvent, FALSE);

 

IoCopyCurrentIrpStackLocationToNext(Irp);

 

IoSetCompletionRoutine(Irp,

                       CatchIrpRoutine,

                       &event,

                       TRUE,

                       TRUE,

                       TRUE

                       );

 

status = IoCallDriver(DeviceObject, Irp);

 

//

// Wait for lower drivers to be done with the Irp.

// It’s important to note here that when you allocate

// memory for an event on the stack you must do a

// KernelMode wait instead of UserMode to prevent

// the stack from being paged out.

//

 

    if (status == STATUS_PENDING) {

       status = KeWaitForSingleObject(&event,

                             Executive,

                             KernelMode,

                             FALSE,

                             NULL

                             );

       ASSERT(NT_SUCCESS(status));

       status = Irp->IoStatus.Status;

    }

 

return status;

 

In this case, the driver waits for an event that is set by itsIoCompletion routine. The driver must wait in kernel mode because the event was allocated on the stack. For performance reasons, drivers should wait on events only when IRPs complete asynchronously. TheKeWaitForSingleObject routine uses the system-wide dispatcher lock. This lock protects the signal state of events, semaphores, and mutexes, and consequently is used frequently throughout the operating system. Requiring the use of this lock for every synchronous I/O operation would unacceptably hinder performance.

The following code shows the IoCompletion routine set in the preceding fragment:

NTSTATUS

CatchIrpRoutine(

    IN PDEVICE_OBJECT    DeviceObject,

    IN PIRP       Irp,

    IN PKEVENT Event

    )

{

    if (IrpàPendingReturned) {

 

        // Release waiting thread

        KeSetEvent( Event, IO_NO_INCREMENT, FALSE );

    }

 

    return STATUS_MORE_PROCESSING_REQUIRED;

}

 

The IoCompletion routine tests the value of theIrp->PendingReturned field. Based on this value, it sets an event only if STATUS_PENDING has been or will be returned to the caller. This avoids a call to theKeSetEvent routine, which uses the system-wide dispatcher lock.

The IoCompletion routine returns STATUS_MORE_PROCESSING_REQUIRED. This status indicates to the I/O Manager that the current driver must perform additional processing while it owns the IRP. The I/O Manager stops the upward completion of the IRP, leaving the I/O stack location in its current position. The current driver still owns the IRP and can continue to process it in another routine. When the driver has completely processed the IRP, it should call the IoCompleteRequest routine to continue IRP completion.

Ownership of the IRP is important because it determines whether the driver can access the IRP. As soon as a driver relinquishes ownership of the IRP, the IRP can be completed or freed on another thread, and any attempt by the driver to access the IRP can result in a system crash. 
原创粉丝点击