Memory Object and Buffer Allocation for IO Requests


Memory Object and Buffer Allocation for I/O Requests

A driver can allocate a buffer and a memory object in the following ways:

  • Allocating the buffer and the memory object at the same time, in a single call to the framework.

  • Creating a new memory object and associating it with an existing driver-allocated buffer.

A driver can create a new WDF memory object when it creates an I/O request, or the driver can use an existing memory object that it either created earlier or retrieved from an incoming I/O request.

Parent for the Memory Object

When a driver creates a new memory object, the framework by default sets the driver object as the parent of the memory object. This default is intended for general memory allocations but is not ideal for memory that is used in I/O requests. If your driver creates a new memory object to use in an I/O request, you should set the parent to an object whose lifetime more closely matches that of the memory object. Specifically:

To

Set this object as parent

Delete the memory object when the I/O request is completed

I/O request object

Retain the memory object for later use in additional I/O requests

Device object

To set the parent for a memory object:

  • A UMDF driver supplies a pointer to the IWDFObject interface for the parent object when it creates the memory object.

  • A KMDF driver supplies a value for the ParentObject field of the object attributes structure that it supplies when it creates the memory object.

If your driver uses a memory object that it retrieved from an incoming WDF I/O request object, that I/O request object is the parent of the memory object. Thus, the memory object can persist no longer than the incoming WDF I/O request object. When all drivers have completed the incoming I/O request, the framework deletes both the request object and the memory object.

Tip 

If you do not use the appropriate parent for a driver-created memory object and do not explicitly delete the memory object when it is no longer required, it can persist until the driver object is disposed. If the driver uses several memory objects, this can lead to heavy memory usage and possibly slow performance or cause later memory allocations to fail. Furthermore, leak detection tools might not detect this leak because the memory object is eventually freed.

Buffer Types

UMDF and KMDF drivers use different types of buffers because they have access to different memory pools and address spaces:

  • UMDF drivers can use only the address space of the host process, in which all memory is pageable. UMDF drivers do not require nonpaged memory because all of their code runs at PASSIVE_LEVEL, so paging is always enabled. The Windows I/O manager locks any buffers that a UMDF driver passes to the kernel-mode portion of the device stack.

  • KMDF drivers can allocate buffers from the system's paged or nonpaged pool. In a synchronous request, the lifetimes of the memory object and the buffer are the same. Therefore, the driver can supply a simple pointer to memory (PVOID) or a pointer to an MDL (PMDL) for the buffer, or the driver can create the buffer at the same time it creates the memory object. In an asynchronous request, the driver must use WDF memory objects so that the framework can ensure that the buffers persist until the I/O request has completed back to the driver that created the request.

Create a Memory Object and a Buffer Simultaneously

A WDF driver can create a memory object and allocate a buffer with a single call to the framework by using one of the following methods:

  •  UMDF  IWDFDriver::CreateWdfMemory Creates a memory object and allocates a buffer of a specified size for a UMDF driver.

  •  KMDF  WdfMemoryCreate Creates a memory object and allocates a buffer of a specified size for a KMDF driver.

When the framework creates the memory object and allocates the buffer at the same time, the lifetimes of the memory object and the buffer are the same. The framework ensures that the buffer persists until the I/O request has completed back to the driver.

This technique is the easiest to use and requires a minimum of object lifetime management. Most drivers should create memory objects and buffers in this way whenever practical.

Create a Memory Object that Uses an Existing Buffer

By using an existing buffer, a driver can sometimes avoid double-buffering-that is, copying data from an internal driver buffer to the WDF memory object and vice versa. For example, a driver might already have a region in its device context area that contains the data to send in a device I/O control request. Instead of allocating a new buffer along with the new memory object and copying the data to the new buffer, the driver can associate the existing buffer with the new memory object.

The following methods create a new memory object that uses an existing buffer:

  •  UMDF  IWDFDriver::CreatePreallocatedWdfMemory Creates a new framework memory object and associates it with an existing buffer for a UMDF driver.

    A UMDF driver can later assign a different buffer to the memory object by calling IWDFMemory::SetBuffer on the memory object.

  •  KMDF  WdfMemoryCreatePreallocated Creates a new memory object and associates it with an existing buffer for a KMDF driver.

    A KMDF driver can later assign a different buffer to the memory object by calling WdfMemoryAssignBuffer.

  •  KMDF  WdfMemoryCreateFromLookaside Creates a new memory object and assigns it a buffer from a lookaside list.

    Chapter 12, "WDF Support Objects," provides more information on lookaside lists.

When a driver uses an existing buffer in a WDF memory object, the driver must ensure that the buffer persists until the request has been completed back to the driver. When the memory object is deleted, the framework does not free the buffer. Likewise, the framework does not free the previously assigned buffer when the driver assigns a new buffer to the memory object.

Important 

The following are the rules for reusing I/O and request objects:

  • A driver can reassign a memory object that it created.

  • A driver can reassign a memory object that it received in an I/O request from the framework, if it must split the incoming request into smaller requests.

  • A driver can assign the same memory object for use in multiple I/O requests at the same time, if all of the I/O requests treat the buffer as read-only.

  • UMDF drivers cannot reuse I/O request objects.

  • A KMDF driver can reuse an I/O request object that it created. A KMDF driver cannot reuse an I/O request object that it received from the framework.

