mirror of
https://github.com/reactos/reactos.git
synced 2025-01-04 21:38:43 +00:00
Alex Ionescu <ionucu@videotron.ca>
- Clean up IO Completion Code - Properly delete an IO Completion. The IRPs were not freed, resulting in memory leaks Thomas Weidenmueller <w3seek@reactos.com> - Add SEH to IO Completion Code svn path=/trunk/; revision=13977
This commit is contained in:
parent
b21f552e3b
commit
7fd17a9a85
1 changed files with 375 additions and 281 deletions
|
@ -1,5 +1,4 @@
|
||||||
/* $Id$
|
/*
|
||||||
*
|
|
||||||
* COPYRIGHT: See COPYING in the top level directory
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
* PROJECT: ReactOS kernel
|
* PROJECT: ReactOS kernel
|
||||||
* FILE: ntoskrnl/io/iocomp.c
|
* FILE: ntoskrnl/io/iocomp.c
|
||||||
|
@ -28,56 +27,44 @@ static GENERIC_MAPPING ExIoCompletionMapping =
|
||||||
IO_COMPLETION_ALL_ACCESS
|
IO_COMPLETION_ALL_ACCESS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const INFORMATION_CLASS_INFO ExIoCompletionInfoClass[] = {
|
||||||
|
|
||||||
|
/* IoCompletionBasicInformation */
|
||||||
|
ICI_SQ_SAME( sizeof(IO_COMPLETION_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY ),
|
||||||
|
};
|
||||||
|
|
||||||
/* FUNCTIONS *****************************************************************/
|
/* FUNCTIONS *****************************************************************/
|
||||||
|
|
||||||
NTSTATUS
|
VOID
|
||||||
STDCALL
|
STDCALL
|
||||||
IopCreateIoCompletion(
|
|
||||||
PVOID ObjectBody,
|
|
||||||
PVOID Parent,
|
|
||||||
PWSTR RemainingPath,
|
|
||||||
POBJECT_ATTRIBUTES ObjectAttributes
|
|
||||||
)
|
|
||||||
{
|
|
||||||
DPRINT("IopCreateIoCompletion(ObjectBody %x, Parent %x, RemainingPath %S)\n",
|
|
||||||
ObjectBody, Parent, RemainingPath);
|
|
||||||
|
|
||||||
if (RemainingPath != NULL && wcschr(RemainingPath+1, '\\') != NULL)
|
|
||||||
{
|
|
||||||
return STATUS_UNSUCCESSFUL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID STDCALL
|
|
||||||
IopDeleteIoCompletion(PVOID ObjectBody)
|
IopDeleteIoCompletion(PVOID ObjectBody)
|
||||||
{
|
{
|
||||||
PKQUEUE Queue = ObjectBody;
|
PKQUEUE Queue = ObjectBody;
|
||||||
|
PLIST_ENTRY FirstEntry;
|
||||||
|
PLIST_ENTRY CurrentEntry;
|
||||||
|
PIO_COMPLETION_PACKET Packet;
|
||||||
|
|
||||||
DPRINT("IopDeleteIoCompletion()\n");
|
DPRINT("IopDeleteIoCompletion()\n");
|
||||||
|
|
||||||
KeRundownQueue(Queue);
|
/* Rundown the Queue */
|
||||||
|
FirstEntry = KeRundownQueue(Queue);
|
||||||
|
|
||||||
|
/* Clean up the IRPs */
|
||||||
|
if (FirstEntry) {
|
||||||
|
|
||||||
|
CurrentEntry = FirstEntry;
|
||||||
|
do {
|
||||||
|
|
||||||
|
/* Get the Packet */
|
||||||
|
Packet = CONTAINING_RECORD(CurrentEntry, IO_COMPLETION_PACKET, ListEntry);
|
||||||
|
|
||||||
|
/* Go to next Entry */
|
||||||
|
CurrentEntry = CurrentEntry->Flink;
|
||||||
|
|
||||||
|
/* Free it */
|
||||||
|
ExFreeToNPagedLookasideList(&IoCompletionPacketLookaside, Packet);
|
||||||
|
} while (FirstEntry != CurrentEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @unimplemented
|
|
||||||
*/
|
|
||||||
NTSTATUS
|
|
||||||
STDCALL
|
|
||||||
IoSetCompletionRoutineEx(
|
|
||||||
IN PDEVICE_OBJECT DeviceObject,
|
|
||||||
IN PIRP Irp,
|
|
||||||
IN PIO_COMPLETION_ROUTINE CompletionRoutine,
|
|
||||||
IN PVOID Context,
|
|
||||||
IN BOOLEAN InvokeOnSuccess,
|
|
||||||
IN BOOLEAN InvokeOnError,
|
|
||||||
IN BOOLEAN InvokeOnCancel
|
|
||||||
)
|
|
||||||
{
|
|
||||||
UNIMPLEMENTED;
|
|
||||||
return STATUS_NOT_IMPLEMENTED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -85,42 +72,57 @@ IoSetCompletionRoutineEx(
|
||||||
*/
|
*/
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
STDCALL
|
STDCALL
|
||||||
IoSetIoCompletion (
|
IoSetIoCompletion(IN PVOID IoCompletion,
|
||||||
IN PVOID IoCompletion,
|
|
||||||
IN PVOID KeyContext,
|
IN PVOID KeyContext,
|
||||||
IN PVOID ApcContext,
|
IN PVOID ApcContext,
|
||||||
IN NTSTATUS IoStatus,
|
IN NTSTATUS IoStatus,
|
||||||
IN ULONG_PTR IoStatusInformation,
|
IN ULONG_PTR IoStatusInformation,
|
||||||
IN BOOLEAN Quota
|
IN BOOLEAN Quota)
|
||||||
)
|
|
||||||
{
|
{
|
||||||
PKQUEUE Queue = (PKQUEUE)IoCompletion;
|
PKQUEUE Queue = (PKQUEUE)IoCompletion;
|
||||||
PIO_COMPLETION_PACKET Packet;
|
PIO_COMPLETION_PACKET Packet;
|
||||||
|
|
||||||
|
/* Allocate the Packet */
|
||||||
Packet = ExAllocateFromNPagedLookasideList(&IoCompletionPacketLookaside);
|
Packet = ExAllocateFromNPagedLookasideList(&IoCompletionPacketLookaside);
|
||||||
if (NULL == Packet)
|
if (NULL == Packet) return STATUS_NO_MEMORY;
|
||||||
{
|
|
||||||
return STATUS_NO_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* Set up the Packet */
|
||||||
Packet->Key = KeyContext;
|
Packet->Key = KeyContext;
|
||||||
Packet->Context = ApcContext;
|
Packet->Context = ApcContext;
|
||||||
Packet->IoStatus.Status = IoStatus;
|
Packet->IoStatus.Status = IoStatus;
|
||||||
Packet->IoStatus.Information = IoStatusInformation;
|
Packet->IoStatus.Information = IoStatusInformation;
|
||||||
|
|
||||||
|
/* Insert the Queue */
|
||||||
KeInsertQueue(Queue, &Packet->ListEntry);
|
KeInsertQueue(Queue, &Packet->ListEntry);
|
||||||
|
|
||||||
|
/* Return Success */
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @unimplemented
|
||||||
|
*/
|
||||||
|
NTSTATUS
|
||||||
|
STDCALL
|
||||||
|
IoSetCompletionRoutineEx(IN PDEVICE_OBJECT DeviceObject,
|
||||||
|
IN PIRP Irp,
|
||||||
|
IN PIO_COMPLETION_ROUTINE CompletionRoutine,
|
||||||
|
IN PVOID Context,
|
||||||
|
IN BOOLEAN InvokeOnSuccess,
|
||||||
|
IN BOOLEAN InvokeOnError,
|
||||||
|
IN BOOLEAN InvokeOnCancel)
|
||||||
|
{
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
return STATUS_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
FASTCALL
|
FASTCALL
|
||||||
IopInitIoCompletionImplementation(VOID)
|
IopInitIoCompletionImplementation(VOID)
|
||||||
{
|
{
|
||||||
|
/* Create the IO Completion Type */
|
||||||
ExIoCompletionType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE));
|
ExIoCompletionType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE));
|
||||||
|
RtlInitUnicodeString(&ExIoCompletionType->TypeName, L"IoCompletion");
|
||||||
RtlpCreateUnicodeString(&ExIoCompletionType->TypeName, L"IoCompletion", NonPagedPool);
|
|
||||||
|
|
||||||
ExIoCompletionType->Tag = IOC_TAG;
|
ExIoCompletionType->Tag = IOC_TAG;
|
||||||
ExIoCompletionType->PeakObjects = 0;
|
ExIoCompletionType->PeakObjects = 0;
|
||||||
ExIoCompletionType->PeakHandles = 0;
|
ExIoCompletionType->PeakHandles = 0;
|
||||||
|
@ -137,9 +139,10 @@ IopInitIoCompletionImplementation(VOID)
|
||||||
ExIoCompletionType->Security = NULL;
|
ExIoCompletionType->Security = NULL;
|
||||||
ExIoCompletionType->QueryName = NULL;
|
ExIoCompletionType->QueryName = NULL;
|
||||||
ExIoCompletionType->OkayToClose = NULL;
|
ExIoCompletionType->OkayToClose = NULL;
|
||||||
ExIoCompletionType->Create = IopCreateIoCompletion;
|
ExIoCompletionType->Create = NULL;
|
||||||
ExIoCompletionType->DuplicationNotify = NULL;
|
ExIoCompletionType->DuplicationNotify = NULL;
|
||||||
|
|
||||||
|
/* Initialize the Lookaside List we'll use for packets */
|
||||||
ExInitializeNPagedLookasideList(&IoCompletionPacketLookaside,
|
ExInitializeNPagedLookasideList(&IoCompletionPacketLookaside,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
|
@ -149,241 +152,332 @@ IopInitIoCompletionImplementation(VOID)
|
||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
STDCALL
|
STDCALL
|
||||||
NtCreateIoCompletion(
|
NtCreateIoCompletion(OUT PHANDLE IoCompletionHandle,
|
||||||
OUT PHANDLE IoCompletionHandle,
|
|
||||||
IN ACCESS_MASK DesiredAccess,
|
IN ACCESS_MASK DesiredAccess,
|
||||||
IN POBJECT_ATTRIBUTES ObjectAttributes,
|
IN POBJECT_ATTRIBUTES ObjectAttributes,
|
||||||
IN ULONG NumberOfConcurrentThreads
|
IN ULONG NumberOfConcurrentThreads)
|
||||||
)
|
|
||||||
{
|
{
|
||||||
PKQUEUE Queue;
|
PKQUEUE Queue;
|
||||||
NTSTATUS Status;
|
HANDLE hIoCompletionHandle;
|
||||||
|
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
||||||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||||||
|
|
||||||
Status = ObCreateObject(ExGetPreviousMode(),
|
PAGED_CODE();
|
||||||
|
|
||||||
|
if (PreviousMode != KernelMode) {
|
||||||
|
|
||||||
|
_SEH_TRY {
|
||||||
|
|
||||||
|
ProbeForWrite(IoCompletionHandle,
|
||||||
|
sizeof(HANDLE),
|
||||||
|
sizeof(ULONG));
|
||||||
|
} _SEH_HANDLE {
|
||||||
|
|
||||||
|
Status = _SEH_GetExceptionCode();
|
||||||
|
} _SEH_END;
|
||||||
|
|
||||||
|
if (!NT_SUCCESS(Status)) {
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create the Object */
|
||||||
|
Status = ObCreateObject(PreviousMode,
|
||||||
ExIoCompletionType,
|
ExIoCompletionType,
|
||||||
ObjectAttributes,
|
ObjectAttributes,
|
||||||
ExGetPreviousMode(),
|
PreviousMode,
|
||||||
NULL,
|
NULL,
|
||||||
sizeof(KQUEUE),
|
sizeof(KQUEUE),
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
(PVOID*)&Queue);
|
(PVOID*)&Queue);
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
|
|
||||||
Status = ObInsertObject ((PVOID)Queue,
|
/* Check for success */
|
||||||
|
if (NT_SUCCESS(Status)) {
|
||||||
|
|
||||||
|
/* Initialize the Queue */
|
||||||
|
KeInitializeQueue(Queue, NumberOfConcurrentThreads);
|
||||||
|
|
||||||
|
/* Insert it */
|
||||||
|
Status = ObInsertObject(Queue,
|
||||||
NULL,
|
NULL,
|
||||||
DesiredAccess,
|
DesiredAccess,
|
||||||
0,
|
0,
|
||||||
NULL,
|
NULL,
|
||||||
IoCompletionHandle);
|
&hIoCompletionHandle);
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
ObDereferenceObject(Queue);
|
ObDereferenceObject(Queue);
|
||||||
|
|
||||||
|
if (NT_SUCCESS(Status)) {
|
||||||
|
|
||||||
|
_SEH_TRY {
|
||||||
|
|
||||||
|
*IoCompletionHandle = hIoCompletionHandle;
|
||||||
|
} _SEH_HANDLE {
|
||||||
|
|
||||||
|
Status = _SEH_GetExceptionCode();
|
||||||
|
} _SEH_END;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return Status */
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
KeInitializeQueue(Queue, NumberOfConcurrentThreads);
|
|
||||||
ObDereferenceObject(Queue);
|
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
|
||||||
/*
|
|
||||||
|
|
||||||
CompletionPort = NULL OR ExistingCompletionPort
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
DesiredAccess:
|
|
||||||
ZERO
|
|
||||||
IO_COMPLETION_QUERY_STATE Query access
|
|
||||||
IO_COMPLETION_MODIFY_STATE Modify access
|
|
||||||
IO_COMPLETION_ALL_ACCESS All of the preceding + STANDARD_RIGHTS_ALL
|
|
||||||
|
|
||||||
ObjectAttributes
|
|
||||||
OBJ_OPENLINK and OBJ_PERMANENT are not valid attributes
|
|
||||||
|
|
||||||
Return Value
|
|
||||||
STATUS_SUCCESS or an error status, such as STATUS_ACCESS_DENIED or
|
|
||||||
STATUS_OBJECT_NAME_NOT_FOUND.
|
|
||||||
*/
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
STDCALL
|
STDCALL
|
||||||
NtOpenIoCompletion(
|
NtOpenIoCompletion(OUT PHANDLE IoCompletionHandle,
|
||||||
OUT PHANDLE IoCompletionHandle,
|
|
||||||
IN ACCESS_MASK DesiredAccess,
|
IN ACCESS_MASK DesiredAccess,
|
||||||
IN POBJECT_ATTRIBUTES ObjectAttributes
|
IN POBJECT_ATTRIBUTES ObjectAttributes)
|
||||||
)
|
|
||||||
{
|
{
|
||||||
NTSTATUS Status;
|
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
||||||
|
HANDLE hIoCompletionHandle;
|
||||||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||||||
|
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
if(PreviousMode != KernelMode) {
|
||||||
|
|
||||||
|
_SEH_TRY {
|
||||||
|
|
||||||
|
ProbeForWrite(IoCompletionHandle,
|
||||||
|
sizeof(HANDLE),
|
||||||
|
sizeof(ULONG));
|
||||||
|
} _SEH_HANDLE {
|
||||||
|
|
||||||
|
Status = _SEH_GetExceptionCode();
|
||||||
|
} _SEH_END;
|
||||||
|
|
||||||
|
if(!NT_SUCCESS(Status)) {
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Open the Object */
|
||||||
Status = ObOpenObjectByName(ObjectAttributes,
|
Status = ObOpenObjectByName(ObjectAttributes,
|
||||||
ExIoCompletionType,
|
ExIoCompletionType,
|
||||||
NULL,
|
NULL,
|
||||||
UserMode,
|
PreviousMode,
|
||||||
DesiredAccess,
|
DesiredAccess,
|
||||||
NULL,
|
NULL,
|
||||||
IoCompletionHandle); //<- ???
|
&hIoCompletionHandle);
|
||||||
|
|
||||||
|
if (NT_SUCCESS(Status)) {
|
||||||
|
|
||||||
|
_SEH_TRY {
|
||||||
|
|
||||||
|
*IoCompletionHandle = hIoCompletionHandle;
|
||||||
|
} _SEH_HANDLE {
|
||||||
|
|
||||||
|
Status = _SEH_GetExceptionCode();
|
||||||
|
} _SEH_END;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return Status */
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
STDCALL
|
STDCALL
|
||||||
NtQueryIoCompletion(
|
NtQueryIoCompletion(IN HANDLE IoCompletionHandle,
|
||||||
IN HANDLE IoCompletionHandle,
|
|
||||||
IN IO_COMPLETION_INFORMATION_CLASS IoCompletionInformationClass,
|
IN IO_COMPLETION_INFORMATION_CLASS IoCompletionInformationClass,
|
||||||
OUT PVOID IoCompletionInformation,
|
OUT PVOID IoCompletionInformation,
|
||||||
IN ULONG IoCompletionInformationLength,
|
IN ULONG IoCompletionInformationLength,
|
||||||
OUT PULONG ResultLength OPTIONAL
|
OUT PULONG ResultLength OPTIONAL)
|
||||||
)
|
|
||||||
{
|
{
|
||||||
PKQUEUE Queue;
|
PKQUEUE Queue;
|
||||||
NTSTATUS Status;
|
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
||||||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||||||
|
|
||||||
if (IoCompletionInformationClass != IoCompletionBasicInformation)
|
PAGED_CODE();
|
||||||
{
|
|
||||||
return STATUS_INVALID_INFO_CLASS;
|
|
||||||
}
|
|
||||||
if (IoCompletionInformationLength < sizeof(IO_COMPLETION_BASIC_INFORMATION))
|
|
||||||
{
|
|
||||||
return STATUS_INFO_LENGTH_MISMATCH;
|
|
||||||
}
|
|
||||||
|
|
||||||
Status = ObReferenceObjectByHandle( IoCompletionHandle,
|
/* Check buffers and parameters */
|
||||||
IO_COMPLETION_QUERY_STATE,
|
DefaultQueryInfoBufferCheck(IoCompletionInformationClass,
|
||||||
ExIoCompletionType,
|
ExIoCompletionInfoClass,
|
||||||
UserMode,
|
IoCompletionInformation,
|
||||||
(PVOID*)&Queue,
|
IoCompletionInformationLength,
|
||||||
NULL);
|
ResultLength,
|
||||||
if (NT_SUCCESS(Status))
|
PreviousMode,
|
||||||
{
|
&Status);
|
||||||
((PIO_COMPLETION_BASIC_INFORMATION)IoCompletionInformation)->Depth =
|
if(!NT_SUCCESS(Status)) {
|
||||||
Queue->Header.SignalState;
|
|
||||||
|
|
||||||
ObDereferenceObject(Queue);
|
|
||||||
|
|
||||||
if (ResultLength) *ResultLength = sizeof(IO_COMPLETION_BASIC_INFORMATION);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
DPRINT1("NtQueryMutant() failed, Status: 0x%x\n", Status);
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Get the Object */
|
||||||
|
Status = ObReferenceObjectByHandle(IoCompletionHandle,
|
||||||
|
IO_COMPLETION_QUERY_STATE,
|
||||||
|
ExIoCompletionType,
|
||||||
|
PreviousMode,
|
||||||
|
(PVOID*)&Queue,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
/* Check for Success */
|
||||||
|
if (NT_SUCCESS(Status)) {
|
||||||
|
|
||||||
|
_SEH_TRY {
|
||||||
|
|
||||||
|
/* Return Info */
|
||||||
|
((PIO_COMPLETION_BASIC_INFORMATION)IoCompletionInformation)->Depth = KeReadStateQueue(Queue);
|
||||||
|
ObDereferenceObject(Queue);
|
||||||
|
|
||||||
|
/* Return Result Length if needed */
|
||||||
|
if (ResultLength) {
|
||||||
|
|
||||||
|
*ResultLength = sizeof(IO_COMPLETION_BASIC_INFORMATION);
|
||||||
|
}
|
||||||
|
} _SEH_HANDLE {
|
||||||
|
|
||||||
|
Status = _SEH_GetExceptionCode();
|
||||||
|
} _SEH_END;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return Status */
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Dequeues an I/O completion message from an I/O completion object
|
* Dequeues an I/O completion message from an I/O completion object
|
||||||
*/
|
*/
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
STDCALL
|
STDCALL
|
||||||
NtRemoveIoCompletion(
|
NtRemoveIoCompletion(IN HANDLE IoCompletionHandle,
|
||||||
IN HANDLE IoCompletionHandle,
|
|
||||||
OUT PVOID *CompletionKey,
|
OUT PVOID *CompletionKey,
|
||||||
OUT PVOID *CompletionContext,
|
OUT PVOID *CompletionContext,
|
||||||
OUT PIO_STATUS_BLOCK IoStatusBlock,
|
OUT PIO_STATUS_BLOCK IoStatusBlock,
|
||||||
IN PLARGE_INTEGER Timeout OPTIONAL
|
IN PLARGE_INTEGER Timeout OPTIONAL)
|
||||||
)
|
|
||||||
{
|
{
|
||||||
|
LARGE_INTEGER SafeTimeout;
|
||||||
PKQUEUE Queue;
|
PKQUEUE Queue;
|
||||||
NTSTATUS Status;
|
|
||||||
PIO_COMPLETION_PACKET Packet;
|
PIO_COMPLETION_PACKET Packet;
|
||||||
PLIST_ENTRY ListEntry;
|
PLIST_ENTRY ListEntry;
|
||||||
|
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
||||||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||||||
|
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
if (PreviousMode != KernelMode) {
|
||||||
|
|
||||||
|
_SEH_TRY {
|
||||||
|
|
||||||
|
ProbeForWrite(CompletionKey,
|
||||||
|
sizeof(PVOID),
|
||||||
|
sizeof(ULONG));
|
||||||
|
ProbeForWrite(CompletionContext,
|
||||||
|
sizeof(PVOID),
|
||||||
|
sizeof(ULONG));
|
||||||
|
ProbeForWrite(IoStatusBlock,
|
||||||
|
sizeof(IO_STATUS_BLOCK),
|
||||||
|
sizeof(ULONG));
|
||||||
|
if (Timeout != NULL) {
|
||||||
|
|
||||||
|
ProbeForRead(Timeout,
|
||||||
|
sizeof(LARGE_INTEGER),
|
||||||
|
sizeof(ULONG));
|
||||||
|
SafeTimeout = *Timeout;
|
||||||
|
Timeout = &SafeTimeout;
|
||||||
|
}
|
||||||
|
} _SEH_HANDLE {
|
||||||
|
|
||||||
|
Status = _SEH_GetExceptionCode();
|
||||||
|
} _SEH_END;
|
||||||
|
|
||||||
|
if (!NT_SUCCESS(Status)) {
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Open the Object */
|
||||||
Status = ObReferenceObjectByHandle(IoCompletionHandle,
|
Status = ObReferenceObjectByHandle(IoCompletionHandle,
|
||||||
IO_COMPLETION_MODIFY_STATE,
|
IO_COMPLETION_MODIFY_STATE,
|
||||||
ExIoCompletionType,
|
ExIoCompletionType,
|
||||||
UserMode,
|
PreviousMode,
|
||||||
(PVOID*)&Queue,
|
(PVOID*)&Queue,
|
||||||
NULL);
|
NULL);
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/* Check for success */
|
||||||
Try 2 remove packet from queue. Wait (optionaly) if
|
if (NT_SUCCESS(Status)) {
|
||||||
no packet in queue or max num of threads allready running.
|
|
||||||
*/
|
|
||||||
|
|
||||||
do {
|
/* Remove queue */
|
||||||
|
ListEntry = KeRemoveQueue(Queue, PreviousMode, Timeout);
|
||||||
|
|
||||||
ListEntry = KeRemoveQueue(Queue, UserMode, Timeout );
|
/* If we got a timeout or user_apc back, return the status */
|
||||||
|
if ((NTSTATUS)ListEntry == STATUS_TIMEOUT || (NTSTATUS)ListEntry == STATUS_USER_APC) {
|
||||||
|
|
||||||
/* Nebbets book says nothing about NtRemoveIoCompletion returning STATUS_USER_APC,
|
Status = (NTSTATUS)ListEntry;
|
||||||
and the umode equivalent GetQueuedCompletionStatus says nothing about this either,
|
|
||||||
so my guess it we should restart the operation. Need further investigation. -Gunnar
|
|
||||||
*/
|
|
||||||
|
|
||||||
} while((NTSTATUS)ListEntry == STATUS_USER_APC);
|
} else {
|
||||||
|
|
||||||
ObDereferenceObject(Queue);
|
|
||||||
|
|
||||||
if ((NTSTATUS)ListEntry == STATUS_TIMEOUT)
|
|
||||||
{
|
|
||||||
return STATUS_TIMEOUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT(ListEntry);
|
|
||||||
|
|
||||||
|
/* Get the Packet Data */
|
||||||
Packet = CONTAINING_RECORD(ListEntry, IO_COMPLETION_PACKET, ListEntry);
|
Packet = CONTAINING_RECORD(ListEntry, IO_COMPLETION_PACKET, ListEntry);
|
||||||
|
|
||||||
if (CompletionKey) *CompletionKey = Packet->Key;
|
_SEH_TRY {
|
||||||
if (CompletionContext) *CompletionContext = Packet->Context;
|
|
||||||
if (IoStatusBlock) *IoStatusBlock = Packet->IoStatus;
|
|
||||||
|
|
||||||
|
/* Return it */
|
||||||
|
*CompletionKey = Packet->Key;
|
||||||
|
*CompletionContext = Packet->Context;
|
||||||
|
*IoStatusBlock = Packet->IoStatus;
|
||||||
|
|
||||||
|
} _SEH_HANDLE {
|
||||||
|
|
||||||
|
Status = _SEH_GetExceptionCode();
|
||||||
|
} _SEH_END;
|
||||||
|
|
||||||
|
/* Free packet */
|
||||||
ExFreeToNPagedLookasideList(&IoCompletionPacketLookaside, Packet);
|
ExFreeToNPagedLookasideList(&IoCompletionPacketLookaside, Packet);
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Dereference the Object */
|
||||||
|
ObDereferenceObject(Queue);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/* Return status */
|
||||||
ASSOSIERT MED FOB's IoCompletionContext
|
return Status;
|
||||||
|
}
|
||||||
typedef struct _IO_COMPLETION_CONTEXT {
|
|
||||||
PVOID Port;
|
|
||||||
ULONG Key;
|
|
||||||
} IO_COMPLETION_CONTEXT, *PIO_COMPLETION_CONTEXT;
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Queues an I/O completion message to an I/O completion object
|
* Queues an I/O completion message to an I/O completion object
|
||||||
*/
|
*/
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
STDCALL
|
STDCALL
|
||||||
NtSetIoCompletion(
|
NtSetIoCompletion(IN HANDLE IoCompletionPortHandle,
|
||||||
IN HANDLE IoCompletionPortHandle,
|
|
||||||
IN PVOID CompletionKey,
|
IN PVOID CompletionKey,
|
||||||
IN PVOID CompletionContext,
|
IN PVOID CompletionContext,
|
||||||
IN NTSTATUS CompletionStatus,
|
IN NTSTATUS CompletionStatus,
|
||||||
IN ULONG CompletionInformation
|
IN ULONG CompletionInformation)
|
||||||
)
|
|
||||||
{
|
{
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
PKQUEUE Queue;
|
PKQUEUE Queue;
|
||||||
|
|
||||||
|
PAGED_CODE();
|
||||||
|
|
||||||
|
/* Get the Object */
|
||||||
Status = ObReferenceObjectByHandle(IoCompletionPortHandle,
|
Status = ObReferenceObjectByHandle(IoCompletionPortHandle,
|
||||||
IO_COMPLETION_MODIFY_STATE,
|
IO_COMPLETION_MODIFY_STATE,
|
||||||
ExIoCompletionType,
|
ExIoCompletionType,
|
||||||
UserMode,
|
ExGetPreviousMode(),
|
||||||
(PVOID*)&Queue,
|
(PVOID*)&Queue,
|
||||||
NULL);
|
NULL);
|
||||||
if (NT_SUCCESS(Status))
|
|
||||||
{
|
/* Check for Success */
|
||||||
Status = IoSetIoCompletion(Queue, CompletionKey, CompletionContext,
|
if (NT_SUCCESS(Status)) {
|
||||||
CompletionStatus, CompletionInformation, TRUE);
|
|
||||||
|
/* Set the Completion */
|
||||||
|
Status = IoSetIoCompletion(Queue,
|
||||||
|
CompletionKey,
|
||||||
|
CompletionContext,
|
||||||
|
CompletionStatus,
|
||||||
|
CompletionInformation,
|
||||||
|
TRUE);
|
||||||
ObDereferenceObject(Queue);
|
ObDereferenceObject(Queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return status */
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue