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