IoCancelIrp does indeed use InterlockedExchangePointer to grab the
function pointer, so it is synchronized with IoSetCancelRoutine
(otherwise IoSetCancelRoutine would also have to grab the cancel spin
lock). You can easily find this out by dumping the asm for IoCancelIrp.
D
This posting is provided “AS IS” with no warranties, and confers no
rights.
-----Original Message-----
From: Dave Harvey [mailto:xxxxx@syssoftsol.com]
Sent: Thursday, February 28, 2002 7:12 PM
To: NT Developers Interest List
Subject: [ntdev] Re: IoCancelIrp
RE: [ntdev] IoCancelIrpIf I’m protecting my queue with my own lock, and
use the example from the DDK design guide, and the code is as you show
it, isn’t there a race on two CPUs where the cancel routine
will not be called? i.e., IoCancelIrp reads irp->CancelRoutine, the
driver then sets it
on the other CPU, then IoCancelIrp overwrites it.
If the code was:
CancelRoutine = Irp->CancelRoutine;
if (CancelRoutine != NULL)
{
Irp->CnacelRoutine = NULL;
Then there is a race were the IRP could be completed twice.
-DH
Here’s the DDK example:
KeAcquireSpinLock(&deviceContext->irpQueueSpinLock, &oldIrql);
// Queue the IRP and call IoMarkIrpPending
// to indicate that the IRP may complete on a different thread. //
N.B. It’s okay to call these inside the spin lock because they’re
macros, not functions. IoMarkIrpPending(Irp);
InsertTailList(&deviceContext->irpQueue, &Irp->Tail.Overlay.ListEntry);
// Must set a Cancel routine before checking the Cancel flag.
oldCancelRoutine = IoSetCancelRoutine(Irp, IrpCancelRoutine);
ASSERT(!oldCancelRoutine);
if (Irp->Cancel){
// The IRP was canceled. Check whether our cancel routine was
called.
oldCancelRoutine = IoSetCancelRoutine(Irp, NULL);
if (oldCancelRoutine){
// The cancel routine was NOT called.
// So dequeue the IRP now and complete it after releasing the
spinlock.
RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
status = Irp->IoStatus.Status = STATUS_CANCELLED;
} //endif
else {
// The cancel routine WAS called.
// As soon as we drop our spin lock it will dequeue and
complete the IRP.
// So leave the IRP in the queue and otherwise don’t touch it.
// Return pending since we’re not completing the IRP here.
} //end else
} // endif
KeReleaseSpinLock(&deviceContext->irpQueueSpinLock, oldIrql);
“Pavel Hrdina” wrote in message news:xxxxx@ntdev…
The IoCancelIrp looks like this… BOOLEAN IoCancelIrp (
IN PIRP Irp
)
{
KIRQL Irql;
PDRIVER_CANCEL CancelRoutine;
ASSERT(Irp->Type == IO_TYPE_IRP);
IoAcquireCancelSpinLock(&Irql);
Irp->Cancel = TRUE;
CancelRoutine = Irp->CancelRoutine;
Irp->CnacelRoutine = NULL;
if (CancelRoutine != NULL)
{
if (Irp->CurrentLocation > Irp->StackCount + 1)
{
KeBugCheckEx(CANCEL_STATE_IN_COMPLETED_IRP, Irp, 0, 0, 0);
}
Irp->CancelIrql = Irql;
CancelRoutine(IoGetCurrentIrpStackLocation(Irp)->DeviceObject,
Irp);
return TRUE;
}
IoReleaseCancelSpinLock(&Irql);
return FALSE;
}
Paul
-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com]On Behalf Of Dave Harvey
Sent: Thursday, February 28, 2002 4:20 AM
To: NT Developers Interest List
Subject: [ntdev] IoCancelIrp
Does IoCancelIrp do an InterlockedExchange with 0 for the cancel routine
as implied by the design guide, or does it only set irp->Cancel to TRUE,
and read the cancel routine, as stated in the Reference section?
------------------------------------------------------------------------
----------------------------------
Dave Harvey, System Software Solutions, Inc.
617-964-7039, FAX 208-361-9395, xxxxx@syssoftsol.com,
http://www.syssoftsol.com
Creators of RedunDisks - Robust RAID 1 for embedded systems.
—
You are currently subscribed to ntdev as: xxxxx@compelson.com
To unsubscribe send a blank email to %%email.unsub%%
—
You are currently subscribed to ntdev as: xxxxx@windows.microsoft.com
To unsubscribe send a blank email to %%email.unsub%%