Cancelling an Irp

Hello all developers,

I have a following problem with canceling
my own Irps which I’m sending to the USB
device stack:

I send and Irp and if the returned status from
IoCallDriver is STATUS_PENDING, I have to wait
for the completion. I’m the owner of the Irp and
I have set a completion routine on it to set
some event on which I’m waiting - so I’m the one
who ensures that the Irp will not be completed
unexpectedly and it remains valid until I free it.

The wait after pending has been returned has timeout
value specified and if the wait times out, I want to
cancel the Irp and return - which is logical, I think ;-).

I’m using the following code to cancel my Irps:

VOID
XxxCancelUrbIrp (
IN PIRP Irp,
IN PKEVENT Event
)
{
LARGE_INTEGER CancelTimeout;
NTSTATUS Status;
BOOLEAN Cancelled;

Cancelled = IoCancelIrp(Irp);

//BUGBUG: what time should we set here?
CancelTimeout.QuadPart = -50*1000*10; //50 ms for now

Status = KeWaitForSingleObject(Event, Executive, KernelMode, FALSE,
&CancelTimeout);
ASSERT(Status == STATUS_WAIT_0);

if (Cancelled)
{
ASSERT(Irp->IoStatus.Status == STATUS_IO_TIMEOUT);
ASSERT(!Irp->Cancel);
}

else
{
ASSERT(Irp->IoStatus.Status != STATUS_PENDING);
ASSERT(Irp->Cancel);
Irp->Cancel = FALSE;
}
}

But sometimes the first assertion fails and then also
the following ones. The wait returns status of STATUS_TIMEOUT,
which means that the Irp is still not completed after
50 milliseconds. Then the result will be unpredictable, because
the Irp is reused for something else and it can be
still pending.

So, what is the proper way to ensure that the Irp will
be completed by the lower level components in some short
time after I cancel it?

Maybe someone at Microsoft who has written the USBD.SYS knows
some issues for canceling the Irps sent to it.

Thank you very much for your help,
it’s the first time I really need it on this list :wink:

Paul

PS: You might argue how can I assert some status and not set the
cancel flag… Of course this behaviour is ensured in my completion
routine ;-))

The other case is when I tried to cancel already completed Irp (or
at least I think the Irp must be already completed because it had no
completion routine at the cancel time).


You are currently subscribed to ntdev as: $subst(‘Recip.EmailAddr’)
To unsubscribe send a blank email to leave-ntdev-$subst(‘Recip.MemberIDChar’)@lists.osr.com

I don’t think you can assign an arbitrary time here and just hope that
the lower driver will manage to complete your irp. When the iomanager,
for example, does its generic thread-termination irp cancelling, I think
it waits five minutes for the irps to complete, and then assigns the
tardy (or perhaps retarded,) irps to a loser queue in case they ever
manage to complete.

The usb stack does deal with cancellation of at least some irps
correctly, as the various polling-based usb input devices always park an
irp with the bus driver for the next io request, and have to cancel that
irp if somebody unplugs the device.

Perhaps it would be better to just call IoCancelIrp and let your
completion handler deal with the irps as they complete, if they ever
complete, and not worry about the ones that don’t?

=====================
Mark Roddy
Windows XP/2000/NT Consulting
Hollis Technology Solutions 603-321-1032
www.hollistech.com
xxxxx@hollistech.com
For Windows Device Driver Training: see www.azius.com

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@compelson.com
Sent: Monday, January 28, 2002 1:10 PM
To: NT Developers Interest List
Subject: [ntdev] Cancelling an Irp

Hello all developers,

I have a following problem with canceling
my own Irps which I’m sending to the USB
device stack:

I send and Irp and if the returned status from
IoCallDriver is STATUS_PENDING, I have to wait
for the completion. I’m the owner of the Irp and
I have set a completion routine on it to set
some event on which I’m waiting - so I’m the one
who ensures that the Irp will not be completed
unexpectedly and it remains valid until I free it.

The wait after pending has been returned has timeout
value specified and if the wait times out, I want to
cancel the Irp and return - which is logical, I think ;-).

I’m using the following code to cancel my Irps:

VOID
XxxCancelUrbIrp (
IN PIRP Irp,
IN PKEVENT Event
)
{
LARGE_INTEGER CancelTimeout;
NTSTATUS Status;
BOOLEAN Cancelled;

Cancelled = IoCancelIrp(Irp);

//BUGBUG: what time should we set here?
CancelTimeout.QuadPart = -50*1000*10; //50 ms for now

Status = KeWaitForSingleObject(Event, Executive, KernelMode, FALSE,
&CancelTimeout);
ASSERT(Status == STATUS_WAIT_0);

if (Cancelled)
{
ASSERT(Irp->IoStatus.Status == STATUS_IO_TIMEOUT);
ASSERT(!Irp->Cancel);
}

else
{
ASSERT(Irp->IoStatus.Status != STATUS_PENDING);
ASSERT(Irp->Cancel);
Irp->Cancel = FALSE;
}
}

