Windows Vista
Windows 7
Windows Azure
Windows Server
Windows Phone
Windows 7

Windows 7 User Mode Drivers Overview and Operation : I/O Queues & I/O Request Objects

6/28/2012 5:32:20 PM

1. I/O Queues

The IWDFIoQueue interface exposes a queue object that presents requests from UMDF to the driver. Queues control the flow of I/O through the driver.

A driver typically creates one or more I/O queues, each of which can accept one or more types of requests. The driver configures the queues when it creates them. For each queue, the driver can specify:

  • The types of requests that are placed in the queue.

  • The power management options for the queue.

  • The dispatch method for the queue, which determines whether the framework calls the driver to dispatch a request or whether the driver calls the framework to dispatch a request. The dispatch method also determines whether the driver services multiple requests from the queue at a given time.

  • Whether the queue accepts read and write requests that have a zero-length buffer.

A driver can have any number of queues, which can all be configured differently. For example, a driver might have a parallel queue for read requests and a sequential queue for write requests.

Although a request is in a queue and has not yet been presented to the driver, the queue is considered the “owner” of the request. After the request has been dispatched to the driver, it is “owned” by the driver. Internally, each queue object keeps track of which requests it owns and which requests it has dispatched to the driver. A driver can forward a request from one queue to another by calling a method on the request object.

1.1. Dispatch Type

A queue’s dispatch type determines how and when I/O requests are delivered to the driver and, as a result, whether multiple I/O requests from a queue are active in the driver at one time. Drivers can control the concurrency of I/O requests by configuring the dispatching method for their queues. UMDF supports three dispatch types:

  • Sequential— A queue that is configured for sequential dispatching delivers I/O requests to the driver one at a time. The queue does not deliver another request to the driver until the previous request has been completed or forwarded to another queue.

  • Parallel— A queue that is configured for parallel dispatching delivers I/O requests to the driver as soon as possible, whether or not another request is already active in the driver.

  • Manual— A queue that is configured for manual dispatching does not deliver I/O requests to the driver. Instead, the driver retrieves requests at its own pace by calling a method on the queue.

The dispatch type controls only the number of requests that are active within a driver at one time. It has no effect on whether the queue’s I/O event callbacks are invoked sequentially or concurrently; instead, the concurrency of callbacks is controlled by the synchronization model (locking constraint) of the device object. Even if the synchronization model does not allow concurrent callbacks, a parallel queue nevertheless might have many requests active in the driver at one time.

All I/O requests that a driver receives from a queue are inherently asynchronous. The driver can complete the request within the event callback or sometime later, after returning from the callback. The driver is not required to mark the request pending, as in a Kernel Mode WDM Driver; UMDF handles this on behalf of the driver.

1.2. Queues and Power Management

UMDF integrates support for queues with Plug and Play/power management state machine. Power management is configurable on a per-queue basis. A driver can use both power-managed and nonpower-managed queues and can sort requests based on the requirements for its power model.

1.2.1. Power-Managed Queues

By default, I/O queues are power managed, which means that the state of the queue can trigger power-management activities. Such queues have a couple of advantages, as the following scenarios show:

  • If an I/O request arrives while the system is in the working state (SO) but the device is not, UMDF notifies its Plug and Play and power handler so that it can restore device power.

  • If the device power state begins to change while the driver “owns” an I/O request that was dispatched from a power-managed queue, UMDF can notify the driver through the IQueueCallbackIoStop::OnIoStop callback. The driver must complete, cancel, or acknowledge all of the I/O requests that it owns before the device can exit from the working state.

For power-managed queues, UMDF pauses the delivery of requests when the device leaves the working state (DO) and resumes delivery when the device returns to the working state. Although delivery stops while the queue is paused, queuing does not. If UMDF receives a request while the queue is paused, UMDF adds the request to the queue for delivery after the queue resumes. If an I/O request arrives while the system is transitioning to a sleep state, however, UMDF does not return the device to the working state until the system returns to the working state. The request remains in the queue until the system and the device have returned to the working state.

