Is EvtUsbTargetPipeReadComplete synchronized with EvtIoRead?

If I choose WdfSynchronizationScopeDevice, will EvtUsbTargetPipeReadComplete be synchronized with EvtIoRead?

Also, what if I set a WDM preprocess routine for read IRPs and then deliver the IRP to the framework? Will the framework still grab the lock before calling EvtIoRead?

I got a trace log where the execution of EvtIoRead and EvtUsbTargetPipeReadComplete are being mixed. They are both accessing a buffer at the same time – they both think the buffer has N bytes, so they both drain N bytes, and the buffer ends up with N*2 bytes drained out of it. Assuming I chose WdfSynchronizationScopeDevice, I thought this was impossible.

Also, what pattern should I follow in my WDM preprocess callback for read IRPs? Right now, it basically looks like this:

WdfObjectAcquireLock(Device);

if (certainCondition)
{
processIrpSynchronously(pIrp);
IoCompleteIrp(pIrp, IO_NO_INCREMENT);
WdfObjectReleaseLock(Device);
return pIrp->IoStatus.Status;
}
else
{
IoSkipCurrentIrpStackLocation(pIrp);
WdfObjectReleaseLock(Device);
return WdfDeviceWdmDispatchPreprocessedIrp(Device, pIrp);
}

Basically, under the assumption that KMDF would attempt to grab the device-wide lock before calling EvtIoRead, I released it manually before dispatching the IRP (to prevent a deadlock). Is this right?

-Chris

> If I choose WdfSynchronizationScopeDevice, will
EvtUsbTargetPipeReadComplete be synchronized with EvtIoRead?
No, KMDF synchronization can only apply to queues, dpcs, timers, and
work items. It does not apply to i/o completion routines, pnp, and
power callbacks.

Also, what if I set a WDM preprocess routine for read IRPs and then
deliver the IRP to the framework? Will the framework still grab the
lock before calling EvtIoRead?
Yes, the locking is independent of the preprocess routine, it has no
idea that it is there.

I got a trace log where the execution of EvtIoRead and
EvtUsbTargetPipeReadComplete are being mixed.
Since there is no locking between the 2, this is very possible. If you
need to synchronize the 2, you either need to grab the device lock in
the completion routine or roll your own lock. The danger of grabbing
the lock in the completion routine is if you are waiting for the usb
pipe to fully drain while holding the lock, you will deadlock.

The code looks OK, there is a bug in it though independent of the KMDF
aspects. You are touching the IRP after completing it

IoCompleteIrp(pIrp, IO_NO_INCREMENT);
WdfObjectReleaseLock(Device);
return pIrp->IoStatus.Status; <== here

it should be

NTSTATUS status = pIrp->IoStatus.Status;
IoCompleteIrp(pIrp, IO_NO_INCREMENT);
WdfObjectReleaseLock(Device);
return status;

d

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of
xxxxx@gmail.com
Sent: Monday, April 30, 2007 6:49 PM
To: Windows System Software Devs Interest List
Subject: [ntdev] Is EvtUsbTargetPipeReadComplete synchronized with
EvtIoRead?

If I choose WdfSynchronizationScopeDevice, will
EvtUsbTargetPipeReadComplete be synchronized with EvtIoRead?

Also, what if I set a WDM preprocess routine for read IRPs and then
deliver the IRP to the framework? Will the framework still grab the
lock before calling EvtIoRead?

I got a trace log where the execution of EvtIoRead and
EvtUsbTargetPipeReadComplete are being mixed. They are both accessing a
buffer at the same time – they both think the buffer has N bytes, so
they both drain N bytes, and the buffer ends up with N*2 bytes drained
out of it. Assuming I chose WdfSynchronizationScopeDevice, I thought
this was impossible.

Also, what pattern should I follow in my WDM preprocess callback for
read IRPs? Right now, it basically looks like this:

WdfObjectAcquireLock(Device);

