📄 queue.c
字号:
//
// 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 + -