For requests to be delivered, both the driver and device power state must allow processing. The driver can pause delivery manually by calling IWDFIoQueue::Stop or IWDFIoQueue::StopSynchronously and later resume delivery by calling WdfIoQueue::Start.

1.2.2. Nonpower-Managed Queues

If a queue is not power managed, the state of the queue has no effect on power management, and conversely, UMDF delivers requests to the driver any time the system is in the working state, regardless of the power state of the device. Drivers should use nonpower-managed queues to hold requests that the driver can handle even while its device is not in the working state.

2. I/O Request Objects

The IWDFIoRequest interface exposes an I/O request object, which describes a read, write, or device I/O control request. When an I/O request arrives from the reflector, the I/O handler creates an I/O request object and adds the object to the queue that the driver configured for requests of that type. The driver receives a pointer to IWDFIoRequest interface for the object when UMDF calls the I/O event callback function or, if the queue supports manual dispatching, when the driver requests the object from the queue.

The driver can then call methods on the interface to retrieve information about the request, such as the request type, parameters, data buffers, and associated file object, among others.

Like all other UMDF objects, the I/O request object has a reference count. When the driver completes the I/O request that the object represents, UMDF automatically drops its reference on the object and any child objects such as memory buffers. After the driver that was called completes the request, it must not attempt to access the request object or any of its child objects.

2.1. Retrieving Buffers from I/O Requests

The IWDFMemory interface exposes a memory object, which encapsulates an I/O buffer that is associated with an I/O request. The memory object can be used to copy data from the driver to the buffer and vice versa. The driver can also create its own memory object by calling IWDFDriver::CreatePreallocatedWdfMemory and can then associate that memory object with the buffer that is supplied in an I/O request.

Like other UMDF objects, memory objects have reference counts and persist until all references to them have been removed. The buffer that underlies the memory object, however, might not be “owned” by the object itself. For example, if the issuer of the I/O request allocated the buffer or if the driver called CreatePreallocatedWdfMemory to assign an existing driver-created buffer to the object, the memory object does not “own the buffer.” In this case, the buffer pointer becomes invalid when the associated I/O request has been completed, even if the memory object still exists.

Each memory object contains the length of the buffer that it represents. IWDFMemory methods that copy data to and from the buffer validate the length of every transfer to prevent buffer over runs and under runs, which can result in corrupt data or security breaches.

Each memory object also controls access to the buffer and allows the driver to write only buffers that support I/O from the device to the buffer. A buffer that is used to receive data from the device (as in a read request) is writable. The memory object does not allow write access to a buffer that only supplies data (as in a write request).

2.2. Sending I/O Requests to an I/O Target

If a driver cannot satisfy an I/O request by itself, it typically forwards the request to an I/O target. An I/O target represents a device object to which the driver sends an I/O request. The default I/O target is typically the next lower driver in the device stack. A UMDF driver can access the default I/O target through the IWDFIoTarget interface; it gets a pointer to this interface by calling the IWDFDevice::GetDefaultIoTarget method.

In addition to forwarding existing I/O requests, some UMDF drivers issue I/O requests by creating or reusing an I/O request object and sending the request to an I/O target. Drivers can send requests either synchronously or asynchronously and can specify a time-out value for either type of request. If the time-out period expires, UMDF cancels the request.

In addition to using the default I/O target, a driver can create additional I/O targets. An I/O target can be a UMDF driver, a KMDF driver, a WDM driver, or any other Kernel Mode Driver. UMDF defines two interfaces that create targets:

  • IWDFFileHandleTargetFactory creates an I/O target that is associated with a file handle that the driver has already opened. The driver calls the Win32 CreateFile function to open the handle, and then calls methods in this interface to create the I/O target. This mechanism enables a driver to send I/O requests to a different device stack.

  • IWDFUsbTargetFactory creates a USB device object and an associated I/O target.

To create an I/O target, the driver queries the device object for the IWDFFileHandleTargetFactory or IWDFUsbTargetFactory interface and then calls the creation method that is supported by the interface.

If the driver is the originator of the request, it creates an I/O request object by calling IWDFDevice::CreateRequest. If the driver is merely forwarding an existing request, this step is not required.