But sometimes the first assertion fails and then also
the following ones. The wait returns status of STATUS_TIMEOUT, which
means that the Irp is still not completed after 50 milliseconds. Then
the result will be unpredictable, because the Irp is reused for
something else and it can be still pending.

So, what is the proper way to ensure that the Irp will
be completed by the lower level components in some short
time after I cancel it?

Maybe someone at Microsoft who has written the USBD.SYS knows some
issues for canceling the Irps sent to it.

Thank you very much for your help,
it’s the first time I really need it on this list :wink:

Paul

PS: You might argue how can I assert some status and not set the
cancel flag… Of course this behaviour is ensured in my completion
routine ;-))

The other case is when I tried to cancel already completed Irp (or
at least I think the Irp must be already completed because it had no
completion routine at the cancel time).


You are currently subscribed to ntdev as: xxxxx@hollistech.com To
unsubscribe send a blank email to leave-ntdev-$subst(‘Recip.MemberIDChar’)@lists.osr.com


You are currently subscribed to ntdev as: $subst(‘Recip.EmailAddr’)
To unsubscribe send a blank email to leave-ntdev-$subst(‘Recip.MemberIDChar’)@lists.osr.com

Mark, thank you for your answer.

Yes, you’re right, it can be done by ignoring those
requests which can’t be canceled in some short
time and let them to do “anything they want to do” :-))
but there is one problem: I use only one Irp because
I can send only one request down at the same time -
thus not needing still allocate and free Irps. One only
Irp is enough for me… Except the case when the Irp
can’t be cancelled quickly. Then it would be better to
forget this Irp and allocate a new one (and also mark
the current as non-active and thus force my completion
routine to free it on eventual completion).

But I want to know if the is some better solution before
I implement this kind of “optimization”.

Paul

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com]On Behalf Of Mark Roddy
Sent: Monday, January 28, 2002 7:51 PM
To: NT Developers Interest List
Subject: [ntdev] RE: Cancelling an Irp

I don’t think you can assign an arbitrary time here and just hope that
the lower driver will manage to complete your irp. When the iomanager,
for example, does its generic thread-termination irp cancelling, I think
it waits five minutes for the irps to complete, and then assigns the
tardy (or perhaps retarded,) irps to a loser queue in case they ever
manage to complete.

The usb stack does deal with cancellation of at least some irps
correctly, as the various polling-based usb input devices always park an
irp with the bus driver for the next io request, and have to cancel that
irp if somebody unplugs the device.

Perhaps it would be better to just call IoCancelIrp and let your
completion handler deal with the irps as they complete, if they ever
complete, and not worry about the ones that don’t?

=====================
Mark Roddy
Windows XP/2000/NT Consulting
Hollis Technology Solutions 603-321-1032
www.hollistech.com
xxxxx@hollistech.com
For Windows Device Driver Training: see www.azius.com

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@compelson.com
Sent: Monday, January 28, 2002 1:10 PM
To: NT Developers Interest List
Subject: [ntdev] Cancelling an Irp

Hello all developers,

I have a following problem with canceling
my own Irps which I’m sending to the USB
device stack:

I send and Irp and if the returned status from
IoCallDriver is STATUS_PENDING, I have to wait
for the completion. I’m the owner of the Irp and
I have set a completion routine on it to set
some event on which I’m waiting - so I’m the one
who ensures that the Irp will not be completed
unexpectedly and it remains valid until I free it.

The wait after pending has been returned has timeout
value specified and if the wait times out, I want to
cancel the Irp and return - which is logical, I think ;-).

I’m using the following code to cancel my Irps:

VOID
XxxCancelUrbIrp (
IN PIRP Irp,
IN PKEVENT Event
)
{
LARGE_INTEGER CancelTimeout;
NTSTATUS Status;
BOOLEAN Cancelled;

Cancelled = IoCancelIrp(Irp);

//BUGBUG: what time should we set here?
CancelTimeout.QuadPart = -50*1000*10; //50 ms for now

Status = KeWaitForSingleObject(Event, Executive, KernelMode, FALSE,
&CancelTimeout);
ASSERT(Status == STATUS_WAIT_0);

if (Cancelled)
{
ASSERT(Irp->IoStatus.Status == STATUS_IO_TIMEOUT);
ASSERT(!Irp->Cancel);
}

else
{
ASSERT(Irp->IoStatus.Status != STATUS_PENDING);
ASSERT(Irp->Cancel);
Irp->Cancel = FALSE;
}
}

