Handling cancel request in Driver

Hi,
I have a confusion regarding WdfRequestMarkCancelable. MSDN doc says when driver receives(and own) IO request, Driver should invoke this function with another callback. This call back shall be invoked by WDF framework when IO manager or another driver cancel this request. Inside this callback request can be cancelled.

But it is mentioned about another approach of using EvtWdfIoQueueIoCanceledOnQueue for handling cancelled request.

Which one should be used in driver?

Handling cancel can be tough. The easiest way is to simply hold your Requests on a WDFQUEUE, where they will automatically be cancelled. If you don’t need to KNOW about the cancellation (entirely plausible in many drivers) you do not need a Canceled On Queue event processing callback.

If you must handle cancel (and it’s only necessary when your holding Requests for a long or indeterminate amount of time), and you are NOT holding them on a WDFQUEUE, you can use WdfRequestMarkCanceable. But it’s not simple to implement. Opportunities for race conditions abound.

You might want to read this, from the OSR Learning Library: https://www.osr.com/nt-insider/2017-issue2/handling-cleanup-close-cancel-wdf-driver/

Peter

1 Like

But it’s not simple to implement.

Amen to that. I did a telemetry driver for a company last year, where I thought I couldn’t use a WDFQUEUE and tried WdfRequestMarkCancelable with a WDFCOLLECTION. That worked great until they upgraded to two simultaneous and continuous data streams. Every 2 1/2 days or so, it would suddenly stop communicating. Turned out to be a complicated interaction between multiple requests completing in the wrong order. I went back to a WDFQUEUE and now everyone is happy.

Regression testing is painful when a problem only happens twice a week.

1 Like

Add to that the fact that inserting into a WDFCOLLECTION allocates, so your inserts can fail. Yeah… glad you could make the Queue work.

Peter

@“Peter_Viscarola_(OSR)” said:
Handling cancel can be tough. The easiest way is to simply hold your Requests on a WDFQUEUE, where they will automatically be cancelled. If you don’t need to KNOW about the cancellation (entirely plausible in many drivers) you do not need a Canceled On Queue event processing callback.

If you must handle cancel (and it’s only necessary when your holding Requests for a long or indeterminate amount of time), and you are NOT holding them on a WDFQUEUE, you can use WdfRequestMarkCanceable. But it’s not simple to implement. Opportunities for race conditions abound.

You might want to read this, from the OSR Learning Library: https://www.osr.com/nt-insider/2017-issue2/handling-cleanup-close-cancel-wdf-driver/

Peter

Thanks!
Would the requests put into a manual queue (moved to manual queue on some scenario e.g. no data while read request came) shall be automatically cancelled? Or this is applicable to auto dispatching queue.

Requests that are on any type of WDFQUEUE are automatically cancelled. The Queue’s Dispatch Type (Parallel, Sequential, or Manual) doesn’t matter.

Peter

1 Like

General guidance on this should be don’t support cancelation at all, or use the KMDF cancelation support. I know how to do it correctly ‘manually’ aka the old way, but this is still the rule I work by.

Operations that don’t access hardware, don’t switch thread context or can’t effectively be cancelled once initiated should just not support cancel at all. For example if your driver synchronously computes the next 100 digits of PI from a previous estimate, then there is no need to even attempt to support cancel. But if you driver has sent and async command to read the next 100 blocks off of a SAN volume via an MPIO provider, where a cancel command exists, cancel should be supported and a cancel command sent - understanding that cancel might be sent after the whole command has completed

1 Like

Ok Thanks!

General guidance on this should be don’t support cancelation at al

Sorry… but we have to add add a caveat or two to that before we can really call it “general guidance.” But I agree with Mr. Bond that in many, many, cases you can get by without cancel entirely.

Best practice is to support cancel when you holding Requests in your driver for a long or indeterminate amount of time. Even a software-only driver that holds Requests on a Queue until some other event occurs needs to support cancel, if those events it’s waiting for aren’t guaranteed to come “quickly.” There are other times when you need to support cancel as well up such as when the consequences of allowing the operation to proceed outweigh the complexity of the cancelation (you probably want to allow cancellation of the “launch missile” IOCTL right up until the last millisecond).

For a long time, back in the days of WDM, too few people implemented cancel support. The result was a lot of threads that hung on exit or termination, waiting for their I/O to complete.

Then MSFT strongly emphasized cancel. And everybody through they should ALWAYS implement cancel. This is wrong and leads to nothing but bugs.

Peter

Peter - I think we are saying the same thing. Computing 100 digits of PI synchronously implies no queuing. Sending the ‘launch missile’ command might be synch or async depending on your design. Almost everything done by real drivers implies queueing – which implies cancel support should be provided at least during the queued phase. And most kinds of requests that come out of software queues, go into some kind of hardware queue (with or without direct cancel support) because that is how overall performance is achieved – pipelining – can be cancelled at least on the software side