Whether this is a new or existing request, the driver must format it before sending it. To format a request for the default I/O target or for a file handle-based target, the driver calls methods in the IWDFIoTarget interface. To format an I/O request for a USB target, the driver calls methods in the IWDFUsbTargetDevice, which inherits from IWDFIoTarget. Formatting the request is important because it specifies the buffers and buffer lengths that the target should use in performing the I/O.

The driver then can call IWDFIoRequest::Send to send the request. If the driver implements the IRequestCallbackCompletion::OnCompletion and IRequestCallbackCancel::OnCancel interfaces, UMDF calls the driver if the request is completed or canceled.

The I/O target object racks queued and sent requests and can cancel them when the state of the target device of the issuing driver changes. UMDF does not free the I/O target object until all of the I/O requests that have been sent to it are complete. If the driver created the I/O request, it must release its reference to the request before deleting it.

By default, UMDF sends a request only when the target is in the proper state to receive it. However, a driver can request that UMDF ignore the state of the target and send the request anyway. If the target device has been stopped (but not removed), UMDF queues the request to send later after the target device resumes. If the driver that forwarded the request specifies a time-out value, the timer starts when the request is added to the queue.

To manage an I/O target, the driver can call methods in the IWDFIoTargetStateManagement interface. These methods enable the driver to start, stop, and remove the target and to query its current state.

2.3. Creating Buffers for I/O Requests

Drivers that issue I/O requests must supply buffers with those requests. A driver can

  • Allocate the buffer from memory by using the C++ new operator or a Win32 memory allocation function and the call IWdfDriver::CreatePreallocatedWdfMemory to associate the buffer with a memory object. The driver must ensure that the buffer persists until the request has completed.

  • Call IWdfDriver::CreateWdfMemory to create a memory object with a specified buffer size. UMDF ensures that the buffer persists until the I/O request has completed back to the issuing driver.

  • Retrieve a memory object from an incoming I/O request for use in a new request.

If the driver uses a memory object, UMDF takes out a reference on that object on behalf of the new I/O target when it formats the memory object to send to the I/O target. This reference persists until one of the following occurs:

  • The request has been completed.

  • The driver reformats the request object by calling IWDFRequest::FormatUsingCurrentType or any of the IWDFIoTarget::FormatRequestForXxx methods.

  • The request has been deleted.

The driver can retrieve a memory object from an incoming I/O request and then reformat it for use in a new request to a new I/O target. However, if the driver has not yet completed the original request, the driver still has a reference on the memory object. The driver should implement an I/O completion callback (the IRequestCallbackRequestCompletion interface) for the new I/O request, and in this callback must call Release on the memory object before it completes the original request.

2.4. Canceled and Suspended Requests

Windows I/O is inherently asynchronous. The system can request that a driver stop processing an I/O request at any time for many reasons, most commonly:

  • The thread or process that issued the request cancels it or exits.

  • A system Plug and Play or power event such as hibernation occurs.

  • The device is being, or has been, removed.

The action that a driver takes to stop processing an I/O request depends on the reason for suspension or cancellation. In general, the driver can either cancel the request or complete it with an error. In some situations, the system might request that a driver suspend (temporarily pause) processing; the system notifies the driver later when to resume processing.

To provide a good user experience, drivers should provide callbacks to handle cancellation and suspension of any I/O request that might take a long time to complete or that might not complete, such as a request for asynchronous input.

2.4.1. Request Cancellation

How UMDF proceeds to cancel an I/O request depends on whether the request has already been delivered to the target driver:

  • If the request has never been delivered—either because UMDF has not yet queued it or because it is still in a queue—UMDF cancels or suspends it automatically without notifying the driver.

  • If the request has been delivered but the driver forwards it to a different queue, UMDF automatically cancels the request without notifying the driver.

  • If the request has been delivered and is owned by the driver, UMDF does not cancel it. However, if the driver explicitly marks the request cancelable by calling the IWDFIoRequest::MarkCancelable method and registering a cancellation callback (IRequestCallbackCancel::OnCancel), UMDF notifies the driver that the request was canceled.

