Managing I/O Queues

Starting an I/O Queue

When a driver calls WdfIoQueueCreate to create an I/O queue, the framework automatically enables the queue to receive I/O requests and to deliver them to a driver.

Drivers typically call WdfIoQueueCreate from within an EvtDriverDeviceAdd callback function. The framework can begin delivering I/O requests to the driver after the driver's EvtDriverDeviceAdd callback function returns.

If your driver is using power-managed I/O queues, the framework cannot begin delivering requests to your driver until the device enters its working state and the framework has called the driver's EvtDeviceD0Entry callback function.

Stopping and Restarting an I/O Queue

Your driver can call WdfIoQueueStop or WdfIoQueueStopSynchronously to temporarily prevent the framework from delivering I/O requests from an I/O queue. To resume delivery of I/O requests, the driver calls WdfIoQueueStart.

If your driver uses power-managed I/O queues, the framework automatically stops a device's queues when the device leaves its working (D0) state, and the framework restarts the queues when the device state returns to D0.

Adding Requests to an I/O Queue

When the system sends a read, write, or device I/O control request to a driver, the framework places the request in an I/O queue. The driver can control the types of requests that the framework stores in each queue by calling WdfDeviceConfigureRequestDispatching.

A driver can also requeue requests that it has received from the framework, by calling WdfRequestForwardToIoQueue.

Obtaining Requests from an I/O Queue

If a driver specifies the sequential or the parallel dispatching method for an I/O queue, it receives requests in request handlers.

If a driver specifies the manual or sequential dispatching method, it can obtain requests by calling WdfIoQueueRetrieveNextRequest or WdfIoQueueRetrieveRequestByFileObject.

Searching for an I/O Request

If a driver specifies the manual dispatching method for an I/O queue, it can use the following steps to search for particular requests in the queue:

  1. Call WdfIoQueueFindRequest to locate a request that matches driver-specified criteria.

  2. Call WdfIoQueueRetrieveFoundRequest to retrieve the request that WdfIoQueueFindRequest located.

Purging or Draining an I/O Queue

Purging an I/O queue means stopping insertion of I/O requests into the queue and canceling any requests that are already in the queue.

Draining an I/O queue means stopping insertion of I/O requests into the queue, while allowing any requests that are already in the queue to be delivered to the driver.

Drivers typically purge or drain their queues only if the queues are not power-managed. For power-managed I/O queues, drivers can provide EvtIoStop and EvtIoResume callback functions.

If some of your driver's queues are not power-managed, you might want to purge or drain a queue if its associated device or I/O channel becomes unavailable. Typically, you will purge, instead of drain, a queue unless there is a high likelihood that each request contains very important information. For example, a driver for a network device might purge its queues, while a driver for a storage device would likely drain its queues.

If you want your driver to purge or drain an I/O queue, the driver can call one of the following queue object methods:

Exercise caution when calling WdfIoQueueDrain and WdfIoQueueDrainSynchronously. Because a drain operation waits for requests to be completed, you should only drain a queue if you are certain that the queue's pending requests will complete in a timely fashion. If you do not know how long I/O requests will take to complete and it is acceptable to cancel outstanding requests, consider purging the queue.

Moving Requests from One I/O Queue to Another

After your driver has received an I/O request, you might want the driver to requeue the request into a different I/O queue. To do this, the driver calls WdfRequestForwardToIoQueue or WdfRequestForwardToParentDeviceIoQueue, which adds the request to the tail of a specified queue. Eventually, the framework will deliver the request to the driver again by using the specified queue's dispatching method. For more information about moving I/O requests from one I/O queue to another, see Requeuing I/O Requests.

Intercepting an I/O Request before it is Queued

It is possible for a driver to intercept an I/O request before the framework places the request in an I/O queue. To intercept I/O requests, the driver must call WdfDeviceInitSetIoInCallerContextCallback to register an EvtIoInCallerContext callback function.

The framework associates the EvtIoInCallerContext callback function with a device. As a result, the framework calls the EvtIoInCallerContext callback function every time it receives a request that the system is sending to the device.

Typically, when an EvtIoInCallerContext callback function receives a request, it performs some preliminary processing for the request. Next, the callback function calls WdfDeviceEnqueueRequest, which gives the request back to the framework. The framework can then place the request in the proper I/O queue, just as it would have if it had not called the EvtIoInCallerContext callback function.

The primary reason that a driver might provide an EvtIoInCallerContext callback function is that the driver has to handle I/O operations that support the I/O method called neither buffered nor direct I/O. For this I/O method, the driver must access received buffers in the process context of the originator of the I/O request. For more information, see Accessing Data Buffers in Framework-Based Drivers.

Obtaining I/O Queue Properties

To obtain properties of a framework queue object, the driver can call the following methods: