Cancel pending Read in Bulk Transfer

Hi,

My USB driver has a bulk transfer pipe and I have a driver routine
to handle read command ‘IRP_MJ_READ’. I also set up a completion routine
using

" IoSetCompletionRoutine(Irp,
(PIO_COMPLETION_ROUTINE)BulkUsb_ReadWriteCompletion,
rwContext,
TRUE,
FALSE,
FALSE);
"

The IRP is passed to the lower layer using

"
ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject,
Irp);
"

Question is, when there is no data to be read from the USB device,
the completion routine never get called. And the IRP never gets completed.
The problem is at the user application, the call using “ReadFile()”
‘hangs’ the whole application.

How should I change it such that if there is no data from USB
device after a certain time (timeout period of say 100ms), the IRP is
cancelled and the IRP is “completed”.

Thanks.

Mark Sim

I assume you are also setting up the next stack location as well right? The irp should be cancelable when pended by the usb core (otherwise your driver would not be able to cancel it in the timer). When the app exits, the irp should be canceled as well by the i/o manager (you can put a break on address write on &Irp->Cancel to see when this happens, you can do this via “ba w1 ” in kd/windbg). Canceling a sent io from a timer involves handling the race where your timer fires and the irp is completing at the same time, walter oney’s book has a section on irp cancellation that shows you how to handle this race properly.

d

________________________________________
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of Mark Sim
Sent: Wednesday, November 30, 2005 12:45 AM
To: Windows System Software Devs Interest List
Subject: [ntdev] Cancel pending Read in Bulk Transfer

Hi,

? ? ? ? My USB driver has a bulk transfer pipe and I have a driver routine to handle read command ‘IRP_MJ_READ’. I also set up a completion routine using

" ? ?IoSetCompletionRoutine(Irp,
? ? ? ? ? ? ? ? ? ? ? ? ? ?(PIO_COMPLETION_ROUTINE)BulkUsb_ReadWriteCompletion,
? ? ? ? ? ? ? ? ? ? ? ? ? ?rwContext,
? ? ? ? ? ? ? ? ? ? ? ? ? ?TRUE,
? ? ? ? ? ? ? ? ? ? ? ? ? ?FALSE,
? ? ? ? ? ? ? ? ? ? ? ? ? ?FALSE);
"

? ? ? ? The IRP is passed to the lower layer using

"
? ? ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject,
? ? ? ? ? ? ? ? ? ? ? ? ? ? Irp);
"

? ? ? ? Question is, when there is no data to be read from the USB device, the completion routine never get called. And the IRP never gets completed. The problem is at the user application, the call using “ReadFile()” ‘hangs’ the whole application.

? ? ? ? How should I change it such that if there is no data from USB device after a certain time (timeout period of say 100ms), the IRP is cancelled and the IRP is “completed”.

? ? ? ? Thanks.

Mark Sim
— Questions? First check the Kernel Driver FAQ at http://www.osronline.com/article.cfm?id=256 You are currently subscribed to ntdev as: xxxxx@microsoft.com To unsubscribe send a blank email to xxxxx@lists.osr.com

Rise event in your completion routine.

Wait for this event with timeout in your read routine - something like this:

KeResetEvent(&deviceExtension->DoneEvent);
ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp );
waitStatus = KeWaitForSingleObject(&deviceExtension->DoneEvent,
Executive,
KernelMode,
FALSE,
&timeOut);
if (waitStatus == STATUS_TIMEOUT) {
KeResetEvent(&deviceExtension->DoneEvent);
IoCancelIrp(Irp);
KeWaitForSingleObject(&deviceExtension->DoneEvent,
Executive,
KernelMode,
FALSE,
NULL);
KeResetEvent(&deviceExtension->DoneEvent);
}

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com]On Behalf Of Mark Sim
Sent: Wednesday, November 30, 2005 10:45 AM
To: Windows System Software Devs Interest List
Subject: [ntdev] Cancel pending Read in Bulk Transfer

Hi,

My USB driver has a bulk transfer pipe and I have a driver routine to handle read command ‘IRP_MJ_READ’. I also set up a completion routine using

" IoSetCompletionRoutine(Irp,
(PIO_COMPLETION_ROUTINE)BulkUsb_ReadWriteCompletion,
rwContext,
TRUE,
FALSE,
FALSE);
"

The IRP is passed to the lower layer using

"
ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject,
Irp);
"

Question is, when there is no data to be read from the USB device, the completion routine never get called. And the IRP never gets completed. The problem is at the user application, the call using “ReadFile()” ‘hangs’ the whole application.

How should I change it such that if there is no data from USB device after a certain time (timeout period of say 100ms), the IRP is cancelled and the IRP is “completed”.

Thanks.