A driver should mark a request cancelable and register an I/O cancellation callback if either of the following is true:

  • The request involves a long-term operation.

  • The request might never succeed; for example, the request is waiting for synchronous input.

In the OnCancel callback, the driver must perform any tasks that are required to cancel the request, such as stopping any device I/O operations that are in progress and canceling any related requests that it has already forwarded to an I/O target. Eventually, the driver must complete the request with the status ERROR_CANCELLED.

Requests that the driver has marked cancelable cannot be forwarded to another queue. Before requeuing a request, the driver must first make it noncancelable by calling IWDFIoRequest::UnmarkCancelable. After the request has been added to the new queue, UMDF again considers it cancelable until that queue dispatches it to the driver.

2.4.2. Request Suspension

When the system transitions to a sleep state—typically because the user has requested hibernation or closed the lid on a laptop—a driver can complete, requeue, or continue to hold any requests that it is currently processing. UMDF notifies the driver of the impending power change by calling the IQueueCallbackIoStop::OnIoStop callback for each such request. Each call includes flags that indicate the reason for stopping the queue and whether the I/O request is currently cancelable.

Depending on the value of the flags, the driver can complete the request, requeue the request, acknowledge the event but continue to hold the request, or ignore the event if the current request will complete in a timely manner. If the queue is stopping because the device is being removed, either by an orderly removal or a surprise removal, the device must complete the request immediately.

Drivers should implement the OnIoStop method for any request that might take a long time to complete or that might not complete, such as a request for asynchronous input. OnIoStop provides a good user experience for laptops and other power-managed systems.

2.5. Completing I/O Requests

To complete an I/O request, a driver calls IWDFIoRequest::Complete or CompleteWithInformation. In response, UMDF completes the underlying I/O request from the system and then deletes the I/O request object and any child objects. If the driver implements the IObjectCleanup::OnCleanup method for the request object, UMDF invokes that method before completing the underlying system I/O request, so that the system I/O request itself is still valid when the callback runs. Because the underlying request is still valid, the UMDF driver has access to its parameters and memory buffers.

After Complete or CompleteWithInformation returns, the I/O request object and its resources have been released. The driver must not attempt to access the object or any of its resources, such as parameters and memory buffers that were passed in the request.

If the request was dispatched from a sequential queue, the driver’s call to complete the request might cause UMDF to deliver the next request in the queue. (If the queue is configured for parallel dispatching, UMDF can deliver another request at any time.) If the driver holds any locks while it calls Complete or CompleteWithInformation, it must ensure that its event callback methods for the queue do not use the same locks because a deadlock might occur. In practice, this is difficult to ensure, so the best practice is not to call Complete or CompleteWithInformation while holding a lock.

2.6. Adaptive Time-outs

Drivers for Windows 7 should follow the Windows guidelines for I/O completion and cancellation, which require that drivers:

  • Support cancellation for I/O requests that might take an indefinite period of time to complete.

  • Complete I/O requests within a reasonable period (generally, 10 seconds or less) after cancellation.

  • Do not block I/O thread for an unreasonable period while performing I/O. UMDF I/O threads are a limited resource, so blocking on such a thread for a long time can decrease driver performance.

To aid User Mode Drivers in conforming to these guidelines, UMDF supports adaptive time-outs. UMDF tracks the progress on critical I/O operations that can hold up the system if delayed. Critical operations include cleanup, close, cancellation, and Plug and Play and power requests.

When the reflector passes a critical request to the driver host process, it watches for progress to ensure that I/O operations are proceeding. While such a request is pending, the User Mode Driver must complete an operation at regular intervals until it has completed the critical request. If the time-out period expires, the reflector terminates the host process and reports the problem through Window Error Reporting (WER). By default, the time-out is currently one minute. If the driver must perform operations that take a long time to complete, it should handle them asynchronously, create a separate thread to handle them, or handle them in a user work item.

