2005-02-28 16:44:38 +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.
|
|
|
|
*
|
|
|
|
* 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>
|
|
|
|
|
2003-03-19 23:17:52 +00:00
|
|
|
#define IOC_TAG TAG('I', 'O', 'C', 'T')
|
|
|
|
|
|
|
|
POBJECT_TYPE ExIoCompletionType;
|
|
|
|
|
2005-02-28 16:44:38 +00:00
|
|
|
NPAGED_LOOKASIDE_LIST IoCompletionPacketLookaside;
|
2003-03-19 23:17:52 +00:00
|
|
|
|
|
|
|
static GENERIC_MAPPING ExIoCompletionMapping =
|
|
|
|
{
|
2005-02-28 16:44:38 +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
|
|
|
};
|
|
|
|
|
1998-10-05 04:00:59 +00:00
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
|
2005-02-28 16:44:38 +00:00
|
|
|
VOID
|
2003-03-19 23:17:52 +00:00
|
|
|
STDCALL
|
2005-02-07 10:33:44 +00:00
|
|
|
IopDeleteIoCompletion(PVOID ObjectBody)
|
2003-03-19 23:17:52 +00:00
|
|
|
{
|
2005-02-28 16:44:38 +00:00
|
|
|
PKQUEUE Queue = ObjectBody;
|
|
|
|
PLIST_ENTRY FirstEntry;
|
|
|
|
PLIST_ENTRY CurrentEntry;
|
|
|
|
PIO_COMPLETION_PACKET Packet;
|
|
|
|
|
|
|
|
DPRINT("IopDeleteIoCompletion()\n");
|
|
|
|
|
|
|
|
/* 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);
|
|
|
|
}
|
2003-03-19 23:17:52 +00:00
|
|
|
}
|
|
|
|
|
2004-06-23 21:42:50 +00:00
|
|
|
/*
|
2005-02-28 16:44:38 +00:00
|
|
|
* @implemented
|
2004-06-23 21:42:50 +00:00
|
|
|
*/
|
|
|
|
NTSTATUS
|
2004-08-21 20:55:41 +00:00
|
|
|
STDCALL
|
2005-02-28 16:44:38 +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-02-28 16:44:38 +00:00
|
|
|
PKQUEUE Queue = (PKQUEUE)IoCompletion;
|
|
|
|
PIO_COMPLETION_PACKET Packet;
|
|
|
|
|
|
|
|
/* Allocate the Packet */
|
|
|
|
Packet = ExAllocateFromNPagedLookasideList(&IoCompletionPacketLookaside);
|
|
|
|
if (NULL == Packet) return STATUS_NO_MEMORY;
|
|
|
|
|
|
|
|
/* Set up the Packet */
|
|
|
|
Packet->Key = KeyContext;
|
|
|
|
Packet->Context = ApcContext;
|
|
|
|
Packet->IoStatus.Status = IoStatus;
|
|
|
|
Packet->IoStatus.Information = IoStatusInformation;
|
|
|
|
|
|
|
|
/* Insert the Queue */
|
|
|
|
KeInsertQueue(Queue, &Packet->ListEntry);
|
|
|
|
|
|
|
|
/* Return Success */
|
|
|
|
return STATUS_SUCCESS;
|
2004-06-23 21:42:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2005-02-28 16:44:38 +00:00
|
|
|
* @unimplemented
|
2004-06-23 21:42:50 +00:00
|
|
|
*/
|
|
|
|
NTSTATUS
|
2004-08-21 20:55:41 +00:00
|
|
|
STDCALL
|
2005-02-28 16:44:38 +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-02-28 16:44:38 +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-02-28 16:44:38 +00:00
|
|
|
/* Create the IO Completion Type */
|
|
|
|
ExIoCompletionType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE));
|
|
|
|
RtlpCreateUnicodeString(&ExIoCompletionType->TypeName, L"IoCompletion", NonPagedPool);
|
|
|
|
ExIoCompletionType->Tag = IOC_TAG;
|
|
|
|
ExIoCompletionType->PeakObjects = 0;
|
|
|
|
ExIoCompletionType->PeakHandles = 0;
|
|
|
|
ExIoCompletionType->TotalObjects = 0;
|
|
|
|
ExIoCompletionType->TotalHandles = 0;
|
|
|
|
ExIoCompletionType->PagedPoolCharge = 0;
|
|
|
|
ExIoCompletionType->NonpagedPoolCharge = sizeof(KQUEUE);
|
|
|
|
ExIoCompletionType->Mapping = &ExIoCompletionMapping;
|
|
|
|
ExIoCompletionType->Dump = NULL;
|
|
|
|
ExIoCompletionType->Open = NULL;
|
|
|
|
ExIoCompletionType->Close = NULL;
|
|
|
|
ExIoCompletionType->Delete = IopDeleteIoCompletion;
|
|
|
|
ExIoCompletionType->Parse = NULL;
|
|
|
|
ExIoCompletionType->Security = NULL;
|
|
|
|
ExIoCompletionType->QueryName = NULL;
|
|
|
|
ExIoCompletionType->OkayToClose = NULL;
|
|
|
|
ExIoCompletionType->Create = NULL;
|
|
|
|
ExIoCompletionType->DuplicationNotify = NULL;
|
|
|
|
|
|
|
|
/* Initialize the Lookaside List we'll use for packets */
|
|
|
|
ExInitializeNPagedLookasideList(&IoCompletionPacketLookaside,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
sizeof(IO_COMPLETION_PACKET),
|
|
|
|
IOC_TAG,
|
|
|
|
0);
|
2003-03-19 23:17:52 +00:00
|
|
|
}
|
|
|
|
|
1999-06-18 22:11:21 +00:00
|
|
|
NTSTATUS
|
|
|
|
STDCALL
|
2005-02-28 16:44:38 +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-02-28 16:44:38 +00:00
|
|
|
PKQUEUE Queue;
|
|
|
|
NTSTATUS Status;
|
|
|
|
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
|
|
|
|
|
|
|
/* Create the Object */
|
|
|
|
Status = ObCreateObject(PreviousMode,
|
|
|
|
ExIoCompletionType,
|
|
|
|
ObjectAttributes,
|
|
|
|
PreviousMode,
|
|
|
|
NULL,
|
|
|
|
sizeof(KQUEUE),
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
(PVOID*)&Queue);
|
|
|
|
|
|
|
|
/* Check for success */
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
|
|
|
|
/* Initialize the Queue */
|
|
|
|
KeInitializeQueue(Queue, NumberOfConcurrentThreads);
|
|
|
|
|
|
|
|
/* Insert it */
|
|
|
|
Status = ObInsertObject(Queue,
|
|
|
|
NULL,
|
|
|
|
DesiredAccess,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
IoCompletionHandle);
|
|
|
|
ObDereferenceObject(Queue);
|
2003-03-19 23:17:52 +00:00
|
|
|
}
|
2005-02-28 16:44:38 +00:00
|
|
|
|
|
|
|
/* Return Status */
|
2003-09-25 20:09:56 +00:00
|
|
|
return STATUS_SUCCESS;
|
1998-10-05 04:00:59 +00:00
|
|
|
}
|
|
|
|
|
1999-06-18 22:11:21 +00:00
|
|
|
NTSTATUS
|
|
|
|
STDCALL
|
2005-02-28 16:44:38 +00:00
|
|
|
NtOpenIoCompletion(OUT PHANDLE IoCompletionHandle,
|
|
|
|
IN ACCESS_MASK DesiredAccess,
|
|
|
|
IN POBJECT_ATTRIBUTES ObjectAttributes)
|
1998-10-05 04:00:59 +00:00
|
|
|
{
|
2005-02-28 16:44:38 +00:00
|
|
|
NTSTATUS Status;
|
|
|
|
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
|
|
|
|
|
|
|
/* Open the Object */
|
|
|
|
Status = ObOpenObjectByName(ObjectAttributes,
|
|
|
|
ExIoCompletionType,
|
|
|
|
NULL,
|
|
|
|
PreviousMode,
|
|
|
|
DesiredAccess,
|
|
|
|
NULL,
|
|
|
|
IoCompletionHandle);
|
|
|
|
|
|
|
|
/* Return Status */
|
|
|
|
return Status;
|
1998-10-05 04:00:59 +00:00
|
|
|
}
|
|
|
|
|
1999-06-18 22:11:21 +00:00
|
|
|
NTSTATUS
|
|
|
|
STDCALL
|
2005-02-28 16:44:38 +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-02-28 16:44:38 +00:00
|
|
|
PKQUEUE Queue;
|
|
|
|
NTSTATUS Status;
|
|
|
|
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
2003-03-19 23:17:52 +00:00
|
|
|
|
2005-02-28 16:44:38 +00:00
|
|
|
/* Get the Object */
|
|
|
|
Status = ObReferenceObjectByHandle(IoCompletionHandle,
|
2003-03-19 23:17:52 +00:00
|
|
|
IO_COMPLETION_QUERY_STATE,
|
|
|
|
ExIoCompletionType,
|
2005-02-28 16:44:38 +00:00
|
|
|
PreviousMode,
|
2003-03-19 23:17:52 +00:00
|
|
|
(PVOID*)&Queue,
|
|
|
|
NULL);
|
2005-02-28 16:44:38 +00:00
|
|
|
|
|
|
|
/* Check for Success */
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
|
|
|
|
/* Return Info */
|
|
|
|
((PIO_COMPLETION_BASIC_INFORMATION)IoCompletionInformation)->Depth = KeReadStateQueue(Queue);
|
|
|
|
ObDereferenceObject(Queue);
|
2003-03-19 23:17:52 +00:00
|
|
|
|
2005-02-28 16:44:38 +00:00
|
|
|
/* Return Result Length if needed */
|
|
|
|
if (ResultLength) *ResultLength = sizeof(IO_COMPLETION_BASIC_INFORMATION);
|
|
|
|
}
|
2003-03-19 23:17:52 +00:00
|
|
|
|
2005-02-28 16:44:38 +00:00
|
|
|
/* Return Status */
|
|
|
|
return Status;
|
1998-10-05 04:00:59 +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-02-28 16:44:38 +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-02-28 16:44:38 +00:00
|
|
|
PKQUEUE Queue;
|
|
|
|
NTSTATUS Status;
|
|
|
|
PIO_COMPLETION_PACKET Packet;
|
|
|
|
PLIST_ENTRY ListEntry;
|
|
|
|
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
|
|
|
|
|
|
|
/* Open the Object */
|
|
|
|
Status = ObReferenceObjectByHandle(IoCompletionHandle,
|
2003-03-19 23:17:52 +00:00
|
|
|
IO_COMPLETION_MODIFY_STATE,
|
|
|
|
ExIoCompletionType,
|
2005-02-28 16:44:38 +00:00
|
|
|
PreviousMode,
|
2003-03-19 23:17:52 +00:00
|
|
|
(PVOID*)&Queue,
|
|
|
|
NULL);
|
2005-02-28 16:44:38 +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) {
|
|
|
|
|
|
|
|
Status = (NTSTATUS)ListEntry;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
/* Get the Packet Data */
|
|
|
|
Packet = CONTAINING_RECORD(ListEntry, IO_COMPLETION_PACKET, ListEntry);
|
|
|
|
|
|
|
|
/* Return it */
|
|
|
|
if (CompletionKey) *CompletionKey = Packet->Key;
|
|
|
|
if (CompletionContext) *CompletionContext = Packet->Context;
|
|
|
|
if (IoStatusBlock) *IoStatusBlock = Packet->IoStatus;
|
|
|
|
|
|
|
|
/* Free packet */
|
|
|
|
ExFreeToNPagedLookasideList(&IoCompletionPacketLookaside, Packet);
|
|
|
|
}
|
2004-12-21 02:34:32 +00:00
|
|
|
|
2005-02-28 16:44:38 +00:00
|
|
|
/* Dereference the Object */
|
|
|
|
ObDereferenceObject(Queue);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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-02-28 16:44:38 +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-02-28 16:44:38 +00:00
|
|
|
NTSTATUS Status;
|
|
|
|
PKQUEUE Queue;
|
|
|
|
|
|
|
|
/* Get the Object */
|
|
|
|
Status = ObReferenceObjectByHandle(IoCompletionPortHandle,
|
2003-03-19 23:17:52 +00:00
|
|
|
IO_COMPLETION_MODIFY_STATE,
|
|
|
|
ExIoCompletionType,
|
2005-02-28 16:44:38 +00:00
|
|
|
ExGetPreviousMode(),
|
2003-03-19 23:17:52 +00:00
|
|
|
(PVOID*)&Queue,
|
|
|
|
NULL);
|
2005-02-28 16:44:38 +00:00
|
|
|
|
|
|
|
/* Check for Success */
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
|
|
|
|
/* Set the Completion */
|
|
|
|
Status = IoSetIoCompletion(Queue,
|
|
|
|
CompletionKey,
|
|
|
|
CompletionContext,
|
|
|
|
CompletionStatus,
|
|
|
|
CompletionInformation,
|
|
|
|
TRUE);
|
|
|
|
ObDereferenceObject(Queue);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return status */
|
|
|
|
return Status;
|
1998-10-05 04:00:59 +00:00
|
|
|
}
|