Mark Sim
— Questions? First check the Kernel Driver FAQ at http://www.osronline.com/article.cfm?id=256 You are currently subscribed to ntdev as: xxxxx@creo.com To unsubscribe send a blank email to xxxxx@lists.osr.com

There are several ways to do what you ask. However, that really isn’t the right solution.

If someone calls ReadFile, it is probably because they want data. If it can take a long time to get the data, and the user thread also has other things to do, then the user should be using an overlapped readfile request. This way the read will get posted, and when the data eventually shows up, it will be posted into the user’s buffer and they will be notified.

If you arbitrarily cancel the read IRP after some amount of time, the user will have to keep hanging the read over and over to try to get the data. This wastes system resources doing useless polling when polling isn’t required.

Worse, what if the user posted a 1024 byte buffer, and the unit just started sending data before your timeout occurred? What if there is already 64 or 128 bytes of data sent to the host? Now you kill the read and the user hangs a new one. The data received up to this point is lost! The new read will effectively start in the middle of the packet stream. If this is bulk data the user will have lost data unexpectedly, and will be out of sync with the stream. Not good.

The only time you should cancel the read IRP is if you receive a cancel or close request from an upper driver (or the user).

Loren

Rise event in your completion routine.

Wait for this event with timeout in your read routine - something like this:

KeResetEvent(&deviceExtension->DoneEvent);
ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp );
waitStatus = KeWaitForSingleObject(&deviceExtension->DoneEvent,
Executive,
KernelMode,
FALSE,
&timeOut);
if (waitStatus == STATUS_TIMEOUT) {
KeResetEvent(&deviceExtension->DoneEvent);
IoCancelIrp(Irp);
KeWaitForSingleObject(&deviceExtension->DoneEvent,
Executive,
KernelMode,
FALSE,
NULL);
KeResetEvent(&deviceExtension->DoneEvent);
}
-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com]On Behalf Of Mark Sim
Sent: Wednesday, November 30, 2005 10:45 AM
To: Windows System Software Devs Interest List
Subject: [ntdev] Cancel pending Read in Bulk Transfer

Hi,

My USB driver has a bulk transfer pipe and I have a driver routine to handle read command ‘IRP_MJ_READ’. I also set up a completion routine using

" IoSetCompletionRoutine(Irp,
(PIO_COMPLETION_ROUTINE)BulkUsb_ReadWriteCompletion,
rwContext,
TRUE,
FALSE,
FALSE);
"

The IRP is passed to the lower layer using

"
ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject,
Irp);
"

Question is, when there is no data to be read from the USB device, the completion routine never get called. And the IRP never gets completed. The problem is at the user application, the call using “ReadFile()” ‘hangs’ the whole application.

How should I change it such that if there is no data from USB device after a certain time (timeout period of say 100ms), the IRP is cancelled and the IRP is “completed”.

Thanks.

Mark Sim

Hi Loren,

If we leave the Read IRP pending, what happens to this pending IRP
if the USB device never provide any data for it to read. Will it get auto
canceled by the I/O manager after some time. If the driver can’t do
anything to this pending IRP, what happens if another Read IRP is received
by the driver? Will this queue of pending IRP grow?

Thanks.

It will wait forever till user app will close the handle or the device will
be detached.

Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
xxxxx@storagecraft.com
http://www.storagecraft.com

----- Original Message -----
From: “Mark Sim”
To: “Windows System Software Devs Interest List”
Sent: Wednesday, November 30, 2005 12:37 PM
Subject: Re: [ntdev] Cancel pending Read in Bulk Transfer

> Hi Loren,
>
> If we leave the Read IRP pending, what happens to this pending IRP
> if the USB device never provide any data for it to read. Will it get auto
> canceled by the I/O manager after some time. If the driver can’t do
> anything to this pending IRP, what happens if another Read IRP is received
> by the driver? Will this queue of pending IRP grow?
>
> Thanks.
>
> —
> Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256
>
> You are currently subscribed to ntdev as: xxxxx@storagecraft.com
> To unsubscribe send a blank email to xxxxx@lists.osr.com

> to handle read command ‘IRP_MJ_READ’. I also set up a completion routine

using

" IoSetCompletionRoutine(Irp,
(PIO_COMPLETION_ROUTINE)BulkUsb_ReadWriteCompletion,
rwContext,
TRUE,
FALSE,
FALSE);

Set TRUE, TRUE, TRUE here.

Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
xxxxx@storagecraft.com
http://www.storagecraft.com

Hi Alexander,

what happens if the Irp completes just in that moment you are calling
IoCancelIrp(Irp). Is the Irp canceled twice?
Is your code save?

Uwe

Alexander Krol wrote:

Rise event in your completion routine.

Wait for this event with timeout in your read routine - something like this:

KeResetEvent(&deviceExtension->DoneEvent);
ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp );
waitStatus = KeWaitForSingleObject(&deviceExtension->DoneEvent,
Executive,
KernelMode,
FALSE,
&timeOut);
if (waitStatus == STATUS_TIMEOUT) {
KeResetEvent(&deviceExtension->DoneEvent);
IoCancelIrp(Irp);
KeWaitForSingleObject(&deviceExtension->DoneEvent,
Executive,
KernelMode,
FALSE,
NULL);
KeResetEvent(&deviceExtension->DoneEvent);
}
-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com]On Behalf Of Mark Sim
Sent: Wednesday, November 30, 2005 10:45 AM
To: Windows System Software Devs Interest List
Subject: [ntdev] Cancel pending Read in Bulk Transfer

Hi,

My USB driver has a bulk transfer pipe and I have a driver routine to handle read command ‘IRP_MJ_READ’. I also set up a completion routine using

" IoSetCompletionRoutine(Irp,
(PIO_COMPLETION_ROUTINE)BulkUsb_ReadWriteCompletion,
rwContext,
TRUE,
FALSE,
FALSE);
"

The IRP is passed to the lower layer using

"
ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject,
Irp);
"

Question is, when there is no data to be read from the USB device, the completion routine never get called. And the IRP never gets completed. The problem is at the user application, the call using “ReadFile()” ‘hangs’ the whole application.

How should I change it such that if there is no data from USB device after a certain time (timeout period of say 100ms), the IRP is cancelled and the IRP is “completed”.

Thanks.

Mark Sim


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

You are currently subscribed to ntdev as: unknown lmsubst tag argument: ‘’
To unsubscribe send a blank email to xxxxx@lists.osr.com

Well, I think there are some bugs in that example, as well, but different
bugs. There is a potential race condition that could cause the second
KeWaitForSingleObject to never complete. If the first wait completes with
STATUS_TIMEOUT, then the IRP completes (and, I assume, the completion
routine set before IoCallDriver was called sets the event), then the
KeResetEvent function runs, then IoCancelIrp runs, then the second
KeWaitForSingleObject will wait forever, and no thread will ever set the
event.

A better solution would be:

NTSTATUS
CallDriverWithTimeoutCompletionRoutine(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context)
{
KeSetEvent((PKEVENT)Context, IO_NO_INCREMENT, FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
}

NTSTATUS
CallDriverWithTimeout(
IN PDEVICE_OBJECT LowerDeviceObject,
IN PIRP Irp,
IN LARGE_INTEGER Timeout)
{
KEVENT CompletionEvent;
NTSTATUS Status;

PAGED_CODE();

KeInitializeEvent(&CompletionEvent, SynchronizationEvent, FALSE);
IoSetCompletionRoutine(Irp, CallDriverWithTimeoutCompletionroutine,
&CompletionEvent, TRUE, TRUE, TRUE);
Status = IoCallDriver(LowerDeviceObject, Irp);

if (Status == STATUS_PENDING) {
Status = KeWaitForSingleObject(&CompletionEvent, Executive,
KernelMode, FALSE, &Timeout);
if (Status == STATUS_TIMEOUT) {
// We’ve given up on this IRP.
IoCancelIrp(Irp);

// Wait “forever” for completion, which should
happen “quickly”
KeWaitForSingleObject(&CompletionEvent, Executive,
KernelMode, FALSE, NULL);
}
Status = Irp->IoStatus.Status;
}

return Status;
}

You are guaranteed that the completion event will run, no matter whether the
IRP completes synchronously, asynchronously, or is cancelled. You are also
guaranteed that the lower driver has removed its cancellation routine
(Irp->CancelRoutine == NULL) before your completion routine begins. This
should safely deal with all of the completion/cancellation race conditions.

There is no need to reset the event; doing so exposes harmful race
conditions.

– arlie

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of uwe kirst
Sent: Wednesday, November 30, 2005 12:30 PM
To: Windows System Software Devs Interest List
Subject: Re: [ntdev] Cancel pending Read in Bulk Transfer

Hi Alexander,

what happens if the Irp completes just in that moment you are calling
IoCancelIrp(Irp). Is the Irp canceled twice?
Is your code save?

Uwe

Alexander Krol wrote:

Rise event in your completion routine.

Wait for this event with timeout in your read routine - something like
this:

KeResetEvent(&deviceExtension->DoneEvent);
ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp );
waitStatus = KeWaitForSingleObject(&deviceExtension->DoneEvent,
Executive,
KernelMode,
FALSE,
&timeOut);
if (waitStatus == STATUS_TIMEOUT) {
KeResetEvent(&deviceExtension->DoneEvent);
IoCancelIrp(Irp);
KeWaitForSingleObject(&deviceExtension->DoneEvent,
Executive,
KernelMode,
FALSE,
NULL);
KeResetEvent(&deviceExtension->DoneEvent);
}
-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com]On Behalf Of Mark Sim
Sent: Wednesday, November 30, 2005 10:45 AM
To: Windows System Software Devs Interest List
Subject: [ntdev] Cancel pending Read in Bulk Transfer