Other -----------------
- Windows 7 User Mode Drivers Overview and Operation : I/O Request Flow
- Memory Dump Files (part 2) - Using Memory Dump Files to Analyze Stop Errors
- Memory Dump Files (part 1) - Configuring Small Memory Dump Files, Kernel Memory Dump Files, Complete Memory Dump Files
- Troubleshooting Stop Messages : Stop Message Overview
- Using Tablet PCs and Ultra-Mobile PCs : Using a Tablet PC (part 4) - Flicks and Gestures
- Using Tablet PCs and Ultra-Mobile PCs : Using a Tablet PC (part 3) - Using the Tablet PC Input Panel
- Using Tablet PCs and Ultra-Mobile PCs : Using a Tablet PC (part 2) - Configuring Tablet PC Features - Using Pen and Touch
- Using Tablet PCs and Ultra-Mobile PCs : Using a Tablet PC (part 1) - Configuring Tablet PC Features - Using Tablet PC Settings
- Using Tablet PCs and Ultra-Mobile PCs : A Short History of the Tablet PC
- Microsoft Project 2010 : Using the Resource Sheet View
- Microsoft Project 2010 : Understanding How Project Uses Resources and Costs
- Microsoft Access 2010 : Creating Queries - Finding Unmatched Records
- Microsoft Access 2010 : Creating Queries - Finding Duplicate Records
- Microsoft Outlook 2010 : Viewing Message Participant Information
- Microsoft Outlook 2010 : Configuring Reading Pane Behavior
- Deep Dive: Windows Home Server Features (part 2) - Remote Access
- Deep Dive: Windows Home Server Features (part 1) - PC Backup and Restore, Document and Media Sharing
- Microsoft Visio 2010 : Containers and Lists (part 2) - Lists
- Microsoft Visio 2010 : Containers and Lists (part 1) - Containers
- Microsoft Visio 2010 : Creating rule set reports - Getting the XSL stylesheet
Most view of day
- Windows Server 2012 : Ensuring DHCP availability (part 2) - Implementing DHCP failover
- Adobe Photoshop CS5 : The Essentials of Camera Raw - Photoshop Killer Tips
- Windows Small Business Server 2011 : Disaster Planning - Planning for Disaster
- Microsoft Visio 2010 : Importing Graphics (part 3) - Adding Clip Art to Your Diagrams
- Windows Phone 7 Programming Model : Asynchronous Programming - Background Threads
- What's new and improved in SharePoint 2013 : Using the Office Store
- Microsoft Lync Server 2013 : Deploying Lync Online - Adding Domains to Lync Online
- Games and Windows 7 : Using the Games Explorer (part 3) - Rating Your System's Performance
- Working with the User State Migration Tool (part 5) - Getting Extra Mileage Out of the USMT
- Managing Windows Licensing and Activation : Managing Volume License Activation (part 1) - Centralizing activation with KMS
Top 10
- Microsoft Exchange Server 2013 : Mailbox management - Setting mailbox permissions (part 5) - Outlook delegate access
- Microsoft Exchange Server 2013 : Mailbox management - Setting mailbox permissions (part 4) - Sending messages on behalf of other users
- Microsoft Exchange Server 2013 : Mailbox management - Setting mailbox permissions (part 3) - Mailbox auto-mapping through Autodiscover
- Microsoft Exchange Server 2013 : Mailbox management - Setting mailbox permissions (part 2) - Managing Full Access permission
- Microsoft Exchange Server 2013 : Mailbox management - Setting mailbox permissions (part 1) - Mailbox delegation
- Microsoft Exchange Server 2013 : Mailbox management - Health mailboxes
- Microsoft Exchange Server 2013 : Mailbox management - Discovery mailboxes - Creating additional discovery mailboxes
- Windows Phone 8 : Messaging - Composing a New Message (part 8) - Checking for New Mail
- Windows Phone 8 : Messaging - Composing a New Message (part 7) - Adding Emoticons and Clip Art
- Windows Phone 8 : Messaging - Composing a New Message (part 6) - Adding Recipients Through CC and Blind CC
Windows XP
Windows Vista
Windows 7
Windows Azure
Windows Server
Windows Phone
2015 Camaro