⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 queue.c

📁 该源码是用DDK编写的WDM驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
//
//  Return Value:
//      none
//
VOID CharSample_DDKListCancelRoutine(
    IN  PDEVICE_OBJECT  DeviceObject,
    IN  PIRP            Irp
    )
{
    KIRQL           oldIrql;
    PCHARSAMPLE_DDK_LIST   list;

    oldIrql = Irp->CancelIrql;

    // release the system cancel spinlock
    IoReleaseCancelSpinLock(DISPATCH_LEVEL);

    // get our list context from the IRP
    list = (PCHARSAMPLE_DDK_LIST)Irp->Tail.Overlay.DriverContext[0];

    // grab the list protection
    KeAcquireSpinLockAtDpcLevel(&list->ListLock);

    // remove our IRP from the list
    RemoveEntryList(&Irp->Tail.Overlay.ListEntry);

    // drop the list protection
    KeReleaseSpinLock(&list->ListLock, oldIrql);

    // cancel the IRP
    Irp->IoStatus.Status = STATUS_CANCELLED;
    Irp->IoStatus.Information = 0;

    IoCompleteRequest(Irp, IO_NO_INCREMENT);

    return;
}

///////////////////////////////////////////////////////////////////////////////////////////////////
// CHARSAMPLE_DDK_IO_LOCK
///////////////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////////////////
//  CharSample_DDKInitializeIoLock
//      Initializes io lock structure.
//
//  Arguments:
//      IN  IoLock
//              io lock to initialize
//
//      IN  DeviceObject
//              device object 
//
//  Return Value:
//      none
//
VOID CharSample_DDKInitializeIoLock(
    IN  PCHARSAMPLE_DDK_IO_LOCK    IoLock, 
    IN  PDEVICE_OBJECT              DeviceObject
    )
{
    IoLock->DeviceObject = DeviceObject;
    KeInitializeEvent(&IoLock->StallCompleteEvent, NotificationEvent, FALSE);
    InitializeListHead(&IoLock->StallIrpList);
    KeInitializeSpinLock(&IoLock->IoLock);
    IoLock->StallCount = 1;
    IoLock->ActiveIrpCount = 0;
    IoLock->ErrorStatus = STATUS_SUCCESS;
    IoLock->CurrentIrp = NULL;

    return;
}

///////////////////////////////////////////////////////////////////////////////////////////////////
//  CharSample_DDKCheckIoLock
//      checks if IRP is allowed to proceed.
//
//  Arguments:
//      IN  IoLock
//              io lock for our device
//
//      IN  Irp
//              new IRP
//
//  Return Value:
//      Status
//
NTSTATUS CharSample_DDKCheckIoLock(
    IN  PCHARSAMPLE_DDK_IO_LOCK    IoLock, 
    IN  PIRP                        Irp
    )
{
    NTSTATUS            status;
    KIRQL               oldIrql;
    PCHARSAMPLE_DDK_DEVICE_EXTENSION   deviceExtension;

    deviceExtension = (PCHARSAMPLE_DDK_DEVICE_EXTENSION)IoLock->DeviceObject->DeviceExtension;

    KeAcquireSpinLock(&IoLock->IoLock, &oldIrql);

    // check if device has been removed
    if (IoLock->ErrorStatus != STATUS_SUCCESS)
    {
        status = IoLock->ErrorStatus;
        KeReleaseSpinLock(&IoLock->IoLock, oldIrql);

        Irp->IoStatus.Status = status;
        IoCompleteRequest(Irp, IO_NO_INCREMENT);

        return status;
    }

    // check if io is stalled
    if (IoLock->StallCount > 0)
    {
        // check if Irp is not the one sent by CharSample_DDKUnlockIo
        if (IoLock->CurrentIrp != Irp)
        {
            // save device extension into the IRP
            Irp->Tail.Overlay.DriverContext[0] = IoLock;

            // stall the IRP
            InsertTailList(&IoLock->StallIrpList, &Irp->Tail.Overlay.ListEntry);

            // insert our queue cancel routine into the IRP
            IoSetCancelRoutine(Irp, CharSample_DDKPendingIoCancelRoutine);

            // see if IRP was canceled
            if (Irp->Cancel && (IoSetCancelRoutine(Irp, NULL) != NULL))
            {
                // IRP was canceled
                RemoveEntryList(&Irp->Tail.Overlay.ListEntry);

                // drop the lock
                KeReleaseSpinLock(&IoLock->IoLock, oldIrql);

                // cancel the IRP
                status = STATUS_CANCELLED;
                Irp->IoStatus.Status = status;
                IoCompleteRequest(Irp, IO_NO_INCREMENT);

                return status;
            }

            // mark irp pending since STATUS_PENDING is returned
            IoMarkIrpPending(Irp);
            status = STATUS_PENDING;

            // drop the lock
            KeReleaseSpinLock(&IoLock->IoLock, oldIrql);

            return status;
        }
        else
        {
            IoLock->CurrentIrp = NULL;
        }
    }

    // increment active io count
    ++IoLock->ActiveIrpCount;

    // drop the lock
    KeReleaseSpinLock(&IoLock->IoLock, oldIrql);

    status = STATUS_SUCCESS;
    return status;
}