Hi,

My USB driver has a bulk transfer pipe and I have a driver
routine to handle read command ‘IRP_MJ_READ’. I also set up a
completion routine using

" IoSetCompletionRoutine(Irp,

(PIO_COMPLETION_ROUTINE)BulkUsb_ReadWriteCompletion,

rwContext,
TRUE,
FALSE,
FALSE);
"

The IRP is passed to the lower layer using

"
ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject,
Irp);
"

Question is, when there is no data to be read from the USB device,
the completion routine never get called. And the IRP never gets completed.
The problem is at the user application, the call using “ReadFile()” ‘hangs’
the whole application.

How should I change it such that if there is no data from USB
device after a certain time (timeout period of say 100ms), the IRP is
cancelled and the IRP is “completed”.

Thanks.

Mark Sim


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

You are currently subscribed to ntdev as: unknown lmsubst tag argument: ‘’
To unsubscribe send a blank email to xxxxx@lists.osr.com


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

You are currently subscribed to ntdev as: xxxxx@stonestreetone.com To
unsubscribe send a blank email to xxxxx@lists.osr.com

Note that this method will block the user mode application until the timeout has expired or the irp has completed. The whole point of asyn io is that the UM app’s thread will be free to do other things while the i/o sits in a queue somewhere.

d


From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of Alexander Krol
Sent: Wednesday, November 30, 2005 1:09 AM
To: Windows System Software Devs Interest List
Subject: RE: [ntdev] Cancel pending Read in Bulk Transfer

Rise event in your completion routine.
?
Wait for this event with timeout?in your read routine - something like this:
?
KeResetEvent(&deviceExtension->DoneEvent);
ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp );
waitStatus = KeWaitForSingleObject(&deviceExtension->DoneEvent,
??? Executive,
??? KernelMode,
??? FALSE,
??? &timeOut);
?if (waitStatus == STATUS_TIMEOUT) {
?? KeResetEvent(&deviceExtension->DoneEvent);
?? IoCancelIrp(Irp);
?? KeWaitForSingleObject(&deviceExtension->DoneEvent,
??? Executive,
??? KernelMode,
??? FALSE,
??? NULL);
?? KeResetEvent(&deviceExtension->DoneEvent);
?}
-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com]On Behalf Of Mark Sim
Sent: Wednesday, November 30, 2005 10:45 AM
To: Windows System Software Devs Interest List
Subject: [ntdev] Cancel pending Read in Bulk Transfer

Hi,

? ? ? ? My USB driver has a bulk transfer pipe and I have a driver routine to handle read command ‘IRP_MJ_READ’. I also set up a completion routine using

" ? ?IoSetCompletionRoutine(Irp,
? ? ? ? ? ? ? ? ? ? ? ? ? ?(PIO_COMPLETION_ROUTINE)BulkUsb_ReadWriteCompletion,
? ? ? ? ? ? ? ? ? ? ? ? ? ?rwContext,
? ? ? ? ? ? ? ? ? ? ? ? ? ?TRUE,
? ? ? ? ? ? ? ? ? ? ? ? ? ?FALSE,
? ? ? ? ? ? ? ? ? ? ? ? ? ?FALSE);
"

? ? ? ? The IRP is passed to the lower layer using

"
? ? ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject,
? ? ? ? ? ? ? ? ? ? ? ? ? ? Irp);
"

? ? ? ? Question is, when there is no data to be read from the USB device, the completion routine never get called. And the IRP never gets completed. The problem is at the user application, the call using “ReadFile()” ‘hangs’ the whole application.

? ? ? ? How should I change it such that if there is no data from USB device after a certain time (timeout period of say 100ms), the IRP is cancelled and the IRP is “completed”.

? ? ? ? Thanks.

Mark Sim
— Questions? First check the Kernel Driver FAQ at http://www.osronline.com/article.cfm?id=256 You are currently subscribed to ntdev as: xxxxx@creo.com To unsubscribe send a blank email to xxxxx@lists.osr.com


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

You are currently subscribed to ntdev as: unknown lmsubst tag argument: ‘’
To unsubscribe send a blank email to xxxxx@lists.osr.com

Sure, this is bad idea. Correct approach is to open device for overlapped access and handle timeouts at app level if necessary. Driver job is to blindly process requests and only app knows logic behind processed data so it is able to handle timeouts, retries etc. better. When timeout expires, app can call CancelIo() to cancel pending IRPs for current thread or close handle which in turns cancels all pending IRPs. USB function driver doesn’t need to care about IRP cancellation at all.

Best regards,

