kmdf: synchronization, feeding a IoRead queue from a ringbuffer.

Hi all,

I apologize if this is going to be a too broad question but I’m really stuck on this problem and I’m too new to the kmdf to figure out the optimal solution.

I’m writing a filter driver (USB) that creates a raw pdo for a user mode process to connect to. The raw pdo is used to monitor some reports that match a certain criteria. Basically the driver handles the IOCTL_INTERNAL_USB_SUBMIT_URB function URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER and if there’s a match, it posts an event using the raw pdo.

The link between the main code path and the raw pdo EvtIoRead handler is through a ringbuffer. Basically, from the EvtIoInternalDeviceControl when I want to post a new event, I enqueue a message to the ringbuffer. When I get an EvtIoRead for the raw pdo, I dequeue the message and complete the request with it.

Now the issues with this: if I get a IoRead request but the ring buffer is empty, I can’t complete the IoRead with anything useful on the other end I cannot really get rid of it either.
Also, upon enqueue, I’d like to be able to start processing any pending IoRead.

One first idea was to set the IoRead queue as manual. The problem is that if I enqueue something but there’s no IoRead pending yet, I have no way to get the queue running when the IoRead comes in.
I also thought about setting the IoRead queue as sequential and stop the queue right away. Then when I enqueue something in the ringbuffer I start the queue. In the IoRead handler I stop the queue (asynchronously), dequeue and complete. The problem I see with this is that it’s not entirely clear to me what happens if I try to enqueue (and thus start the queue) WHILE I’m trying to stop it. Even if start and stop are synchronized, if for some reason the start comes while I’m in the IoRead handler but before I stopped the queue and end up with inconsistencies. I thought about checking the status of the ringbuffer before attempting the stop but in other to do that meaningfully I should be able to lock together the check and the stop and in the enqueue process lock the enqueue and the start, but this I can’t do since I can’t hold a lock while starting a queue.

I have the feeling that there’s a simpler way to use the framework to code this in the right way but I just can’t see it.

Could anybody point me in the right direction?

Thank you in advance,
Marco.

Have you tried a parallel top level read wdfqueue. When you process the read, if you have data in the buffer you complete the request. If there is no data in the ring buffer, you fwd the request into a 2ndary manual queue. When you get data to put into the ring buffer, you first check the manual queue. If empty, data goes into the ring buffer. If not empty, you pop a request and complete it without putting the data into the ring buffer

d

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@laurenzano.it
Sent: Tuesday, June 22, 2010 3:59 PM
To: Windows System Software Devs Interest List
Subject: [ntdev] kmdf: synchronization, feeding a IoRead queue from a ringbuffer.

Hi all,

I apologize if this is going to be a too broad question but I’m really stuck on this problem and I’m too new to the kmdf to figure out the optimal solution.

I’m writing a filter driver (USB) that creates a raw pdo for a user mode process to connect to. The raw pdo is used to monitor some reports that match a certain criteria. Basically the driver handles the IOCTL_INTERNAL_USB_SUBMIT_URB function URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER and if there’s a match, it posts an event using the raw pdo.

The link between the main code path and the raw pdo EvtIoRead handler is through a ringbuffer. Basically, from the EvtIoInternalDeviceControl when I want to post a new event, I enqueue a message to the ringbuffer. When I get an EvtIoRead for the raw pdo, I dequeue the message and complete the request with it.

Now the issues with this: if I get a IoRead request but the ring buffer is empty, I can’t complete the IoRead with anything useful on the other end I cannot really get rid of it either.
Also, upon enqueue, I’d like to be able to start processing any pending IoRead.

One first idea was to set the IoRead queue as manual. The problem is that if I enqueue something but there’s no IoRead pending yet, I have no way to get the queue running when the IoRead comes in.
I also thought about setting the IoRead queue as sequential and stop the queue right away. Then when I enqueue something in the ringbuffer I start the queue. In the IoRead handler I stop the queue (asynchronously), dequeue and complete. The problem I see with this is that it’s not entirely clear to me what happens if I try to enqueue (and thus start the queue) WHILE I’m trying to stop it. Even if start and stop are synchronized, if for some reason the start comes while I’m in the IoRead handler but before I stopped the queue and end up with inconsistencies. I thought about checking the status of the ringbuffer before attempting the stop but in other to do that meaningfully I should be able to lock together the check and the stop and in the enqueue process lock the enqueue and the start, but this I can’t do since I can’t hold a lock while starting a queue.

I have the feeling that there’s a simpler way to use the framework to code this in the right way but I just can’t see it.

Could anybody point me in the right direction?

Thank you in advance,
Marco.


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

xxxxx@laurenzano.it wrote:

I apologize if this is going to be a too broad question but I’m really stuck on this problem and I’m too new to the kmdf to figure out the optimal solution.

I’m writing a filter driver (USB) that creates a raw pdo for a user mode process to connect to. The raw pdo is used to monitor some reports that match a certain criteria. Basically the driver handles the IOCTL_INTERNAL_USB_SUBMIT_URB function URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER and if there’s a match, it posts an event using the raw pdo.

The link between the main code path and the raw pdo EvtIoRead handler is through a ringbuffer. Basically, from the EvtIoInternalDeviceControl when I want to post a new event, I enqueue a message to the ringbuffer. When I get an EvtIoRead for the raw pdo, I dequeue the message and complete the request with it.

Now the issues with this: if I get a IoRead request but the ring buffer is empty, I can’t complete the IoRead with anything useful on the other end I cannot really get rid of it either.
Also, upon enqueue, I’d like to be able to start processing any pending IoRead.

One first idea was to set the IoRead queue as manual. The problem is that if I enqueue something but there’s no IoRead pending yet, I have no way to get the queue running when the IoRead comes in.

I would use a separate manual queue for “pending read requests”. Have
your EvtIoRead dispatch through a sequential queue like normal.

EvtIoRead handler:
* WdfRequestForwardToIoQueue to the “PendingRead” queue
* Call “satisfy requests”

EvtIoInternalDeviceHandler:
* Queue up a message
* Call “satisfy requests”

SatisfyRequests:
* If there is a pending message in the ring buffer:
* WdfIoQueueRetrieveNextRequest from Pending Read
* If none, return
* Else pop and copy the message and complete the request

KMDF I/O queues are lightweight and extremely useful. There’s nothing
wrong with having a whole bunch of very specialized queues in a driver.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.