///////////////////////////////////////////////////////////////////////////////////////////////////
//  CharSample_DDKPendingIoCancelRoutine
//      Cancel routine for stalled IRPs.
//
//  Arguments:
//      IN  DeviceObject
//              our device object
//
//      IN  Irp
//              IRP to be canceled
//
//  Return Value:
//      None
//
VOID CharSample_DDKPendingIoCancelRoutine(
    IN  PDEVICE_OBJECT  DeviceObject,
    IN  PIRP            Irp
    )
{
    KIRQL           oldIrql;
    PCHARSAMPLE_DDK_IO_LOCK  ioLock;

    // release the system cancel spinlock
    oldIrql = Irp->CancelIrql;
    IoReleaseCancelSpinLock(DISPATCH_LEVEL);

    // get our queue from the IRP
    ioLock = (PCHARSAMPLE_DDK_IO_LOCK)Irp->Tail.Overlay.DriverContext[0];

    // grab the queue protection
    KeAcquireSpinLockAtDpcLevel(&ioLock->IoLock);

    // remove our IRP from the queue
    RemoveEntryList(&Irp->Tail.Overlay.ListEntry);

    // drop the queue protection
    KeReleaseSpinLock(&ioLock->IoLock, oldIrql);

    // cancel the IRP
    Irp->IoStatus.Status = STATUS_CANCELLED;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);

    return;
}

///////////////////////////////////////////////////////////////////////////////////////////////////
//  CharSample_DDKIncrementIoCount
//      increment active io count.
//
//  Arguments:
//      IN  IoLock
//              io lock for our device
//
//  Return Value:
//      Status
//
NTSTATUS CharSample_DDKIncrementIoCount(
    IN  PCHARSAMPLE_DDK_IO_LOCK    IoLock
    )
{
    KIRQL       oldIrql;
    NTSTATUS    status;

    KeAcquireSpinLock(&IoLock->IoLock, &oldIrql);

    if (IoLock->ErrorStatus != STATUS_SUCCESS)
    {
        status = IoLock->ErrorStatus;
    }
    else if (IoLock->StallCount > 0)
    {
        status = STATUS_DEVICE_BUSY;
    }
    else
    {
        ++IoLock->ActiveIrpCount;
        status = STATUS_SUCCESS;
    }

    KeReleaseSpinLock(&IoLock->IoLock, oldIrql);

    return status;
}

///////////////////////////////////////////////////////////////////////////////////////////////////
//  CharSample_DDKDecrementIoCount
//      decrements active io count.
//
//  Arguments:
//      IN  IoLock
//              io lock for our device
//
//  Return Value:
//      None
//
VOID CharSample_DDKDecrementIoCount(
    IN  PCHARSAMPLE_DDK_IO_LOCK    IoLock
    )
{
    KIRQL       oldIrql;

    KeAcquireSpinLock(&IoLock->IoLock, &oldIrql);

    if (--IoLock->ActiveIrpCount == 0)
    {
        KeSetEvent(&IoLock->StallCompleteEvent, IO_NO_INCREMENT, FALSE);
    }

    KeReleaseSpinLock(&IoLock->IoLock, oldIrql);

    return;
}

///////////////////////////////////////////////////////////////////////////////////////////////////
//  CharSample_DDKLockIo
//      Locks new IRP processing.
//
//  Arguments:
//      IN  IoLock
//              io lock for our device
//
//  Return Value:
//      None
//
VOID CharSample_DDKLockIo(
    IN  PCHARSAMPLE_DDK_IO_LOCK    IoLock
    )
{
    KIRQL       oldIrql;

    KeAcquireSpinLock(&IoLock->IoLock, &oldIrql);

    // increment stall count
    ++IoLock->StallCount;

    KeReleaseSpinLock(&IoLock->IoLock, oldIrql);

    return;
}

///////////////////////////////////////////////////////////////////////////////////////////////////
//  CharSample_DDKWaitForStopIo
//      Waits for all active io to complete.
//
//  Arguments:
//      IN  IoLock
//              io lock for our device
//
//  Return Value:
//      None
//
VOID CharSample_DDKWaitForStopIo(
    IN  PCHARSAMPLE_DDK_IO_LOCK    IoLock
    )
{
    KIRQL       oldIrql;
    BOOLEAN     bWait;

    KeAcquireSpinLock(&IoLock->IoLock, &oldIrql);

    // clear stall completed event
    KeClearEvent(&IoLock->StallCompleteEvent);

    // check if we need to wait for some IRPs to finish
    bWait = (IoLock->ActiveIrpCount != 0);

    KeReleaseSpinLock(&IoLock->IoLock, oldIrql);

    if (bWait)
    {
        // wait for outstanding IRPs to complete
        KeWaitForSingleObject(&IoLock->StallCompleteEvent, Executive, KernelMode, FALSE, NULL);
    }

    return;
}

