2005-03-12 19:58:53 +00:00
|
|
|
/*
|
1998-10-05 04:00:59 +00:00
|
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
|
|
* PROJECT: ReactOS kernel
|
2005-01-26 13:58:37 +00:00
|
|
|
* FILE: ntoskrnl/io/iocomp.c
|
|
|
|
* PURPOSE: No purpose listed.
|
2005-05-09 01:38:29 +00:00
|
|
|
*
|
2005-01-26 13:58:37 +00:00
|
|
|
* PROGRAMMERS: David Welch (welch@mcmail.com)
|
1998-10-05 04:00:59 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
/* INCLUDES *****************************************************************/
|
|
|
|
|
2004-08-15 16:39:12 +00:00
|
|
|
#include <ntoskrnl.h>
|
2003-03-19 23:17:52 +00:00
|
|
|
#define NDEBUG
|
1998-10-05 04:00:59 +00:00
|
|
|
#include <internal/debug.h>
|
|
|
|
|
2005-05-15 17:59:33 +00:00
|
|
|
POBJECT_TYPE IoCompletionType;
|
2003-03-19 23:17:52 +00:00
|
|
|
|
2005-03-12 19:58:53 +00:00
|
|
|
NPAGED_LOOKASIDE_LIST IoCompletionPacketLookaside;
|
2003-03-19 23:17:52 +00:00
|
|
|
|
2005-05-15 17:59:33 +00:00
|
|
|
static GENERIC_MAPPING IopCompletionMapping =
|
2003-03-19 23:17:52 +00:00
|
|
|
{
|
2005-03-12 19:58:53 +00:00
|
|
|
STANDARD_RIGHTS_READ | IO_COMPLETION_QUERY_STATE,
|
|
|
|
STANDARD_RIGHTS_WRITE | IO_COMPLETION_MODIFY_STATE,
|
|
|
|
STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE | IO_COMPLETION_QUERY_STATE,
|
|
|
|
IO_COMPLETION_ALL_ACCESS
|
2003-03-19 23:17:52 +00:00
|
|
|
};
|
|
|
|
|
2005-05-15 17:59:33 +00:00
|
|
|
static const INFORMATION_CLASS_INFO IoCompletionInfoClass[] = {
|
2005-02-28 17:40:15 +00:00
|
|
|
|
2005-03-12 19:58:53 +00:00
|
|
|
/* IoCompletionBasicInformation */
|
|
|
|
ICI_SQ_SAME( sizeof(IO_COMPLETION_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY ),
|
|
|
|
};
|
2005-02-28 17:40:15 +00:00
|
|
|
|
2005-03-12 19:58:53 +00:00
|
|
|
/* FUNCTIONS *****************************************************************/
|
2005-02-28 17:40:15 +00:00
|
|
|
|
2005-05-13 05:41:24 +00:00
|
|
|
VOID
|
|
|
|
STDCALL
|
|
|
|
IopFreeIoCompletionPacket(PIO_COMPLETION_PACKET Packet)
|
|
|
|
{
|
|
|
|
PKPRCB Prcb = KeGetCurrentPrcb();
|
|
|
|
PNPAGED_LOOKASIDE_LIST List;
|
|
|
|
|
|
|
|
/* Use the P List */
|
|
|
|
List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[LookasideCompletionList].P;
|
|
|
|
List->L.TotalFrees++;
|
|
|
|
|
|
|
|
/* Check if the Free was within the Depth or not */
|
|
|
|
if (ExQueryDepthSList(&List->L.ListHead) >= List->L.Depth)
|
|
|
|
{
|
|
|
|
/* Let the balancer know */
|
|
|
|
List->L.FreeMisses++;
|
|
|
|
|
|
|
|
/* Use the L List */
|
|
|
|
List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[LookasideCompletionList].L;
|
|
|
|
List->L.TotalFrees++;
|
|
|
|
|
|
|
|
/* Check if the Free was within the Depth or not */
|
|
|
|
if (ExQueryDepthSList(&List->L.ListHead) >= List->L.Depth)
|
|
|
|
{
|
|
|
|
/* All lists failed, use the pool */
|
|
|
|
List->L.FreeMisses++;
|
|
|
|
ExFreePool(Packet);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The free was within dhe Depth */
|
|
|
|
InterlockedPushEntrySList(&List->L.ListHead, (PSINGLE_LIST_ENTRY)Packet);
|
|
|
|
}
|
|
|
|
|
2005-05-09 01:38:29 +00:00
|
|
|
VOID
|
2005-03-12 19:58:53 +00:00
|
|
|
STDCALL
|
2005-02-07 10:33:44 +00:00
|
|
|
IopDeleteIoCompletion(PVOID ObjectBody)
|
2003-03-19 23:17:52 +00:00
|
|
|
{
|
2005-03-12 19:58:53 +00:00
|
|
|
PKQUEUE Queue = ObjectBody;
|
|
|
|
PLIST_ENTRY FirstEntry;
|
|
|
|
PLIST_ENTRY CurrentEntry;
|
2005-05-13 05:41:24 +00:00
|
|
|
PIRP Irp;
|
2005-03-12 19:58:53 +00:00
|
|
|
PIO_COMPLETION_PACKET Packet;
|
|
|
|
|
|
|
|
DPRINT("IopDeleteIoCompletion()\n");
|
|
|
|
|
|
|
|
/* Rundown the Queue */
|
|
|
|
FirstEntry = KeRundownQueue(Queue);
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-03-12 19:58:53 +00:00
|
|
|
/* Clean up the IRPs */
|
|
|
|
if (FirstEntry) {
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-03-12 19:58:53 +00:00
|
|
|
CurrentEntry = FirstEntry;
|
|
|
|
do {
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-03-12 19:58:53 +00:00
|
|
|
/* Get the Packet */
|
|
|
|
Packet = CONTAINING_RECORD(CurrentEntry, IO_COMPLETION_PACKET, ListEntry);
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-03-12 19:58:53 +00:00
|
|
|
/* Go to next Entry */
|
|
|
|
CurrentEntry = CurrentEntry->Flink;
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-05-13 05:41:24 +00:00
|
|
|
/* Check if it's part of an IRP, or a separate packet */
|
|
|
|
if (Packet->PacketType == IrpCompletionPacket)
|
|
|
|
{
|
|
|
|
/* Get the IRP and free it */
|
|
|
|
Irp = CONTAINING_RECORD(Packet, IRP, Tail.Overlay.ListEntry);
|
|
|
|
IoFreeIrp(Irp);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Use common routine */
|
|
|
|
IopFreeIoCompletionPacket(Packet);
|
|
|
|
}
|
2005-03-12 19:58:53 +00:00
|
|
|
} while (FirstEntry != CurrentEntry);
|
|
|
|
}
|
2003-03-19 23:17:52 +00:00
|
|
|
}
|
|
|
|
|
2004-06-23 21:42:50 +00:00
|
|
|
/*
|
2005-03-12 19:58:53 +00:00
|
|
|
* @implemented
|
2004-06-23 21:42:50 +00:00
|
|
|
*/
|
|
|
|
NTSTATUS
|
2004-08-21 20:55:41 +00:00
|
|
|
STDCALL
|
2005-03-12 19:58:53 +00:00
|
|
|
IoSetIoCompletion(IN PVOID IoCompletion,
|
|
|
|
IN PVOID KeyContext,
|
|
|
|
IN PVOID ApcContext,
|
|
|
|
IN NTSTATUS IoStatus,
|
|
|
|
IN ULONG_PTR IoStatusInformation,
|
|
|
|
IN BOOLEAN Quota)
|
2004-06-23 21:42:50 +00:00
|
|
|
{
|
2005-03-12 19:58:53 +00:00
|
|
|
PKQUEUE Queue = (PKQUEUE)IoCompletion;
|
2005-05-13 05:41:24 +00:00
|
|
|
PNPAGED_LOOKASIDE_LIST List;
|
|
|
|
PKPRCB Prcb = KeGetCurrentPrcb();
|
2005-03-12 19:58:53 +00:00
|
|
|
PIO_COMPLETION_PACKET Packet;
|
|
|
|
|
2005-05-13 05:41:24 +00:00
|
|
|
/* Get the P List */
|
|
|
|
List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[LookasideCompletionList].P;
|
|
|
|
|
|
|
|
/* Try to allocate the Packet */
|
|
|
|
List->L.TotalAllocates++;
|
|
|
|
Packet = (PVOID)InterlockedPopEntrySList(&List->L.ListHead);
|
|
|
|
|
|
|
|
/* Check if that failed, use the L list if it did */
|
|
|
|
if (!Packet)
|
|
|
|
{
|
|
|
|
/* Let the balancer know */
|
|
|
|
List->L.AllocateMisses++;
|
|
|
|
|
|
|
|
/* Get L List */
|
|
|
|
List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[LookasideCompletionList].L;
|
|
|
|
|
|
|
|
/* Try to allocate the Packet */
|
|
|
|
List->L.TotalAllocates++;
|
|
|
|
Packet = (PVOID)InterlockedPopEntrySList(&List->L.ListHead);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Still failed, use pool */
|
|
|
|
if (!Packet)
|
|
|
|
{
|
|
|
|
/* Let the balancer know */
|
|
|
|
List->L.AllocateMisses++;
|
|
|
|
|
|
|
|
/* Allocate from Nonpaged Pool */
|
|
|
|
Packet = ExAllocatePoolWithTag(NonPagedPool, sizeof(*Packet), IOC_TAG);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Make sure we have one by now... */
|
|
|
|
if (Packet)
|
|
|
|
{
|
|
|
|
/* Set up the Packet */
|
|
|
|
Packet->PacketType = IrpMiniCompletionPacket;
|
|
|
|
Packet->Key = KeyContext;
|
|
|
|
Packet->Context = ApcContext;
|
|
|
|
Packet->IoStatus.Status = IoStatus;
|
|
|
|
Packet->IoStatus.Information = IoStatusInformation;
|
|
|
|
|
|
|
|
/* Insert the Queue */
|
|
|
|
KeInsertQueue(Queue, &Packet->ListEntry);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
2005-03-12 19:58:53 +00:00
|
|
|
|
|
|
|
/* Return Success */
|
|
|
|
return STATUS_SUCCESS;
|
2004-06-23 21:42:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2005-03-12 19:58:53 +00:00
|
|
|
* @unimplemented
|
2004-06-23 21:42:50 +00:00
|
|
|
*/
|
|
|
|
NTSTATUS
|
2004-08-21 20:55:41 +00:00
|
|
|
STDCALL
|
2005-03-12 19:58:53 +00:00
|
|
|
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)
|
2004-06-23 21:42:50 +00:00
|
|
|
{
|
2005-03-12 19:58:53 +00:00
|
|
|
UNIMPLEMENTED;
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
2004-06-23 21:42:50 +00:00
|
|
|
}
|
|
|
|
|
2004-12-21 18:37:28 +00:00
|
|
|
VOID
|
|
|
|
FASTCALL
|
|
|
|
IopInitIoCompletionImplementation(VOID)
|
2003-03-19 23:17:52 +00:00
|
|
|
{
|
2005-05-15 17:59:33 +00:00
|
|
|
OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
|
|
|
|
UNICODE_STRING Name;
|
|
|
|
|
2005-05-21 16:33:23 +00:00
|
|
|
DPRINT("Creating IoCompletion Object Type\n");
|
2005-05-15 17:59:33 +00:00
|
|
|
|
|
|
|
/* Initialize the Driver object type */
|
|
|
|
RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
|
|
|
|
RtlInitUnicodeString(&Name, L"IoCompletion");
|
|
|
|
ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
|
|
|
|
ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(KQUEUE);
|
|
|
|
ObjectTypeInitializer.PoolType = NonPagedPool;
|
|
|
|
ObjectTypeInitializer.ValidAccessMask = IO_COMPLETION_ALL_ACCESS;
|
|
|
|
ObjectTypeInitializer.UseDefaultObject = TRUE;
|
|
|
|
ObjectTypeInitializer.GenericMapping = IopCompletionMapping;
|
|
|
|
ObjectTypeInitializer.DeleteProcedure = IopDeleteIoCompletion;
|
|
|
|
ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &IoCompletionType);
|
2003-03-19 23:17:52 +00:00
|
|
|
}
|
|
|
|
|
1999-06-18 22:11:21 +00:00
|
|
|
NTSTATUS
|
|
|
|
STDCALL
|
2005-03-12 19:58:53 +00:00
|
|
|
NtCreateIoCompletion(OUT PHANDLE IoCompletionHandle,
|
|
|
|
IN ACCESS_MASK DesiredAccess,
|
|
|
|
IN POBJECT_ATTRIBUTES ObjectAttributes,
|
|
|
|
IN ULONG NumberOfConcurrentThreads)
|
1998-10-05 04:00:59 +00:00
|
|
|
{
|
2005-03-12 19:58:53 +00:00
|
|
|
PKQUEUE Queue;
|
|
|
|
HANDLE hIoCompletionHandle;
|
|
|
|
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-03-12 19:58:53 +00:00
|
|
|
PAGED_CODE();
|
2005-02-28 17:40:15 +00:00
|
|
|
|
2005-03-12 19:58:53 +00:00
|
|
|
if (PreviousMode != KernelMode) {
|
2005-02-28 17:40:15 +00:00
|
|
|
|
2005-03-12 19:58:53 +00:00
|
|
|
_SEH_TRY {
|
2005-02-28 17:40:15 +00:00
|
|
|
|
2005-08-21 19:04:23 +00:00
|
|
|
ProbeForWriteHandle(IoCompletionHandle);
|
2005-03-12 19:58:53 +00:00
|
|
|
} _SEH_HANDLE {
|
2005-02-28 17:40:15 +00:00
|
|
|
|
2005-03-12 19:58:53 +00:00
|
|
|
Status = _SEH_GetExceptionCode();
|
|
|
|
} _SEH_END;
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-03-12 19:58:53 +00:00
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create the Object */
|
|
|
|
Status = ObCreateObject(PreviousMode,
|
2005-05-15 17:59:33 +00:00
|
|
|
IoCompletionType,
|
2005-03-12 19:58:53 +00:00
|
|
|
ObjectAttributes,
|
|
|
|
PreviousMode,
|
|
|
|
NULL,
|
|
|
|
sizeof(KQUEUE),
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
(PVOID*)&Queue);
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-03-12 19:58:53 +00:00
|
|
|
/* Check for success */
|
|
|
|
if (NT_SUCCESS(Status)) {
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-03-12 19:58:53 +00:00
|
|
|
/* Initialize the Queue */
|
|
|
|
KeInitializeQueue(Queue, NumberOfConcurrentThreads);
|
|
|
|
|
|
|
|
/* Insert it */
|
|
|
|
Status = ObInsertObject(Queue,
|
|
|
|
NULL,
|
|
|
|
DesiredAccess,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
&hIoCompletionHandle);
|
|
|
|
ObDereferenceObject(Queue);
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-03-12 19:58:53 +00:00
|
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
|
|
|
|
_SEH_TRY {
|
|
|
|
|
|
|
|
*IoCompletionHandle = hIoCompletionHandle;
|
|
|
|
} _SEH_HANDLE {
|
|
|
|
|
|
|
|
Status = _SEH_GetExceptionCode();
|
|
|
|
} _SEH_END;
|
|
|
|
}
|
|
|
|
}
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-03-12 19:58:53 +00:00
|
|
|
/* Return Status */
|
|
|
|
return Status;
|
1998-10-05 04:00:59 +00:00
|
|
|
}
|
|
|
|
|
1999-06-18 22:11:21 +00:00
|
|
|
NTSTATUS
|
|
|
|
STDCALL
|
2005-03-12 19:58:53 +00:00
|
|
|
NtOpenIoCompletion(OUT PHANDLE IoCompletionHandle,
|
|
|
|
IN ACCESS_MASK DesiredAccess,
|
|
|
|
IN POBJECT_ATTRIBUTES ObjectAttributes)
|
1998-10-05 04:00:59 +00:00
|
|
|
{
|
2005-03-12 19:58:53 +00:00
|
|
|
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
|
|
|
HANDLE hIoCompletionHandle;
|
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-03-12 19:58:53 +00:00
|
|
|
PAGED_CODE();
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-03-12 19:58:53 +00:00
|
|
|
if(PreviousMode != KernelMode) {
|
|
|
|
|
|
|
|
_SEH_TRY {
|
|
|
|
|
2005-08-21 19:04:23 +00:00
|
|
|
ProbeForWriteHandle(IoCompletionHandle);
|
2005-03-12 19:58:53 +00:00
|
|
|
} _SEH_HANDLE {
|
|
|
|
|
|
|
|
Status = _SEH_GetExceptionCode();
|
|
|
|
} _SEH_END;
|
|
|
|
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
}
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-03-12 19:58:53 +00:00
|
|
|
/* Open the Object */
|
|
|
|
Status = ObOpenObjectByName(ObjectAttributes,
|
2005-05-15 17:59:33 +00:00
|
|
|
IoCompletionType,
|
2005-03-12 19:58:53 +00:00
|
|
|
NULL,
|
|
|
|
PreviousMode,
|
|
|
|
DesiredAccess,
|
|
|
|
NULL,
|
|
|
|
&hIoCompletionHandle);
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-03-12 19:58:53 +00:00
|
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
|
|
|
|
_SEH_TRY {
|
|
|
|
|
|
|
|
*IoCompletionHandle = hIoCompletionHandle;
|
|
|
|
} _SEH_HANDLE {
|
|
|
|
|
|
|
|
Status = _SEH_GetExceptionCode();
|
|
|
|
} _SEH_END;
|
|
|
|
}
|
2005-05-09 01:38:29 +00:00
|
|
|
|
|
|
|
/* Return Status */
|
2005-03-12 19:58:53 +00:00
|
|
|
return Status;
|
1998-10-05 04:00:59 +00:00
|
|
|
}
|
|
|
|
|
2005-02-28 17:40:15 +00:00
|
|
|
|
1999-06-18 22:11:21 +00:00
|
|
|
NTSTATUS
|
|
|
|
STDCALL
|
2005-03-12 19:58:53 +00:00
|
|
|
NtQueryIoCompletion(IN HANDLE IoCompletionHandle,
|
|
|
|
IN IO_COMPLETION_INFORMATION_CLASS IoCompletionInformationClass,
|
|
|
|
OUT PVOID IoCompletionInformation,
|
|
|
|
IN ULONG IoCompletionInformationLength,
|
|
|
|
OUT PULONG ResultLength OPTIONAL)
|
1998-10-05 04:00:59 +00:00
|
|
|
{
|
2005-03-12 19:58:53 +00:00
|
|
|
PKQUEUE Queue;
|
|
|
|
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-03-12 19:58:53 +00:00
|
|
|
PAGED_CODE();
|
|
|
|
|
|
|
|
/* Check buffers and parameters */
|
|
|
|
DefaultQueryInfoBufferCheck(IoCompletionInformationClass,
|
2005-05-15 17:59:33 +00:00
|
|
|
IoCompletionInfoClass,
|
2005-03-12 19:58:53 +00:00
|
|
|
IoCompletionInformation,
|
|
|
|
IoCompletionInformationLength,
|
|
|
|
ResultLength,
|
|
|
|
PreviousMode,
|
|
|
|
&Status);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
|
|
|
|
|
|
DPRINT1("NtQueryMutant() failed, Status: 0x%x\n", Status);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get the Object */
|
|
|
|
Status = ObReferenceObjectByHandle(IoCompletionHandle,
|
2003-03-19 23:17:52 +00:00
|
|
|
IO_COMPLETION_QUERY_STATE,
|
2005-05-15 17:59:33 +00:00
|
|
|
IoCompletionType,
|
2005-03-12 19:58:53 +00:00
|
|
|
PreviousMode,
|
2003-03-19 23:17:52 +00:00
|
|
|
(PVOID*)&Queue,
|
|
|
|
NULL);
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-03-12 19:58:53 +00:00
|
|
|
/* Check for Success */
|
|
|
|
if (NT_SUCCESS(Status)) {
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-03-12 19:58:53 +00:00
|
|
|
_SEH_TRY {
|
2003-03-19 23:17:52 +00:00
|
|
|
|
2005-03-12 19:58:53 +00:00
|
|
|
/* Return Info */
|
|
|
|
((PIO_COMPLETION_BASIC_INFORMATION)IoCompletionInformation)->Depth = KeReadStateQueue(Queue);
|
|
|
|
ObDereferenceObject(Queue);
|
2003-03-19 23:17:52 +00:00
|
|
|
|
2005-03-12 19:58:53 +00:00
|
|
|
/* Return Result Length if needed */
|
|
|
|
if (ResultLength) {
|
2005-02-28 17:40:15 +00:00
|
|
|
|
2005-03-12 19:58:53 +00:00
|
|
|
*ResultLength = sizeof(IO_COMPLETION_BASIC_INFORMATION);
|
|
|
|
}
|
|
|
|
} _SEH_HANDLE {
|
1998-10-05 04:00:59 +00:00
|
|
|
|
2005-03-12 19:58:53 +00:00
|
|
|
Status = _SEH_GetExceptionCode();
|
|
|
|
} _SEH_END;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return Status */
|
|
|
|
return Status;
|
|
|
|
}
|
2005-02-28 17:40:15 +00:00
|
|
|
|
2003-03-19 23:17:52 +00:00
|
|
|
/*
|
|
|
|
* Dequeues an I/O completion message from an I/O completion object
|
|
|
|
*/
|
1999-06-18 22:11:21 +00:00
|
|
|
NTSTATUS
|
|
|
|
STDCALL
|
2005-03-12 19:58:53 +00:00
|
|
|
NtRemoveIoCompletion(IN HANDLE IoCompletionHandle,
|
|
|
|
OUT PVOID *CompletionKey,
|
|
|
|
OUT PVOID *CompletionContext,
|
|
|
|
OUT PIO_STATUS_BLOCK IoStatusBlock,
|
|
|
|
IN PLARGE_INTEGER Timeout OPTIONAL)
|
1998-10-05 04:00:59 +00:00
|
|
|
{
|
2005-03-12 19:58:53 +00:00
|
|
|
LARGE_INTEGER SafeTimeout;
|
|
|
|
PKQUEUE Queue;
|
|
|
|
PIO_COMPLETION_PACKET Packet;
|
|
|
|
PLIST_ENTRY ListEntry;
|
|
|
|
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-03-12 19:58:53 +00:00
|
|
|
PAGED_CODE();
|
|
|
|
|
|
|
|
if (PreviousMode != KernelMode) {
|
|
|
|
|
|
|
|
_SEH_TRY {
|
|
|
|
|
2005-08-21 19:04:23 +00:00
|
|
|
ProbeForWritePointer(CompletionKey);
|
|
|
|
ProbeForWritePointer(CompletionContext);
|
2005-03-12 19:58:53 +00:00
|
|
|
ProbeForWrite(IoStatusBlock,
|
|
|
|
sizeof(IO_STATUS_BLOCK),
|
|
|
|
sizeof(ULONG));
|
|
|
|
if (Timeout != NULL) {
|
|
|
|
|
2005-08-21 19:04:23 +00:00
|
|
|
SafeTimeout = ProbeForReadLargeInteger(Timeout);
|
2005-03-12 19:58:53 +00:00
|
|
|
Timeout = &SafeTimeout;
|
|
|
|
}
|
|
|
|
} _SEH_HANDLE {
|
|
|
|
|
|
|
|
Status = _SEH_GetExceptionCode();
|
|
|
|
} _SEH_END;
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-03-12 19:58:53 +00:00
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
}
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-03-12 19:58:53 +00:00
|
|
|
/* Open the Object */
|
|
|
|
Status = ObReferenceObjectByHandle(IoCompletionHandle,
|
2003-03-19 23:17:52 +00:00
|
|
|
IO_COMPLETION_MODIFY_STATE,
|
2005-05-15 17:59:33 +00:00
|
|
|
IoCompletionType,
|
2005-03-12 19:58:53 +00:00
|
|
|
PreviousMode,
|
2003-03-19 23:17:52 +00:00
|
|
|
(PVOID*)&Queue,
|
|
|
|
NULL);
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-03-12 19:58:53 +00:00
|
|
|
/* Check for success */
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
|
|
|
|
/* Remove queue */
|
|
|
|
ListEntry = KeRemoveQueue(Queue, PreviousMode, Timeout);
|
|
|
|
|
|
|
|
/* If we got a timeout or user_apc back, return the status */
|
|
|
|
if ((NTSTATUS)ListEntry == STATUS_TIMEOUT || (NTSTATUS)ListEntry == STATUS_USER_APC) {
|
2005-05-09 01:38:29 +00:00
|
|
|
|
|
|
|
Status = (NTSTATUS)ListEntry;
|
|
|
|
|
2005-03-12 19:58:53 +00:00
|
|
|
} else {
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-03-12 19:58:53 +00:00
|
|
|
/* Get the Packet Data */
|
|
|
|
Packet = CONTAINING_RECORD(ListEntry, IO_COMPLETION_PACKET, ListEntry);
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-03-12 19:58:53 +00:00
|
|
|
_SEH_TRY {
|
|
|
|
|
2005-05-13 05:41:24 +00:00
|
|
|
/* Check if this is piggybacked on an IRP */
|
|
|
|
if (Packet->PacketType == IrpCompletionPacket)
|
|
|
|
{
|
|
|
|
/* Get the IRP */
|
|
|
|
PIRP Irp = NULL;
|
|
|
|
Irp = CONTAINING_RECORD(ListEntry, IRP, Tail.Overlay.ListEntry);
|
|
|
|
|
|
|
|
/* Return values to user */
|
|
|
|
*CompletionKey = Irp->Tail.CompletionKey;
|
|
|
|
*CompletionContext = Irp->Overlay.AsynchronousParameters.UserApcContext;
|
|
|
|
*IoStatusBlock = Packet->IoStatus;
|
|
|
|
IoFreeIrp(Irp);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* This is a user-mode generated or API generated mini-packet */
|
|
|
|
*CompletionKey = Packet->Key;
|
|
|
|
*CompletionContext = Packet->Context;
|
|
|
|
*IoStatusBlock = Packet->IoStatus;
|
|
|
|
IopFreeIoCompletionPacket(Packet);
|
|
|
|
}
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-03-12 19:58:53 +00:00
|
|
|
} _SEH_HANDLE {
|
|
|
|
|
|
|
|
Status = _SEH_GetExceptionCode();
|
|
|
|
} _SEH_END;
|
|
|
|
}
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-03-12 19:58:53 +00:00
|
|
|
/* Dereference the Object */
|
|
|
|
ObDereferenceObject(Queue);
|
|
|
|
}
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-03-12 19:58:53 +00:00
|
|
|
/* Return status */
|
|
|
|
return Status;
|
1998-10-05 04:00:59 +00:00
|
|
|
}
|
|
|
|
|
2003-03-19 23:17:52 +00:00
|
|
|
/*
|
|
|
|
* Queues an I/O completion message to an I/O completion object
|
|
|
|
*/
|
1999-06-18 22:11:21 +00:00
|
|
|
NTSTATUS
|
|
|
|
STDCALL
|
2005-03-12 19:58:53 +00:00
|
|
|
NtSetIoCompletion(IN HANDLE IoCompletionPortHandle,
|
|
|
|
IN PVOID CompletionKey,
|
|
|
|
IN PVOID CompletionContext,
|
|
|
|
IN NTSTATUS CompletionStatus,
|
|
|
|
IN ULONG CompletionInformation)
|
1998-10-05 04:00:59 +00:00
|
|
|
{
|
2005-03-12 19:58:53 +00:00
|
|
|
NTSTATUS Status;
|
|
|
|
PKQUEUE Queue;
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-03-12 19:58:53 +00:00
|
|
|
PAGED_CODE();
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-03-12 19:58:53 +00:00
|
|
|
/* Get the Object */
|
|
|
|
Status = ObReferenceObjectByHandle(IoCompletionPortHandle,
|
2003-03-19 23:17:52 +00:00
|
|
|
IO_COMPLETION_MODIFY_STATE,
|
2005-05-15 17:59:33 +00:00
|
|
|
IoCompletionType,
|
2005-03-12 19:58:53 +00:00
|
|
|
ExGetPreviousMode(),
|
2003-03-19 23:17:52 +00:00
|
|
|
(PVOID*)&Queue,
|
|
|
|
NULL);
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-03-12 19:58:53 +00:00
|
|
|
/* Check for Success */
|
|
|
|
if (NT_SUCCESS(Status)) {
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-03-12 19:58:53 +00:00
|
|
|
/* Set the Completion */
|
2005-05-09 01:38:29 +00:00
|
|
|
Status = IoSetIoCompletion(Queue,
|
|
|
|
CompletionKey,
|
2005-03-12 19:58:53 +00:00
|
|
|
CompletionContext,
|
2005-05-09 01:38:29 +00:00
|
|
|
CompletionStatus,
|
|
|
|
CompletionInformation,
|
2005-03-12 19:58:53 +00:00
|
|
|
TRUE);
|
|
|
|
ObDereferenceObject(Queue);
|
|
|
|
}
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-03-12 19:58:53 +00:00
|
|
|
/* Return status */
|
|
|
|
return Status;
|
1998-10-05 04:00:59 +00:00
|
|
|
}
|