Michal Vodicka
UPEK, Inc.
[xxxxx@upek.com, http://www.upek.com]


From: xxxxx@lists.osr.com[SMTP:xxxxx@lists.osr.com] on behalf of Doron Holan[SMTP:xxxxx@microsoft.com]
Reply To: Windows System Software Devs Interest List
Sent: Wednesday, November 30, 2005 8:07 PM
To: Windows System Software Devs Interest List
Subject: RE: [ntdev] Cancel pending Read in Bulk Transfer

Note that this method will block the user mode application until the timeout has expired or the irp has completed. The whole point of asyn io is that the UM app’s thread will be free to do other things while the i/o sits in a queue somewhere.

d


From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of Alexander Krol
Sent: Wednesday, November 30, 2005 1:09 AM
To: Windows System Software Devs Interest List
Subject: RE: [ntdev] Cancel pending Read in Bulk Transfer

Rise event in your completion routine.

Wait for this event with timeout in your read routine - something like this:

KeResetEvent(&deviceExtension->DoneEvent);
ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp );
waitStatus = KeWaitForSingleObject(&deviceExtension->DoneEvent,
Executive,
KernelMode,
FALSE,
&timeOut);
if (waitStatus == STATUS_TIMEOUT) {
KeResetEvent(&deviceExtension->DoneEvent);
IoCancelIrp(Irp);
KeWaitForSingleObject(&deviceExtension->DoneEvent,
Executive,
KernelMode,
FALSE,
NULL);
KeResetEvent(&deviceExtension->DoneEvent);
}
-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com]On Behalf Of Mark Sim
Sent: Wednesday, November 30, 2005 10:45 AM
To: Windows System Software Devs Interest List
Subject: [ntdev] Cancel pending Read in Bulk Transfer

Hi,

My USB driver has a bulk transfer pipe and I have a driver routine to handle read command ‘IRP_MJ_READ’. I also set up a completion routine using

" IoSetCompletionRoutine(Irp,
(PIO_COMPLETION_ROUTINE)BulkUsb_ReadWriteCompletion,
rwContext,
TRUE,
FALSE,
FALSE);
"

The IRP is passed to the lower layer using

"
ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject,
Irp);
"

Question is, when there is no data to be read from the USB device, the completion routine never get called. And the IRP never gets completed. The problem is at the user application, the call using “ReadFile()” ‘hangs’ the whole application.

How should I change it such that if there is no data from USB device after a certain time (timeout period of say 100ms), the IRP is cancelled and the IRP is “completed”.

Thanks.

Mark Sim
— Questions? First check the Kernel Driver FAQ at http://www.osronline.com/article.cfm?id=256 You are currently subscribed to ntdev as: xxxxx@creo.com To unsubscribe send a blank email to xxxxx@lists.osr.com>


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

You are currently subscribed to ntdev as: unknown lmsubst tag argument: ‘’
To unsubscribe send a blank email to xxxxx@lists.osr.com


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

You are currently subscribed to ntdev as: unknown lmsubst tag argument: ‘’
To unsubscribe send a blank email to xxxxx@lists.osr.com

I agree with Doron about the need for asynchronous support - I’ve found that out first-hand.

I don’t know what flexibility you have in your driver design, what the app requirements are, or what communication protocol you have between your driver and the usb device, but here’s what I did in my driver.

  1. I submit a usb read request down to the bus driver for 4K bytes with the short transfer flag set
  2. When the request completes (IoCompletion) I stuff the data in a buffer
  3. Then I resubmit the request again (using a work item)
    Note that this read request happens independent of any apps calling ReadFile().

For the IRP_MJ_READ processing, I fetch the data directly out of the buffer. But because there might not be enough data in the buffer to fulfill request, the IRP might be pending on a cancel-safe queue. I use the timeout set by the app to decide when to walk the IRP queue and look for IRPs to cancel. Also, when data comes in (bulk in) I also try to fulfill any pending requests.

Before I added asynchronous support, I had the IRP_MJ_READ handler code return whatever data was available. So, if only part of the data was there, that’s is what it would return. But, the performance sucks doing that, especially if you had the app code sitting in loop doing a ReadFile() + Sleep (to give the buffer time to get filled) until it got all the data it wanted.

Sharon
----- Original Message -----
From: Doron Holanmailto:xxxxx
To: Windows System Software Devs Interest Listmailto:xxxxx
Sent: Wednesday, November 30, 2005 11:07 AM
Subject: RE: [ntdev] Cancel pending Read in Bulk Transfer

Note that this method will block the user mode application until the timeout has expired or the irp has completed. The whole point of asyn io is that the UM app’s thread will be free to do other things while the i/o sits in a queue somewhere.

d

________________________________________
From: xxxxx@lists.osr.commailto:xxxxx [mailto:xxxxx@lists.osr.com] On Behalf Of Alexander Krol
Sent: Wednesday, November 30, 2005 1:09 AM
To: Windows System Software Devs Interest List
Subject: RE: [ntdev] Cancel pending Read in Bulk Transfer

Rise event in your completion routine.

Wait for this event with timeout in your read routine - something like this:

KeResetEvent(&deviceExtension->DoneEvent);
ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp );
waitStatus = KeWaitForSingleObject(&deviceExtension->DoneEvent,
Executive,
KernelMode,
FALSE,
&timeOut);
if (waitStatus == STATUS_TIMEOUT) {
KeResetEvent(&deviceExtension->DoneEvent);
IoCancelIrp(Irp);
KeWaitForSingleObject(&deviceExtension->DoneEvent,
Executive,
KernelMode,
FALSE,
NULL);
KeResetEvent(&deviceExtension->DoneEvent);
}
-----Original Message-----
From: xxxxx@lists.osr.commailto:xxxxx [mailto:xxxxx@lists.osr.com]On Behalf Of Mark Sim
Sent: Wednesday, November 30, 2005 10:45 AM
To: Windows System Software Devs Interest List
Subject: [ntdev] Cancel pending Read in Bulk Transfer

Hi,

My USB driver has a bulk transfer pipe and I have a driver routine to handle read command ‘IRP_MJ_READ’. I also set up a completion routine using

" IoSetCompletionRoutine(Irp,
(PIO_COMPLETION_ROUTINE)BulkUsb_ReadWriteCompletion,
rwContext,
TRUE,
FALSE,
FALSE);
"

The IRP is passed to the lower layer using

"
ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject,
Irp);
"

Question is, when there is no data to be read from the USB device, the completion routine never get called. And the IRP never gets completed. The problem is at the user application, the call using “ReadFile()” ‘hangs’ the whole application.

How should I change it such that if there is no data from USB device after a certain time (timeout period of say 100ms), the IRP is cancelled and the IRP is “completed”.

Thanks.

Mark Sim
— Questions? First check the Kernel Driver FAQ at http://www.osronline.com/article.cfm?id=256http: You are currently subscribed to ntdev as: xxxxx@creo.commailto:xxxxx To unsubscribe send a blank email to xxxxx@lists.osr.commailto:xxxxx


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

You are currently subscribed to ntdev as: unknown lmsubst tag argument: ‘’
To unsubscribe send a blank email to xxxxx@lists.osr.commailto:xxxxx


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

You are currently subscribed to ntdev as: unknown lmsubst tag argument: ‘’
To unsubscribe send a blank email to xxxxx@lists.osr.commailto:xxxxx</mailto:xxxxx></http:></mailto:xxxxx></http:></mailto:xxxxx></mailto:xxxxx></http:></mailto:xxxxx></mailto:xxxxx></mailto:xxxxx></mailto:xxxxx>

Hello,

Does anyone know a solution to this problem where you do not have wait
for the IRP to complete?
It would be nice to be able cancel the IRP from another thread at any time.

This behaviour is needed in my case, because my driver should handle a
“dropout” situation which is detected by hardware.
Uwe

Arlie Davis wrote:

Well, I think there are some bugs in that example, as well, but different
bugs. There is a potential race condition that could cause the second
KeWaitForSingleObject to never complete. If the first wait completes with
STATUS_TIMEOUT, then the IRP completes (and, I assume, the completion
routine set before IoCallDriver was called sets the event), then the
KeResetEvent function runs, then IoCancelIrp runs, then the second
KeWaitForSingleObject will wait forever, and no thread will ever set the
event.

A better solution would be:

NTSTATUS
CallDriverWithTimeoutCompletionRoutine(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context)
{
KeSetEvent((PKEVENT)Context, IO_NO_INCREMENT, FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
}

NTSTATUS
CallDriverWithTimeout(
IN PDEVICE_OBJECT LowerDeviceObject,
IN PIRP Irp,
IN LARGE_INTEGER Timeout)
{
KEVENT CompletionEvent;
NTSTATUS Status;

PAGED_CODE();

KeInitializeEvent(&CompletionEvent, SynchronizationEvent, FALSE);
IoSetCompletionRoutine(Irp, CallDriverWithTimeoutCompletionroutine,
&CompletionEvent, TRUE, TRUE, TRUE);
Status = IoCallDriver(LowerDeviceObject, Irp);

if (Status == STATUS_PENDING) {
Status = KeWaitForSingleObject(&CompletionEvent, Executive,
KernelMode, FALSE, &Timeout);
if (Status == STATUS_TIMEOUT) {
// We’ve given up on this IRP.
IoCancelIrp(Irp);

// Wait “forever” for completion, which should
happen “quickly”
KeWaitForSingleObject(&CompletionEvent, Executive,
KernelMode, FALSE, NULL);
}
Status = Irp->IoStatus.Status;
}

return Status;
}

You are guaranteed that the completion event will run, no matter whether the
IRP completes synchronously, asynchronously, or is cancelled. You are also
guaranteed that the lower driver has removed its cancellation routine
(Irp->CancelRoutine == NULL) before your completion routine begins. This
should safely deal with all of the completion/cancellation race conditions.

There is no need to reset the event; doing so exposes harmful race
conditions.

– arlie

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of uwe kirst
Sent: Wednesday, November 30, 2005 12:30 PM
To: Windows System Software Devs Interest List
Subject: Re: [ntdev] Cancel pending Read in Bulk Transfer

Hi Alexander,

what happens if the Irp completes just in that moment you are calling
IoCancelIrp(Irp). Is the Irp canceled twice?
Is your code save?

Uwe

Alexander Krol wrote:

>Rise event in your completion routine.
>
>Wait for this event with timeout in your read routine - something like
>
>
this:

>KeResetEvent(&deviceExtension->DoneEvent);
>ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp );
>waitStatus = KeWaitForSingleObject(&deviceExtension->DoneEvent,
> Executive,
> KernelMode,
> FALSE,
> &timeOut);
>if (waitStatus == STATUS_TIMEOUT) {
> KeResetEvent(&deviceExtension->DoneEvent);
> IoCancelIrp(Irp);
> KeWaitForSingleObject(&deviceExtension->DoneEvent,
> Executive,
> KernelMode,
> FALSE,
> NULL);
> KeResetEvent(&deviceExtension->DoneEvent);
>}
>-----Original Message-----
>From: xxxxx@lists.osr.com
>[mailto:xxxxx@lists.osr.com]On Behalf Of Mark Sim
>Sent: Wednesday, November 30, 2005 10:45 AM
>To: Windows System Software Devs Interest List
>Subject: [ntdev] Cancel pending Read in Bulk Transfer
>
>
>
>Hi,
>
> My USB driver has a bulk transfer pipe and I have a driver
>routine to handle read command ‘IRP_MJ_READ’. I also set up a
>completion routine using
>
>
>" IoSetCompletionRoutine(Irp,
>
>
>
(PIO_COMPLETION_ROUTINE)BulkUsb_ReadWriteCompletion,

> rwContext,
> TRUE,
> FALSE,
> FALSE);
>"
>
> The IRP is passed to the lower layer using
>
>"
> ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject,
> Irp);
>"
>
> Question is, when there is no data to be read from the USB device,
>
>
the completion routine never get called. And the IRP never gets completed.
The problem is at the user application, the call using “ReadFile()” ‘hangs’
the whole application.

> How should I change it such that if there is no data from USB
>
>
device after a certain time (timeout period of say 100ms), the IRP is
cancelled and the IRP is “completed”.

> Thanks.
>
>Mark Sim
>
>
>—
>Questions? First check the Kernel Driver FAQ at
>http://www.osronline.com/article.cfm?id=256
>
>You are currently subscribed to ntdev as: unknown lmsubst tag argument: ‘’
>To unsubscribe send a blank email to xxxxx@lists.osr.com
>
>
>
>
>
>


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

You are currently subscribed to ntdev as: xxxxx@stonestreetone.com To
unsubscribe send a blank email to xxxxx@lists.osr.com


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

You are currently subscribed to ntdev as: xxxxx@gmx.de
To unsubscribe send a blank email to xxxxx@lists.osr.com

Can you clarify what you mean? You always have to “wait”, in some form or
another, for the IRP to complete. “Waiting” may mean literally waiting on
an event object, or dequeuing an I/O completion packet from an I/O
completion port, or simply being called in your completion routine.

You CAN cancel the IRP from another thread at any time. That’s what
IoCancelIrp does. You do need to be careful using this routine, though.
You need to make sure that you properly handle all race conditions. You
need to make sure that the IRP will not “go away” (either be deleted or
completed and sent to the next-higher completion routine) while you are
making the call to IoCancelIrp.

How you do this differs slightly, depending on whether you are the initiator
of the IRP (IoAllocateIrp or similar) or whether you are received it on a
dispatch routine.

Correct IRP cancellation is one of the trickier aspects of NT’s asynchronous
I/O model.

– arlie

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of uwe kirst
Sent: Thursday, December 01, 2005 7:45 AM
To: Windows System Software Devs Interest List
Subject: Re: [ntdev] Cancel pending Read in Bulk Transfer

Hello,

Does anyone know a solution to this problem where you do not have wait for
the IRP to complete?
It would be nice to be able cancel the IRP from another thread at any time.

This behaviour is needed in my case, because my driver should handle a
“dropout” situation which is detected by hardware.
Uwe

Arlie Davis wrote:

Can you clarify what you mean? You always have to “wait”, in some form or
another, for the IRP to complete. “Waiting” may mean literally waiting on
an event object, or dequeuing an I/O completion packet from an I/O
completion port, or simply being called in your completion routine.