///////////////////////////////////////////////////////////////////////////////////////////////////
//  CharSample_DDKUnlockIo
//      Locks new IRP processing.
//
//  Arguments:
//      IN  IoLock
//              io lock for our device
//
//  Return Value:
//      None
//
VOID CharSample_DDKUnlockIo(
    IN  PCHARSAMPLE_DDK_IO_LOCK    IoLock
    )
{
    PLIST_ENTRY         entry;
    PIRP                irp;
    KIRQL               oldIrql;
    PIO_STACK_LOCATION  irpStack;

    // Grab the list protection
    KeAcquireSpinLock(&IoLock->IoLock, &oldIrql);

    // if StallCount is 1 then we need to flush all pending IRPs
    while ((IoLock->StallCount == 1) && (!IsListEmpty(&IoLock->StallIrpList)))
    {
        entry = RemoveHeadList(&IoLock->StallIrpList);
        irp = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);

        if (IoSetCancelRoutine(irp, NULL) == NULL)
        {
            // irp was canceled
            // let cancel routine deal with it.
            // we need to initialize IRP's list entry, since
            // our cancel routine expects the IRP to be in a list
            InitializeListHead(&irp->Tail.Overlay.ListEntry);
        }
        else
        {
            IoLock->CurrentIrp = irp;
            KeReleaseSpinLock(&IoLock->IoLock, oldIrql);

            // call DriverDispatch
            irpStack = IoGetCurrentIrpStackLocation(irp);
            IoLock->DeviceObject->DriverObject->MajorFunction[irpStack->MajorFunction](
                IoLock->DeviceObject,
                irp
                );

            KeAcquireSpinLock(&IoLock->IoLock, &oldIrql);
        }
    }

    --IoLock->StallCount;
    KeReleaseSpinLock(&IoLock->IoLock, oldIrql);

    return;
}

///////////////////////////////////////////////////////////////////////////////////////////////////
//  CharSample_DDKFlushPendingIo
//      Cancels stalled IRPs for a particular file object.
//
//  Arguments:
//      IN  IoLock
//              io lock for our device
//
//      IN  FileObject
//              file object for about to be closed handle
//
//  Return Value:
//      None
//
VOID CharSample_DDKFlushPendingIo(
    IN  PCHARSAMPLE_DDK_IO_LOCK    IoLock,
    IN  PFILE_OBJECT                FileObject
    )
{
    PLIST_ENTRY         entry;
    PLIST_ENTRY         nextEntry;
    PIRP                irp;
    PIO_STACK_LOCATION  irpStack;
    KIRQL               oldIrql;
    LIST_ENTRY          cancelList;

    // initialize our cancel list
    InitializeListHead(&cancelList);

    // grab the list protection
    KeAcquireSpinLock(&IoLock->IoLock, &oldIrql);

    // Look at the first entry in the list
    entry = IoLock->StallIrpList.Flink;
    while (entry != &IoLock->StallIrpList)
    {
        // get the next list entry
        nextEntry = entry->Flink;

        // Get the IRP from the entry
        irp = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);

        ASSERT(irp->Type == IO_TYPE_IRP);

        // Determine if we need to pull out of list
        if (FileObject != NULL)
        {
            // get the current IRP stack location from the IRP
            irpStack = IoGetCurrentIrpStackLocation(irp);

            if (irpStack->FileObject != FileObject)
            {
                // go to the next entry
                entry = nextEntry;

                // We are not flushing this IRP
                continue;
            }
        }

        // Attempt to cancel the IRP
        if (IoSetCancelRoutine(irp, NULL) == NULL)
        {
            // go to the next entry
            entry = nextEntry;

            // cancel routine already has this IRP,
            // just go on
            continue;
        }

        // pull the IRP from the list
        RemoveEntryList(entry);

        InsertTailList(&cancelList, entry);

        // go to the next entry
        entry = nextEntry;
    }

    // drop the list protection
    KeReleaseSpinLock(&IoLock->IoLock, oldIrql);

    // Now clear out our cancel list
    while (!IsListEmpty(&cancelList))
    {
        // Get the first entry on the list
        entry = RemoveHeadList(&cancelList);

        // Get the IRP for that entry
        irp = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);

        // Cancel the IRP
        irp->IoStatus.Status = STATUS_CANCELLED;
        irp->IoStatus.Information = 0;
        IoCompleteRequest(irp, IO_NO_INCREMENT);
    }

    return;
}

VOID CharSample_DDKInvalidateIo(
    IN  PCHARSAMPLE_DDK_IO_LOCK    IoLock,
    IN  NTSTATUS                    ErrorStatus
    )
{
    // indicate the list is shutdown
    IoLock->ErrorStatus = ErrorStatus;

    // flush all requests from the list
    CharSample_DDKFlushPendingIo(IoLock, NULL);

    return;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -