Every driver-created I/O request object requires one or more memory objects that describe the I/O buffers for the request. The driver must supply the memory objects and the buffers for the I/O request and format the request before sending it.
The drivers that handle an I/O request read from and write to the buffers that are supplied in the request. For a read request, an output buffer provides a place for the I/O target to return the requested data. For a write request, an input buffer supplies the data to be written. A device I/O control request can have one buffer for input and another buffer for output or it can use the same buffer for both.
Figure 9-2 shows the relationships among the WDF I/O request object, the WDF memory object, and the buffer.
Figure 9-2: WDF I/O request object, WDF memory object, and buffer
As Figure 9-2 shows, the WDF I/O request object maintains a reference on the memory object. The memory object, in turn, contains a pointer to a buffer. WDF provides methods for setting and retrieving the memory object from the I/O request object and for setting and retrieving the buffer pointer from the memory object, subject to certain restrictions.
Memory objects are WDF objects, so they do more than just wrap buffer pointers-they also have reference counts. Reference-counted memory decreases the chance that a driver will inadvertently free the memory at the wrong time or try to access memory that has already been freed. Reference counts provide the following advantages:
Memory cannot be freed until the WDF I/O request that uses it is complete, because the I/O request object has a reference on the memory object. The reference also ensures that the memory is not freed while the request is pending in an I/O target driver.
This is particularly advantageous in debugging, because such an error could generate a bug check that indicates a problem in the target driver, even though the bug is actually in your driver.
Cleanup of resources in a driver that sends I/O requests is simpler, because the driver can delete the memory object while the WDF I/O request is still pending. The memory object persists until the I/O request is complete.
Although the memory object has a reference count, the underlying buffer does not. The buffer is just an area in memory that an application, the framework, or the driver has allocated. It is not a WDF object, so its lifetime is controlled by the component that created it. If your driver sends I/O requests-and particularly if it reuses memory objects-you must be careful how and when the driver accesses the buffer pointer. A nonzero reference count alone is not necessarily adequate to keep the buffer pointer valid. Table 9-5 summarizes buffer lifetimes.
If the buffer was created by …
The buffer pointer becomes invalid when …
The application that issued the I/O request
The driver completes the I/O request.
The driver's call to a language-based or system memory allocation function
The driver frees the allocation.
The framework's IWDFDriver:: CreateWdfMemory or WdfMemoryCreate method
The memory object's reference count reaches zero.
Be careful if you use memory objects with different buffer lifetimes in the same code. To simplify coding, try to use only one memory object/buffer type combination in a particular I/O path.
-Doron Holan, Windows Driver Foundation Team, Microsoft