You CAN cancel the IRP from another thread at any time. That’s what
IoCancelIrp does.

HOWEVER, IoCancelIrp is, more or less, only a suggestion. It sets a
flag that politely requests that the IRP be cancelled. If the driver
that currently holds the IRP doesn’t check for this, the IRP will not
actually be cancelled.


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

That is correct, there is nothing you can do about the irp in that case
though. If the driver which is holding onto the irp does so for a very
long time, that is a bug in the driver. IoCancelIrp is what the io
manager uses to cancel io, there is no magical secret sauce that has
more definitive cancellation results.

d

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Tim Roberts
Sent: Thursday, December 01, 2005 9:12 AM
To: Windows System Software Devs Interest List
Subject: Re: [ntdev] Cancel pending Read in Bulk Transfer

Arlie Davis wrote:

Can you clarify what you mean? You always have to “wait”, in some form
or
another, for the IRP to complete. “Waiting” may mean literally waiting
on
an event object, or dequeuing an I/O completion packet from an I/O
completion port, or simply being called in your completion routine.

You CAN cancel the IRP from another thread at any time. That’s what
IoCancelIrp does.

HOWEVER, IoCancelIrp is, more or less, only a suggestion. It sets a
flag that politely requests that the IRP be cancelled. If the driver
that currently holds the IRP doesn’t check for this, the IRP will not
actually be cancelled.


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


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

You are currently subscribed to ntdev as: xxxxx@microsoft.com
To unsubscribe send a blank email to xxxxx@lists.osr.com

I’m having an driver internal IRP queue,
IRPs are allocated via IoAllocateIrp,
they are deleted in my completion routine (my driver “waits” here),
but I’m still haven’t solved the race condition yet which cases BSODs
from time to time.
I did some reading in Walter Oneys book and know I’ think I have to add
another spin lock.
I will try to:
-acquire the spin lock before the call of IoCallDriver()
-release the spin lock in my completion routine
That may help to prevent my Irp from being completed twice, wouldn’t it?

Uwe

Arlie Davis wrote:

Can you clarify what you mean? You always have to “wait”, in some form or
another, for the IRP to complete. “Waiting” may mean literally waiting on
an event object, or dequeuing an I/O completion packet from an I/O
completion port, or simply being called in your completion routine.

You CAN cancel the IRP from another thread at any time. That’s what
IoCancelIrp does. You do need to be careful using this routine, though.
You need to make sure that you properly handle all race conditions. You
need to make sure that the IRP will not “go away” (either be deleted or
completed and sent to the next-higher completion routine) while you are
making the call to IoCancelIrp.

How you do this differs slightly, depending on whether you are the initiator
of the IRP (IoAllocateIrp or similar) or whether you are received it on a
dispatch routine.

Correct IRP cancellation is one of the trickier aspects of NT’s asynchronous
I/O model.

– arlie

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of uwe kirst
Sent: Thursday, December 01, 2005 7:45 AM
To: Windows System Software Devs Interest List
Subject: Re: [ntdev] Cancel pending Read in Bulk Transfer

Hello,

Does anyone know a solution to this problem where you do not have wait for
the IRP to complete?
It would be nice to be able cancel the IRP from another thread at any time.

This behaviour is needed in my case, because my driver should handle a
“dropout” situation which is detected by hardware.
Uwe


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

You are currently subscribed to ntdev as: xxxxx@gmx.de
To unsubscribe send a blank email to xxxxx@lists.osr.com

> Correct IRP cancellation is one of the trickier aspects of NT’s asynchronous

I/O model.

The main 2 issues - which cover all this “trickiest” thing - are:

  • IoCancelIrp can be called racing with putting the IRP to the pending state
    (queue or global variable).
  • IoCancelIrp can be called racing with the IRP “consumption” from this queue
    or the global variable

The IoCancelIrp pseudocode is here:

BOOLEAN IoCancelIrp(PIRP Irp)
{
KIRQL Irql;
PIO_CANCEL_ROUTINE Routine;
IoAcquireCancelSpinLock(&Irql);
Irp->Cancel = TRUE;
Routine = IoSetCancelRoutine(Irp, NULL);
if( Routine == NULL )
{
// Not cancellable
IoReleaseCancelSpinLock(Irql);
return FALSE;
}
Irp->CancelIrql = Irql;
(Routine)(IoGetCurrentIrpStackLocation(Irp)->DeviceObject, Irp);
return TRUE;
}

Walter Oney made a very good description of IRP cancellation logic in his book.

Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
xxxxx@storagecraft.com
http://www.storagecraft.com

> HOWEVER, IoCancelIrp is, more or less, only a suggestion. It sets a

flag that politely requests that the IRP be cancelled. If the driver

It also removes the cancel routine from the IRP (if any) and calls it (if any).

Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
xxxxx@storagecraft.com
http://www.storagecraft.com