if (certainCondition)
{
processIrpSynchronously(pIrp);
IoCompleteIrp(pIrp, IO_NO_INCREMENT);
WdfObjectReleaseLock(Device);
return pIrp->IoStatus.Status;
}
else
{
IoSkipCurrentIrpStackLocation(pIrp);
WdfObjectReleaseLock(Device);
return WdfDeviceWdmDispatchPreprocessedIrp(Device, pIrp);
}

Basically, under the assumption that KMDF would attempt to grab the
device-wide lock before calling EvtIoRead, I released it manually before
dispatching the IRP (to prevent a deadlock). Is this right?

-Chris


Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256

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

Doron Holan wrote:

Since there is no locking between the 2, this is very possible.
If you need to synchronize the 2, you either need to grab the
device lock in he completion routine or roll your own lock.
The danger of grabbing the lock in the completion routine is
if you are waiting for the usb pipe to fully drain while holding
the lock, you will deadlock.

Wait, what exactly do you mean by “waiting for the USB pipe to fully drain” while holding the lock?

You can’t really “wait” while holding a spinlock at all, can you?

Can this be avoided by having a special lock just for the driver’s buffer?

Also you are definitely right about the bug in the preprocess routine, actually we just saw that as well in Driver Verifier, we are going to clean it up.

If it is a spinlock, yes you can’t wait. Yes, this is fixed by having a lock with a finer granularity. Protecting only the buffer is probably the best answer.

d

Doron Holan wrote:

If it is a spinlock, yes you can’t wait. Yes, this is fixed by
having a lock with a finer granularity. Protecting only the
buffer is probably the best answer.

Ok, but the kind of “callback synchronization lock” used by WdfObjectAcquireLock() is a spinlock, right? Or not?

In other words, can I just grab my device-wide lock in the continuous reader callback, do a bunch of “immediate” stuff, and then release lock and exit the callback?

Or, (sorry but) what is meant by “waiting for [a] USB pipe to fully drain”? Is this related to stopping a continuous reader for example?

(Actually, that’s something I would potentially do, from a spawned work-item, inside the cont. reader callback…hmm. Maybe I really should just protect the buffer with a separate spinlock.)

> Ok, but the kind of “callback synchronization lock” used by
WdfObjectAcquireLock() is a spinlock, right? Or not?
By default, yes, unless you specify an execution level of passive.

In other words, can I just grab my device-wide lock in the continuous
reader callback, do a bunch of “immediate” stuff, and then release lock
and exit the callback?
Yes, probably. Never been tested though.

Or, (sorry but) what is meant by “waiting for [a] USB pipe to fully
drain”? Is this related to stopping a continuous reader for example?
Calling WdfIoTargetStop on the pipe configured with a contiguous reader.
If you do this from a work item (which has automatic sync set in its
config during create) or i/o callback, you will deadlock b/c the lock
will be held and then i/o can complete in the same thread and you will
attempt to acquire a lock which will never be released (b/c it is held
by the caller). If you create a work item which is not automatically
synchronized, you could stop the target from the work item.

I would protect the buffer with another lock. You don’t have to abandon
the device wide locking, just add additional locking around the buffer
management logic.

d

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of
xxxxx@gmail.com
Sent: Monday, April 30, 2007 10:07 PM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] Is EvtUsbTargetPipeReadComplete synchronized with
EvtIoRead?

Doron Holan wrote:

If it is a spinlock, yes you can’t wait. Yes, this is fixed by
having a lock with a finer granularity. Protecting only the
buffer is probably the best answer.

Ok, but the kind of “callback synchronization lock” used by
WdfObjectAcquireLock() is a spinlock, right? Or not?

In other words, can I just grab my device-wide lock in the continuous
reader callback, do a bunch of “immediate” stuff, and then release lock
and exit the callback?

Or, (sorry but) what is meant by “waiting for [a] USB pipe to fully
drain”? Is this related to stopping a continuous reader for example?

(Actually, that’s something I would potentially do, from a spawned
work-item, inside the cont. reader callback…hmm. Maybe I really
should just protect the buffer with a separate spinlock.)


Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256

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