Windows System Software -- Consulting, Training, Development -- Engineering Excellent, Every Time.

Using Counted Queues in WDF

Last reviewed and updated: 11 May 2020

If you’re familiar with WDF, you know that WDF Requests arrive at your driver via one or more upper edge WDF Queues that you define in your driver. These queues are used to organize and control the delivery of requests to your driver. How those requests are delivered to your driver is determined by the Dispatch Type with which you configure your Queue. You have two choices for Dispatch Type:

  • WdfIoQueueDispatchSequential — One request is presented from the Queue to your driver. When your driver completes the handling of that one request, a new request is presented.
  • WdfIoQueueDispatchParallel  — Multiple Requests are presented from the Queue to your driver. How many Requests can you get at a time? By default, there is no maximum number of Requests that can be in progress simultaneously. But you can optionally set a maximum number when you configure the Queue.

A Parallel Queue with a Maximum

As mentioned above, you can configure the dispatch type for the queue to be parallel (WdfIoQueueDispatchParallel), and before creating the queue, you fill-in the WDF_IO_QUEUE_CONFIG structure’s Settings.Parallel.NumberOfPresentedRequests field with the maximum number of WDF Requests you allow to be presented by the queue simultaneously. The code that does this is shown below.

  //
    // Configure our queue of incoming requests
    //
    WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queueConfig,
                             WdfIoQueueDispatchParallel);

    //
    // We'll take 2 requests at a time, thank you.
    //
    queueConfig.Settings.Parallel.NumberOfPresentedRequests =
                                                NOTHING_REQUESTS_IN_PROGRESS;

    //
    // Declare our I/O Event Processing callbacks
    //
    // We handle, read, write, and device control requests.
    //
    queueConfig.EvtIoRead = NothingEvtRead;
    queueConfig.EvtIoWrite = NothingEvtWrite;
    queueConfig.EvtIoDeviceControl = NothingEvtDeviceControl;

    //
    // Because this is a queue for a software-only device, indicate
    // that the queue doesn't need to be power managed
    //
    queueConfig.PowerManaged = WdfFalse;

    status = WdfIoQueueCreate(device,
                            &queueConfig,
                            WDF_NO_OBJECT_ATTRIBUTES,
                            NULL); // optional pointer to receive queue handle

In the code block above, you can see the driver initializes its default queue to use dispatch type Parallel in the usual way, using the WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE macro. It then sets the maximum number of requests that will be presented by the queue at one time to NOTHING_REQUESTS_IN_PROGRESS (which happens to be defined as 2 in this example). After configuring Event Processing Callbacks and indicating that the queue state is not to be altered by changes in device power state, the driver creates the queue by calling WdfIoQueueCreate.

Once the queue is created, you’re all set! KMDF will present request from the queue to your driver until the maximum number of in-progress requests has been reached.

The only caveat to note is that the maximum number of in-progress requests is configured via the WDF_IO_QUEUE_ CONFIG structure. This means that the maximum number of in-progress requests can be varied dynamically by your driver. It’s a configuration parameter that’s set when the WDF Queue is created, not a dynamically changeable attribute.

Defining In Progress Requests

In order to fully understand Counted Queues, it’s important to understand what comprises a presented “in progress request” in terms of KMDF. The rules for in-progress requests for a Counted Queue are the same as those for a queue configured for Sequential dispatching. Sequential Dispatching is, after all, entirely equivalent to Counted Queues with a Settings.Parallel.NumberOfPresentedRequests set to 1.

When a request is presented by a KMDF Queue, that request is considered to be “in-progress” until one of the following three things occurs:

  • The Request is completed by the driver, by calling WdfRequestComplete (or one of the similar functions).
  • The Request is forwarded to another Queue within the driver using WdfRequestForwardToIoQueue (or similar).
  • The Request is sent to another device/driver in the system using WdfRequestSend, specifying the WDF_REQUEST_SEND_OPTION_SEND_AND_FORGET flag in the WDF_REQUEST_SEND_ OPTIONS structure Flags field.

So, a request remains “in progress” until it’s been completed, it’s been put on another queue, or it’s been sent away by the driver using “send and forget.” Simple, right?

Yup, It Really IS That Easy

As with most things in WDF, this really is as simple as it seems. Now that’s something that you don’t normally hear when talking about Windows drivers!