Association between Memory Object and I/O Request Object

After the driver creates the memory object, the driver must call the framework to associate the memory object with the I/O request object and format the request for the I/O target. In response, the framework prepares the underlying IRP and takes out a reference on the memory object on behalf of the I/O target. This reference persists until one of the following occurs:

  • The I/O request has been completed back to the driver.

  • The driver reformats the WDF I/O request object.

  • The WDF I/O request object has been deleted.

  • A KMDF driver calls WdfRequestReuse in preparation for sending the WDF I/O request object to another I/O target.

Tip 

Chapter 24, "Static Driver Verifier," describes how to annotate your driver's callback functions so that SDV can analyze compliance with KMDF rules that specify that after a request is completed, its buffer, MDL, or memory object cannot be accessed.

UMDF Example: Create a New Memory Object with an Existing Buffer

The example in Listing 9-5 shows how a UMDF driver can create a new memory object that uses an existing buffer. The code in the example is from the Device.cpp file in the Fx2_Driver sample.

Listing 9-5: Calling CreatePreallocatedWdfMemory in a UMDF driver

image from book
 HRESULT CMyDevice::SendControlTransferSynchronously(     __in PWINUSB_SETUP_PACKET SetupPacket,     __inout PBYTE Buffer,     __in ULONG BufferLength,     __out PULONG LengthTransferred     ) {     HRESULT hr = S_OK;     IWDFIoRequest *pWdfRequest = NULL;     IWDFDriver * FxDriver = NULL;     IWDFMemory * FxMemory = NULL;     IWDFRequestCompletionParams * FxComplParams = NULL;     IWDFUsbRequestCompletionParams * FxUsbComplParams = NULL;     *LengthTransferred = 0;     hr = m_FxDevice->CreateRequest( NULL, //pCallbackInterface                                     NULL, //pParentObject                                     &pWdfRequest);     if (SUCCEEDED(hr)) {         m_FxDevice->GetDriver(&FxDriver);         hr = FxDriver->CreatePreallocatedWdfMemory( Buffer,                                                     BufferLength,                                                     NULL, //pCallbackInterface                                                     pWdfRequest, //pParentObject                                                     &FxMemory);         . . . // Error handling and additional code omitted     }     return; } 
image from book

The sample code in Listing 9-5 creates a framework I/O request object and a framework memory object that the driver sends in the request. The driver calls CreatePreallocatedWdfMemory on the driver object to create the memory object and associate it with the buffer that SendControlTransferSynchronously received as a parameter from its caller.

CreatePreallocatedWdfMemory takes four input parameters: a pointer to the buffer, the length of the buffer, a pointer to an IUnknown interface that the framework can query for object cleanup callbacks, and a pointer to the interface for the parent object.

The sample does not implement a callback object for the memory object, so it passes NULL for the IUnknown interface. By specifying pWdfRequest as the fourth parameter, the driver sets the I/O request object as the parent of the newly created memory object. However, neither the memory object nor the I/O request object is the parent of the buffer. The source of the buffer depends upon the caller of SendControlTransferSynchronously. Consequently, the SendControlTransferSynchronously function cannot make assumptions about the ownership or lifetime of the buffer.

Upon return, CreatePreallocatedWdfMemory supplies a pointer to the IWDFMemory interface for the framework memory object.

KMDF Example: Create a New Memory Object and a New Buffer

Listing 9-6 shows how a driver can create a new memory object and a new buffer in a KMDF driver. The sample code is based on the Sys\Bulkrwr.c file in the Usbsamp sample.

Listing 9-6: Creating a memory object in a KMDF driver

image from book
 WDF_OBJECT_ATTRIBUTES   objectAttribs; WDFREQUEST              Request; WDFMEMORY               urbMemory; PURB                    urb = NULL; WDF_OBJECT_ATTRIBUTES_INIT(&objectAttribs); objectAttribs.ParentObject = Request; status = WdfMemoryCreate( &objectAttribs,                           NonPagedPool,                           POOL_TAG,                           sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),                           &urbMemory,                           (PVOID*) &urb); 
image from book

The Usbsamp driver creates a new memory object to use in an I/O request that it sends to a USB I/O target. It initializes a WDF_OBJECT_ATTRIBUTES structure for the memory object and then sets the ParentObject field of the attributes structure to the I/O request object that will use the memory object. It then calls WdfMemoryCreate to create the memory object. This method has four input parameters: a pointer to the object attributes structure, an enumeration constant that indicates the type of memory to be allocated, a pool tag that identifies the driver and buffer type, and the size of the buffer to allocate. The method returns a handle to the new memory object and a pointer to the newly allocated buffer that is associated with the memory object.




Developing Drivers with the Microsoft Windows Driver Foundation
Developing Drivers with the Windows Driver Foundation (Pro Developer)
ISBN: 0735623740
EAN: 2147483647
Year: 2007
Pages: 224

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net