Error in msdn article "Using a Driver-Supplied Spin Lock"

Discussion in 'Windows Vista Drivers' started by Vetzak, Nov 7, 2005.

  1. Vetzak

    Vetzak Guest


    The article "Using a Driver-Supplied Spin Lock" in the online msdn
    comes with an example implementation for the function QueueIrp(). I've
    used a similar implementation and it crashes during WHQL testing
    (Driver Verifier causes the bsod). It crashes because the IRP is always
    marked pending, while an early cancellation will cause this function to
    complete the IRP with STATUS_CANCELLED.

    Vetzak, Nov 7, 2005
    1. Advertisements

  2. Yep, the sample code is wrong. I can't believe even after so many years we
    can get the cancellation logic correct in our docs and sample code. This
    piece of code was lifted from the parport sample from the DDK, and the bug
    is there in that sample also. I will get both the docs and sample code

    Here is the fixed code:

    NTSTATUS QueueIrp(DEVICE_CONTEXT *deviceContext, PIRP Irp)
    PDRIVER_CANCEL oldCancelRoutine;
    KIRQL oldIrql;
    NTSTATUS status;

    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.

    InsertTailList(&deviceContext->irpQueue, &Irp->Tail.Overlay.ListEntry);

    // Must set a Cancel routine before checking the Cancel flag.
    oldCancelRoutine = IoSetCancelRoutine(Irp, IrpCancelRoutine);
    ASSERT(oldCancelRoutine == NULL);

    if (Irp->Cancel){
    // The IRP was canceled. Check whether our cancel routine was
    oldCancelRoutine = IoSetCancelRoutine(Irp, NULL);
    if (oldCancelRoutine){
    // The cancel routine was NOT called.
    // So dequeue the IRP now and complete it after releasing the
    spin lock.
    // Drop the lock before completing the request
    KeReleaseSpinLock(&deviceContext->irpQueueSpinLock, oldIrql);

    Irp->IoStatus.Status = STATUS_CANCELLED;
    Irp->IoStatus.Information = 0;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);

    return STATUS_PENDING;
    } //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);

    return STATUS_PENDING;


    This posting is provided "AS IS" with no warranties, and confers no rights.
    Eliyas Yakub [MSFT], Nov 7, 2005
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.