But sometimes the first assertion fails and then also
the following ones. The wait returns status of STATUS_TIMEOUT, which
means that the Irp is still not completed after 50 milliseconds. Then
the result will be unpredictable, because the Irp is reused for
something else and it can be still pending.

So, what is the proper way to ensure that the Irp will
be completed by the lower level components in some short
time after I cancel it?

Maybe someone at Microsoft who has written the USBD.SYS knows some
issues for canceling the Irps sent to it.

Thank you very much for your help,
it’s the first time I really need it on this list :wink:

Paul

PS: You might argue how can I assert some status and not set the
cancel flag… Of course this behaviour is ensured in my completion
routine ;-))

The other case is when I tried to cancel already completed Irp (or
at least I think the Irp must be already completed because it had no
completion routine at the cancel time).


You are currently subscribed to ntdev as: xxxxx@hollistech.com To
unsubscribe send a blank email to leave-ntdev-$subst(‘Recip.MemberIDChar’)@lists.osr.com


You are currently subscribed to ntdev as: xxxxx@compelson.com
To unsubscribe send a blank email to leave-ntdev-$subst(‘Recip.MemberIDChar’)@lists.osr.com


You are currently subscribed to ntdev as: $subst(‘Recip.EmailAddr’)
To unsubscribe send a blank email to leave-ntdev-$subst(‘Recip.MemberIDChar’)@lists.osr.com

> But sometimes the first assertion fails and then also

the following ones. The wait returns status of STATUS_TIMEOUT,
which means that the Irp is still not completed after
50 milliseconds. Then the result will be unpredictable, because
the Irp is reused for something else and it can be
still pending.

This is OK.

IoCancelIrp does not guarantee anything. The IRP can even fail to cancel, and in this case you will need to wait till it will be
completed usually. This can take more than 50ms.
Usually, the IRP cannot be cancelled if it is already known to the hardware. I don’t know how UHCD driver works, but, given the
knowlegde of UHCI spec, it is very possible that UHCD implementors do not support cancelling of the IRPs which are already mapped to
the controller’s schedule.

Do not rely on 50ms timeout. Set the infinite timeout.

Max


You are currently subscribed to ntdev as: $subst(‘Recip.EmailAddr’)
To unsubscribe send a blank email to leave-ntdev-$subst(‘Recip.MemberIDChar’)@lists.osr.com

When you are calling IoCancelIrp(), you are saying the following:

  • I promise the IRP will not be completed and free while IoCancelIrp is being called.
  • A lower level driver is now allowed to return a status of STATUS_CANCELLED if it pleases.
  • The lower level driver may no longer hold the IRP indefinitely. The definition of “indefinitely” is up to the lower level
    driver.
  • I don’t mind if the IRP is returned successfully a while from now.

The main purpose of cancel is to get the IRP back if say you are reading from a serial line or a keyboard.

The original NDIS packet driver sample did not support cancel, perhaps on the theory that there will always be packets arriving
on the network. This was a bug when the network was idle, i.e., you replaces a hub with a switch.

Many people would argue that you don’t need to cancel IRPs to disk drives, because those IRPs are not indefinite. However the
ATA standard says a disk can take 30 seconds and still be in spec (and I’ve seen 18-19 seconds on one drive as it worked its way
through a bad spot).

Anyway, deciding to put your own time constraint on lower level drivers you don’t control is a bad idea.

-DH
----- Original Message -----
From: “Maxim S. Shatskih”
To: “NT Developers Interest List”
Sent: Monday, January 28, 2002 5:30 PM
Subject: [ntdev] Re: Cancelling an Irp

> > But sometimes the first assertion fails and then also
> > the following ones. The wait returns status of STATUS_TIMEOUT,
> > which means that the Irp is still not completed after
> > 50 milliseconds. Then the result will be unpredictable, because
> > the Irp is reused for something else and it can be
> > still pending.
>
> This is OK.
>
> IoCancelIrp does not guarantee anything. The IRP can even fail to cancel, and in this case you will need to wait till it will
be
> completed usually. This can take more than 50ms.
> Usually, the IRP cannot be cancelled if it is already known to the hardware. I don’t know how UHCD driver works, but, given
the
> knowlegde of UHCI spec, it is very possible that UHCD implementors do not support cancelling of the IRPs which are already
mapped to
> the controller’s schedule.
>
> Do not rely on 50ms timeout. Set the infinite timeout.
>
> Max
>
>
>
> —
> You are currently subscribed to ntdev as: xxxxx@syssoftsol.com
> To unsubscribe send a blank email to leave-ntdev-$subst(‘Recip.MemberIDChar’)@lists.osr.com


You are currently subscribed to ntdev as: $subst(‘Recip.EmailAddr’)
To unsubscribe send a blank email to leave-ntdev-$subst(‘Recip.MemberIDChar’)@lists.osr.com