xbox-kernel/private/ntos/xapi/k32/cancelio.c
2020-09-30 17:17:25 +02:00

147 lines
3.6 KiB
C

/*++
Copyright (c) 2002 Microsoft Corporation
Module Name:
cancelio.c
Abstract:
This module implements the Win32 CancelIo service.
--*/
#include "basedll.h"
#pragma hdrstop
#include <idexchan.h>
VOID
XapiDpcForCancelIo(
IN PKDPC Dpc,
IN PVOID DeferredContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2
)
{
PLIST_ENTRY CancelListHead;
PLIST_ENTRY NextListEntry;
PIRP Irp;
CancelListHead = (PLIST_ENTRY)DeferredContext;
//
// Run through the list of IRPs to be canceled.
//
NextListEntry = CancelListHead->Flink;
while (NextListEntry != CancelListHead) {
Irp = CONTAINING_RECORD(NextListEntry, IRP, Tail.Overlay.DeviceQueueEntry.DeviceListEntry);
NextListEntry = NextListEntry->Flink;
Irp->IoStatus.Status = STATUS_CANCELLED;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
}
BOOL
WINAPI
CancelIo(
HANDLE hFile
)
/*++
Routine Description:
This routine cancels all of the outstanding I/O for the specified handle
for the specified file.
Arguments:
hFile - Supplies the handle to the file whose pending I/O is to be
canceled.
Return Value:
TRUE -- The operation was successful.
FALSE -- The operation failed. Extended error status is available using
GetLastError.
--*/
{
LIST_ENTRY CancelListHead;
NTSTATUS status;
PFILE_OBJECT FileObject;
KIRQL OldIrql;
PLIST_ENTRY NextListEntry;
PIRP Irp;
KDPC WorkerDpc;
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
InitializeListHead(&CancelListHead);
//
// Reference the file object.
//
status = ObReferenceObjectByHandle(hFile, IoFileObjectType,
(PVOID*)&FileObject);
if (!NT_SUCCESS(status)) {
XapiSetLastNTError(status);
return FALSE;
}
//
// Scan through the IDEX device queue for any pending IRPs that originated
// from the supplied file object. Synchronize with the IDEX channel
// dispatcher by raising to DPC level.
//
OldIrql = KeRaiseIrqlToDpcLevel();
NextListEntry = IdexChannelObject->DeviceQueue.DeviceListHead.Flink;
while (NextListEntry != &IdexChannelObject->DeviceQueue.DeviceListHead) {
Irp = CONTAINING_RECORD(NextListEntry, IRP, Tail.Overlay.DeviceQueueEntry.DeviceListEntry);
NextListEntry = NextListEntry->Flink;
if ((Irp->Tail.Overlay.OriginalFileObject == FileObject) &&
((Irp->Flags & IRP_NO_CANCELIO) == 0)) {
RemoveEntryList(&Irp->Tail.Overlay.DeviceQueueEntry.DeviceListEntry);
InsertTailList(&CancelListHead, &Irp->Tail.Overlay.DeviceQueueEntry.DeviceListEntry);
}
}
KeLowerIrql(OldIrql);
//
// If there are any IRPs that need to be canceled, then do so from a worker
// DPC. This is done for two reasons. First, for packets marked as "must
// complete" using IoMarkIrpMustComplete, IoCompleteRequest must be called
// at DPC level. Second, if the number of "must complete" packets reach
// zero and a shutdown request is pending, then the kernel routine
// HalMustCompletePacketsFinished expects to be called from a DPC stack, not
// an arbitrary thread stack.
//
if (!IsListEmpty(&CancelListHead)) {
KeInitializeDpc(&WorkerDpc, XapiDpcForCancelIo, &CancelListHead);
KeInsertQueueDpc(&WorkerDpc, NULL, NULL);
}
//
// Dereference the file object.
//
ObDereferenceObject(FileObject);
return TRUE;
}