From 957f814a24d3869e3d2d0e54ed94f7b4f8a14ef7 Mon Sep 17 00:00:00 2001 From: Gunnar Dalsnes Date: Wed, 19 Mar 2003 23:17:52 +0000 Subject: [PATCH] initial work on I/O completion svn path=/trunk/; revision=4352 --- reactos/include/ddk/extypes.h | 4 +- reactos/include/ddk/iotypes.h | 8 +- reactos/include/ddk/kefuncs.h | 3 + reactos/include/ddk/ketypes.h | 6 +- reactos/include/ntos/synch.h | 3 + reactos/include/ntos/zw.h | 97 ++++---- reactos/include/ntos/zwtypes.h | 13 ++ reactos/lib/kernel32/file/iocompl.c | 204 ++++++++++------- reactos/ntoskrnl/include/internal/ke.h | 2 + reactos/ntoskrnl/io/file.c | 36 ++- reactos/ntoskrnl/io/iocomp.c | 304 ++++++++++++++++++++++--- reactos/ntoskrnl/ke/queue.c | 131 ++++++++++- 12 files changed, 621 insertions(+), 190 deletions(-) diff --git a/reactos/include/ddk/extypes.h b/reactos/include/ddk/extypes.h index 06d46939e3a..4e6bbc8bda2 100644 --- a/reactos/include/ddk/extypes.h +++ b/reactos/include/ddk/extypes.h @@ -1,4 +1,4 @@ -/* $Id: extypes.h,v 1.12 2002/11/24 18:26:40 robd Exp $ */ +/* $Id: extypes.h,v 1.13 2003/03/19 23:14:11 gdalsnes Exp $ */ #ifndef __INCLUDE_DDK_EXTYPES_H #define __INCLUDE_DDK_EXTYPES_H @@ -7,10 +7,12 @@ extern POBJECT_TYPE EXPORTED ExDesktopObjectType; extern POBJECT_TYPE EXPORTED ExEventObjectType; extern POBJECT_TYPE EXPORTED ExWindowStationObjectType; +extern POBJECT_TYPE EXPORTED ExIoCompletionType; #else extern POBJECT_TYPE IMPORTED ExDesktopObjectType; extern POBJECT_TYPE IMPORTED ExEventObjectType; extern POBJECT_TYPE IMPORTED ExWindowStationObjectType; +extern POBJECT_TYPE IMPORTED ExIoCompletionType; #endif typedef ULONG INTERLOCKED_RESULT; diff --git a/reactos/include/ddk/iotypes.h b/reactos/include/ddk/iotypes.h index 3bf3fa65840..b72d1399d28 100644 --- a/reactos/include/ddk/iotypes.h +++ b/reactos/include/ddk/iotypes.h @@ -1,4 +1,4 @@ -/* $Id: iotypes.h,v 1.45 2002/11/24 18:26:40 robd Exp $ +/* $Id: iotypes.h,v 1.46 2003/03/19 23:14:29 gdalsnes Exp $ * */ @@ -465,6 +465,12 @@ typedef struct _IO_STATUS_BLOCK ULONG Information; } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; +typedef struct _IO_COMPLETION_PACKET{ + ULONG Key; + ULONG Overlapped; + IO_STATUS_BLOCK IoStatus; + LIST_ENTRY ListEntry; +} IO_COMPLETION_PACKET, *PIO_COMPLETION_PACKET; typedef struct _IO_PIPE_CREATE_BUFFER { diff --git a/reactos/include/ddk/kefuncs.h b/reactos/include/ddk/kefuncs.h index b99a1be9f18..6322bf21f39 100644 --- a/reactos/include/ddk/kefuncs.h +++ b/reactos/include/ddk/kefuncs.h @@ -135,6 +135,9 @@ VOID STDCALL KeInitializeQueue(IN PKQUEUE Queue, IN ULONG Count); +PLIST_ENTRY STDCALL +KeRundownQueue(IN PKQUEUE Queue); + VOID STDCALL KeInitializeSemaphore (PKSEMAPHORE Semaphore, LONG Count, LONG Limit); diff --git a/reactos/include/ddk/ketypes.h b/reactos/include/ddk/ketypes.h index be4b6e4ae56..7851386c2c6 100644 --- a/reactos/include/ddk/ketypes.h +++ b/reactos/include/ddk/ketypes.h @@ -122,9 +122,9 @@ typedef struct _KQUEUE { DISPATCHER_HEADER Header; LIST_ENTRY EntryListHead; - ULONG CurrentCount; - ULONG MaximumCount; - LIST_ENTRY ThreadListEntry; + ULONG RunningThreads; + ULONG MaximumThreads; + LIST_ENTRY ThreadListHead; } KQUEUE, *PKQUEUE; struct _KDPC; diff --git a/reactos/include/ntos/synch.h b/reactos/include/ntos/synch.h index be138d4f325..a77a88040e5 100644 --- a/reactos/include/ntos/synch.h +++ b/reactos/include/ntos/synch.h @@ -27,6 +27,9 @@ #define TIMER_ALL_ACCESS (0x1f0003L) #define TIMER_QUERY_STATE (1) #define TIMER_MODIFY_STATE (2) +#define IO_COMPLETION_QUERY_STATE (0x0001) +#define IO_COMPLETION_MODIFY_STATE (0x0002) +#define IO_COMPLETION_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3) #endif /* !__USE_W32API */ diff --git a/reactos/include/ntos/zw.h b/reactos/include/ntos/zw.h index 43f7ce72a5e..1dedb83fe49 100755 --- a/reactos/include/ntos/zw.h +++ b/reactos/include/ntos/zw.h @@ -1,5 +1,5 @@ -/* $Id: zw.h,v 1.8 2003/02/27 22:49:06 ekohl Exp $ +/* $Id: zw.h,v 1.9 2003/03/19 23:16:00 gdalsnes Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -497,21 +497,20 @@ ZwCreateFile( NTSTATUS STDCALL NtCreateIoCompletion( - OUT PHANDLE CompletionPort, - IN ACCESS_MASK DesiredAccess, - OUT PIO_STATUS_BLOCK IoStatusBlock, - IN ULONG NumberOfConcurrentThreads - ); + OUT PHANDLE IoCompletionHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN ULONG NumberOfConcurrentThreads + ); NTSTATUS STDCALL ZwCreateIoCompletion( - OUT PHANDLE CompletionPort, - IN ACCESS_MASK DesiredAccess, - OUT PIO_STATUS_BLOCK IoStatusBlock, - IN ULONG NumberOfConcurrentThreads - ); - + OUT PHANDLE IoCompletionHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN ULONG NumberOfConcurrentThreads + ); /* * FUNCTION: Creates a registry key @@ -2357,20 +2356,22 @@ ZwQueryInformationToken( NTSTATUS STDCALL NtQueryIoCompletion( - IN HANDLE CompletionPort, - IN ULONG CompletionKey, - OUT PIO_STATUS_BLOCK IoStatusBlock, - OUT PULONG NumberOfBytesTransferred - ); + IN HANDLE IoCompletionHandle, + IN IO_COMPLETION_INFORMATION_CLASS IoCompletionInformationClass, + OUT PVOID IoCompletionInformation, + IN ULONG IoCompletionInformationLength, + OUT PULONG ResultLength OPTIONAL + ); + NTSTATUS STDCALL ZwQueryIoCompletion( - IN HANDLE CompletionPort, - IN ULONG CompletionKey, - OUT PIO_STATUS_BLOCK IoStatusBlock, - OUT PULONG NumberOfBytesTransferred - ); - + IN HANDLE IoCompletionHandle, + IN IO_COMPLETION_INFORMATION_CLASS IoCompletionInformationClass, + OUT PVOID IoCompletionInformation, + IN ULONG IoCompletionInformationLength, + OUT PULONG ResultLength OPTIONAL + ); /* * FUNCTION: Queries the information of a registry key object. @@ -2990,22 +2991,23 @@ ZwReleaseSemaphore( NTSTATUS STDCALL NtRemoveIoCompletion( - IN HANDLE CompletionPort, - OUT PULONG CompletionKey, - OUT PIO_STATUS_BLOCK IoStatusBlock, - OUT PULONG CompletionStatus, - IN PLARGE_INTEGER WaitTime - ); + IN HANDLE IoCompletionHandle, + OUT PULONG CompletionKey, + OUT PULONG CompletionValue, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN PLARGE_INTEGER Timeout OPTIONAL + ); NTSTATUS STDCALL ZwRemoveIoCompletion( - IN HANDLE CompletionPort, - OUT PULONG CompletionKey, - OUT PIO_STATUS_BLOCK IoStatusBlock, - OUT PULONG CompletionStatus, - IN PLARGE_INTEGER WaitTime - ); + IN HANDLE IoCompletionHandle, + OUT PULONG CompletionKey, + OUT PULONG CompletionValue, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN PLARGE_INTEGER Timeout OPTIONAL + ); + /* * FUNCTION: Replaces one registry key with another * ARGUMENTS: @@ -3392,21 +3394,22 @@ ZwSetInformationToken( NTSTATUS STDCALL NtSetIoCompletion( - IN HANDLE CompletionPort, - IN ULONG CompletionKey, - OUT PIO_STATUS_BLOCK IoStatusBlock, - IN ULONG NumberOfBytesToTransfer, - OUT PULONG NumberOfBytesTransferred - ); + IN HANDLE IoCompletionPortHandle, + IN ULONG CompletionKey, + IN ULONG CompletionValue, + IN NTSTATUS CompletionStatus, + IN ULONG CompletionInformation + ); + NTSTATUS STDCALL ZwSetIoCompletion( - IN HANDLE CompletionPort, - IN ULONG CompletionKey, - OUT PIO_STATUS_BLOCK IoStatusBlock, - IN ULONG NumberOfBytesToTransfer, - OUT PULONG NumberOfBytesTransferred - ); + IN HANDLE IoCompletionPortHandle, + IN ULONG CompletionKey, + IN ULONG CompletionValue, + IN NTSTATUS CompletionStatus, + IN ULONG CompletionInformation + ); /* * FUNCTION: Set properties for profiling diff --git a/reactos/include/ntos/zwtypes.h b/reactos/include/ntos/zwtypes.h index 4c1a7bfb20d..28a3dcc4926 100755 --- a/reactos/include/ntos/zwtypes.h +++ b/reactos/include/ntos/zwtypes.h @@ -881,6 +881,11 @@ typedef struct _FILE_COMPRESSION_INFORMATION { UCHAR Reserved[3]; } FILE_COMPRESSION_INFORMATION, *PFILE_COMPRESSION_INFORMATION; +typedef struct _FILE_COMPLETION_INFORMATION { // Information Class 30 + HANDLE IoCompletionHandle; + ULONG CompletionKey; +} FILE_COMPLETION_INFORMATION, *PFILE_COMPLETION_INFORMATION; + typedef struct _FILE_ALL_INFORMATION { FILE_BASIC_INFORMATION BasicInformation; FILE_STANDARD_INFORMATION StandardInformation; @@ -1069,6 +1074,14 @@ typedef enum SHUTDOWN_ACTION_TAG { ShutdownPowerOff } SHUTDOWN_ACTION; +typedef enum _IO_COMPLETION_INFORMATION_CLASS { + IoCompletionBasicInformation +} IO_COMPLETION_INFORMATION_CLASS; + +typedef struct _IO_COMPLETION_BASIC_INFORMATION { + LONG SignalState; +} IO_COMPLETION_BASIC_INFORMATION, *PIO_COMPLETION_BASIC_INFORMATION; + #else /* __USE_W32API */ #define DebugDbgLoadSymbols ((DEBUG_CONTROL_CODE)0xffffffff) diff --git a/reactos/lib/kernel32/file/iocompl.c b/reactos/lib/kernel32/file/iocompl.c index 1b406fcadbe..f6f97fbaa2f 100644 --- a/reactos/lib/kernel32/file/iocompl.c +++ b/reactos/lib/kernel32/file/iocompl.c @@ -1,4 +1,4 @@ -/* $Id: iocompl.c,v 1.8 2003/02/03 14:19:30 ekohl Exp $ +/* $Id: iocompl.c,v 1.9 2003/03/19 23:16:55 gdalsnes Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS system libraries @@ -14,23 +14,6 @@ #include - -typedef struct _FILE_COMPLETION_INFORMATION { - HANDLE CompletionPort; - ULONG CompletionKey; -} FILE_COMPLETION_INFORMATION; -typedef FILE_COMPLETION_INFORMATION *PFILE_COMPLETION_INFORMATION; - - -VOID -STDCALL -FileIOCompletionRoutine( - DWORD dwErrorCode, - DWORD dwNumberOfBytesTransfered, - LPOVERLAPPED lpOverlapped - ); - - HANDLE STDCALL CreateIoCompletionPort( @@ -40,99 +23,146 @@ CreateIoCompletionPort( DWORD NumberOfConcurrentThreads ) { - HANDLE CompletionPort = NULL; - NTSTATUS errCode; - FILE_COMPLETION_INFORMATION CompletionInformation; - IO_STATUS_BLOCK IoStatusBlock; + HANDLE CompletionPort = NULL; + NTSTATUS errCode; + FILE_COMPLETION_INFORMATION CompletionInformation; + IO_STATUS_BLOCK IoStatusBlock; - if ( ExistingCompletionPort == NULL && FileHandle == INVALID_HANDLE_VALUE ) { - SetLastErrorByStatus (STATUS_INVALID_PARAMETER); - return FALSE; - } + if ( ExistingCompletionPort == NULL && FileHandle == INVALID_HANDLE_VALUE ) + { + SetLastErrorByStatus (STATUS_INVALID_PARAMETER); + return FALSE; + } - if ( ExistingCompletionPort != NULL ) { - CompletionPort = ExistingCompletionPort; - } - else { - errCode = NtCreateIoCompletion(&CompletionPort,GENERIC_ALL,&IoStatusBlock,NumberOfConcurrentThreads); - if (!NT_SUCCESS(errCode) ) { - SetLastErrorByStatus (errCode); - return FALSE; - } + if ( ExistingCompletionPort != NULL ) + { + CompletionPort = ExistingCompletionPort; + } + else + { - } - if ( FileHandle != INVALID_HANDLE_VALUE ) { + errCode = NtCreateIoCompletion(&CompletionPort, + IO_COMPLETION_ALL_ACCESS, + NULL,//ObjectAttributes + NumberOfConcurrentThreads); - CompletionInformation.CompletionPort = CompletionPort; - CompletionInformation.CompletionKey = CompletionKey; + if (!NT_SUCCESS(errCode) ) + { + SetLastErrorByStatus (errCode); + return FALSE; + } - errCode = NtSetInformationFile(FileHandle, &IoStatusBlock,&CompletionInformation,sizeof(FILE_COMPLETION_INFORMATION),FileCompletionInformation); - if ( !NT_SUCCESS(errCode) ) { - if ( ExistingCompletionPort == NULL ) - NtClose(CompletionPort); - SetLastErrorByStatus (errCode); - return FALSE; - } - } + } + + if ( FileHandle != INVALID_HANDLE_VALUE ) + { + CompletionInformation.IoCompletionHandle = CompletionPort; + CompletionInformation.CompletionKey = CompletionKey; - return CompletionPort; + errCode = NtSetInformationFile(FileHandle, + &IoStatusBlock, + &CompletionInformation, + sizeof(FILE_COMPLETION_INFORMATION), + FileCompletionInformation); + + if ( !NT_SUCCESS(errCode) ) + { + if ( ExistingCompletionPort == NULL ) + { + NtClose(CompletionPort); + } + + SetLastErrorByStatus (errCode); + return FALSE; + } + } + + return CompletionPort; } WINBOOL STDCALL GetQueuedCompletionStatus( - HANDLE CompletionPort, - LPDWORD lpNumberOfBytesTransferred, - LPDWORD lpCompletionKey, - LPOVERLAPPED *lpOverlapped, - DWORD dwMilliseconds - ) + HANDLE CompletionHandle, + LPDWORD lpNumberOfBytesTransferred, + LPDWORD lpCompletionKey, + LPOVERLAPPED *lpOverlapped, + DWORD dwMilliseconds + ) { - NTSTATUS errCode; - ULONG CompletionStatus; - LARGE_INTEGER TimeToWait; + NTSTATUS errCode; + IO_STATUS_BLOCK IoStatus; + LARGE_INTEGER Interval; - errCode = NtRemoveIoCompletion(CompletionPort,(PULONG)lpCompletionKey,(PIO_STATUS_BLOCK)lpOverlapped,&CompletionStatus,&TimeToWait); - if (!NT_SUCCESS(errCode) ) { - SetLastErrorByStatus (errCode); - return FALSE; - } + if (!lpNumberOfBytesTransferred||!lpCompletionKey||!lpOverlapped) + { + return ERROR_INVALID_PARAMETER; + } + + if (dwMilliseconds != INFINITE) + { + /* + * System time units are 100 nanoseconds (a nanosecond is a billionth of + * a second). + */ + Interval.QuadPart = dwMilliseconds; + Interval.QuadPart = -(Interval.QuadPart * 10000); + } + else + { + /* Approximately 292000 years hence */ + Interval.QuadPart = -0x7FFFFFFFFFFFFFFF; + } + + errCode = NtRemoveIoCompletion(CompletionHandle, + lpCompletionKey, + lpNumberOfBytesTransferred, + &IoStatus, + &Interval); + + if (!NT_SUCCESS(errCode) ) { + *lpOverlapped = NULL; + SetLastErrorByStatus(errCode); + return FALSE; + } + + *lpOverlapped = (LPOVERLAPPED)IoStatus.Information; + + if (!NT_SUCCESS(IoStatus.Status)){ + //failed io operation + SetLastErrorByStatus (IoStatus.Status); + return FALSE; + } + + return TRUE; - return TRUE; } WINBOOL STDCALL PostQueuedCompletionStatus( - HANDLE CompletionPort, - DWORD dwNumberOfBytesTransferred, - DWORD dwCompletionKey, - LPOVERLAPPED lpOverlapped -) + HANDLE CompletionHandle, + DWORD dwNumberOfBytesTransferred, + DWORD dwCompletionKey, + LPOVERLAPPED lpOverlapped + ) { - NTSTATUS errCode; - errCode = NtSetIoCompletion(CompletionPort, dwCompletionKey, (PIO_STATUS_BLOCK)lpOverlapped , 0, (PULONG)&dwNumberOfBytesTransferred ); + NTSTATUS errCode; - if ( !NT_SUCCESS(errCode) ) { - SetLastErrorByStatus (errCode); - return FALSE; - } - return TRUE; -} + errCode = NtSetIoCompletion(CompletionHandle, + dwCompletionKey, + dwNumberOfBytesTransferred,//CompletionValue + 0, //IoStatusBlock->Status + (ULONG)lpOverlapped ); //IoStatusBlock->Information - -// this should be a place holder ?????????????????? -VOID -STDCALL -FileIOCompletionRoutine( - DWORD dwErrorCode, - DWORD dwNumberOfBytesTransfered, - LPOVERLAPPED lpOverlapped - ) -{ - return; + if ( !NT_SUCCESS(errCode) ) + { + SetLastErrorByStatus (errCode); + return FALSE; + } + return TRUE; } diff --git a/reactos/ntoskrnl/include/internal/ke.h b/reactos/ntoskrnl/include/internal/ke.h index 93c1ce545f7..e41a3e88ffc 100644 --- a/reactos/ntoskrnl/include/internal/ke.h +++ b/reactos/ntoskrnl/include/internal/ke.h @@ -58,6 +58,8 @@ VOID KiDeliverNormalApc(VOID); BOOLEAN STDCALL KeRemoveQueueApc (PKAPC Apc); +PLIST_ENTRY STDCALL KeRundownQueue(IN PKQUEUE Queue); + /* INITIALIZATION FUNCTIONS *************************************************/ diff --git a/reactos/ntoskrnl/io/file.c b/reactos/ntoskrnl/io/file.c index dc50e9f71ec..3d1a21448c3 100644 --- a/reactos/ntoskrnl/io/file.c +++ b/reactos/ntoskrnl/io/file.c @@ -1,4 +1,4 @@ -/* $Id: file.c,v 1.21 2002/09/08 10:23:24 chorns Exp $ +/* $Id: file.c,v 1.22 2003/03/19 23:11:23 gdalsnes Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -236,7 +236,39 @@ NtSetInformationFile(HANDLE FileHandle, } DPRINT("FileObject %x\n", FileObject); - + + //io completion port? + if (FileInformationClass == FileCompletionInformation) + { + PKQUEUE Queue; + + if (Length < sizeof(FILE_COMPLETION_INFORMATION)) + { + Status = STATUS_INFO_LENGTH_MISMATCH; + } + else + { + Status = ObReferenceObjectByHandle(((PFILE_COMPLETION_INFORMATION)FileInformation)->IoCompletionHandle, + IO_COMPLETION_MODIFY_STATE,//??? + ExIoCompletionType, + UserMode, + (PVOID*)&Queue, + NULL); + if (NT_SUCCESS(Status)) + { + //FIXME: maybe use lookaside list + FileObject->CompletionContext = ExAllocatePool(NonPagedPool, sizeof(IO_COMPLETION_CONTEXT)); + FileObject->CompletionContext->Key = ((PFILE_COMPLETION_INFORMATION)FileInformation)->CompletionKey; + FileObject->CompletionContext->Port = Queue; + + ObDereferenceObject(Queue); + } + } + + ObDereferenceObject(FileObject); + return Status; + } + DeviceObject = FileObject->DeviceObject; Irp = IoAllocateIrp(DeviceObject->StackSize, diff --git a/reactos/ntoskrnl/io/iocomp.c b/reactos/ntoskrnl/io/iocomp.c index 21b672dbad7..0bb9b964eb2 100644 --- a/reactos/ntoskrnl/io/iocomp.c +++ b/reactos/ntoskrnl/io/iocomp.c @@ -11,73 +11,303 @@ /* INCLUDES *****************************************************************/ +#include #include +#include +#define NDEBUG #include +#define IOC_TAG TAG('I', 'O', 'C', 'T') + +POBJECT_TYPE ExIoCompletionType; + +NPAGED_LOOKASIDE_LIST IoCompletionPacketLookaside; + +static GENERIC_MAPPING ExIoCompletionMapping = +{ + 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 +}; + /* FUNCTIONS *****************************************************************/ -NTSTATUS +NTSTATUS STDCALL -NtCreateIoCompletion ( - OUT PHANDLE CompletionPort, - IN ACCESS_MASK DesiredAccess, - OUT PIO_STATUS_BLOCK IoStatusBlock, - IN ULONG NumberOfConcurrentThreads - ) +NtpCreateIoCompletion( + PVOID ObjectBody, + PVOID Parent, + PWSTR RemainingPath, + POBJECT_ATTRIBUTES ObjectAttributes + ) { - UNIMPLEMENTED; + DPRINT("NtpCreateIoCompletion(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 +NtpDeleteIoCompletion(PVOID ObjectBody) +{ + PKQUEUE Queue = ObjectBody; + + DPRINT("NtpDeleteIoCompletion()\n"); + + KeRundownQueue(Queue); +} + + +VOID +NtInitializeIoCompletionImplementation(VOID) +{ + ExIoCompletionType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE)); + + RtlCreateUnicodeString(&ExIoCompletionType->TypeName, L"IoCompletion"); + + ExIoCompletionType->Tag = IOC_TAG; + ExIoCompletionType->MaxObjects = ULONG_MAX; + ExIoCompletionType->MaxHandles = ULONG_MAX; + 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 = NtpDeleteIoCompletion; + ExIoCompletionType->Parse = NULL; + ExIoCompletionType->Security = NULL; + ExIoCompletionType->QueryName = NULL; + ExIoCompletionType->OkayToClose = NULL; + ExIoCompletionType->Create = NtpCreateIoCompletion; + ExIoCompletionType->DuplicationNotify = NULL; + + ExInitializeNPagedLookasideList(&IoCompletionPacketLookaside, + NULL, + NULL, + 0, + sizeof(IO_COMPLETION_PACKET), + IOC_TAG, + 0); } NTSTATUS STDCALL -NtOpenIoCompletion ( - OUT PHANDLE CompletionPort, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes - ) +NtCreateIoCompletion( + OUT PHANDLE IoCompletionHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN ULONG NumberOfConcurrentThreads + ) { - return(STATUS_SUCCESS); + PKQUEUE Queue; + NTSTATUS Status; + + Status = ObCreateObject(IoCompletionHandle, + DesiredAccess, + ObjectAttributes, + ExIoCompletionType, + (PVOID*)&Queue); + + if (NT_SUCCESS(Status)) + { + (void) KeInitializeQueue(Queue, NumberOfConcurrentThreads); + ObDereferenceObject(Queue); + } + + return Status; + /* + + 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 +STDCALL +NtOpenIoCompletion( + OUT PHANDLE IoCompletionHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes + ) +{ + NTSTATUS Status; + + Status = ObOpenObjectByName(ObjectAttributes, + ExIoCompletionType, + NULL, + UserMode, + DesiredAccess, + NULL, + IoCompletionHandle); //<- ??? + + return Status; } NTSTATUS STDCALL -NtQueryIoCompletion ( - IN HANDLE CompletionPort, - IN ULONG CompletionKey, - OUT PIO_STATUS_BLOCK IoStatusBlock, - OUT PULONG NumberOfBytesTransferred - ) +NtQueryIoCompletion( + IN HANDLE IoCompletionHandle, + IN IO_COMPLETION_INFORMATION_CLASS IoCompletionInformationClass, + OUT PVOID IoCompletionInformation, + IN ULONG IoCompletionInformationLength, + OUT PULONG ResultLength OPTIONAL + ) { - UNIMPLEMENTED; + PKQUEUE Queue; + NTSTATUS Status; + + if (IoCompletionInformationClass != IoCompletionBasicInformation) + { + return STATUS_INVALID_INFO_CLASS; + } + if (IoCompletionInformationLength < sizeof(IO_COMPLETION_BASIC_INFORMATION)) + { + return STATUS_INFO_LENGTH_MISMATCH; + } + + Status = ObReferenceObjectByHandle( IoCompletionHandle, + IO_COMPLETION_QUERY_STATE, + ExIoCompletionType, + UserMode, + (PVOID*)&Queue, + NULL); + if (NT_SUCCESS(Status)) + { + ((PIO_COMPLETION_BASIC_INFORMATION)IoCompletionInformation)->SignalState = + Queue->Header.SignalState; + + ObDereferenceObject(Queue); + + if (ResultLength) *ResultLength = sizeof(IO_COMPLETION_BASIC_INFORMATION); + } + + return Status; } +/* + * Dequeues an I/O completion message from an I/O completion object + */ NTSTATUS STDCALL -NtRemoveIoCompletion ( - IN HANDLE CompletionPort, - OUT PULONG CompletionKey, - OUT PIO_STATUS_BLOCK IoStatusBlock, - OUT PULONG CompletionStatus, - PLARGE_INTEGER WaitTime - ) +NtRemoveIoCompletion( + IN HANDLE IoCompletionHandle, + OUT PULONG CompletionKey, + OUT PULONG CompletionValue, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN PLARGE_INTEGER Timeout OPTIONAL + ) { - UNIMPLEMENTED; + PKQUEUE Queue; + NTSTATUS Status; + + Status = ObReferenceObjectByHandle( IoCompletionHandle, + IO_COMPLETION_MODIFY_STATE, + ExIoCompletionType, + UserMode, + (PVOID*)&Queue, + NULL); + if (NT_SUCCESS(Status)) + { + PIO_COMPLETION_PACKET Packet; + PLIST_ENTRY ListEntry; + + /* + Try 2 remove packet from queue. Wait (optionaly) if + no packet in queue or max num of threads allready running. + */ + ListEntry = KeRemoveQueue(Queue, UserMode, Timeout ); + + ObDereferenceObject(Queue); + + Packet = CONTAINING_RECORD(ListEntry, IO_COMPLETION_PACKET, ListEntry); + + if (CompletionKey) *CompletionKey = Packet->Key; + if (CompletionValue) *CompletionValue = Packet->Overlapped; + if (IoStatusBlock) *IoStatusBlock = Packet->IoStatus; + + ExFreeToNPagedLookasideList(&IoCompletionPacketLookaside, Packet); + } + + return Status; } +/* +ASSOSIERT MED FOB's IoCompletionContext + +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 + */ NTSTATUS STDCALL -NtSetIoCompletion ( - IN HANDLE CompletionPort, - IN ULONG CompletionKey, - OUT PIO_STATUS_BLOCK IoStatusBlock, - IN ULONG NumberOfBytesToTransfer, - OUT PULONG NumberOfBytesTransferred - ) +NtSetIoCompletion( + IN HANDLE IoCompletionPortHandle, + IN ULONG CompletionKey, + IN ULONG CompletionValue, + IN NTSTATUS CompletionStatus, + IN ULONG CompletionInformation + ) { - UNIMPLEMENTED; + NTSTATUS Status; + PKQUEUE Queue; + + Status = ObReferenceObjectByHandle( IoCompletionPortHandle, + IO_COMPLETION_MODIFY_STATE, + ExIoCompletionType, + UserMode, + (PVOID*)&Queue, + NULL); + if (NT_SUCCESS(Status)) + { + PIO_COMPLETION_PACKET Packet; + + Packet = ExAllocateFromNPagedLookasideList(&IoCompletionPacketLookaside); + + Packet->Key = CompletionKey; + Packet->Overlapped = CompletionValue; + Packet->IoStatus.Status = CompletionStatus; + Packet->IoStatus.Information = CompletionInformation; + + KeInsertQueue(Queue, &Packet->ListEntry); + ObDereferenceObject(Queue); + } + + return Status; } diff --git a/reactos/ntoskrnl/ke/queue.c b/reactos/ntoskrnl/ke/queue.c index c44c7f233cc..2d307361ca1 100644 --- a/reactos/ntoskrnl/ke/queue.c +++ b/reactos/ntoskrnl/ke/queue.c @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* $Id: queue.c,v 1.4 2002/11/10 18:17:41 chorns Exp $ +/* $Id: queue.c,v 1.5 2003/03/19 23:10:31 gdalsnes Exp $ * * PROJECT: ReactOS kernel * FILE: ntoskrnl/ke/queue.c @@ -31,6 +31,7 @@ #include #include #include +#include #define NDEBUG #include @@ -46,9 +47,9 @@ KeInitializeQueue(IN PKQUEUE Queue, sizeof(KQUEUE)/sizeof(ULONG), 0); InitializeListHead(&Queue->EntryListHead); - InitializeListHead(&Queue->ThreadListEntry); - Queue->CurrentCount = 0; - Queue->MaximumCount = (Count == 0) ? (ULONG) KeNumberProcessors : Count; + InitializeListHead(&Queue->ThreadListHead); + Queue->RunningThreads = 0; + Queue->MaximumThreads = (Count == 0) ? (ULONG) KeNumberProcessors : Count; } @@ -59,12 +60,47 @@ KeReadStateQueue(IN PKQUEUE Queue) } +LONG STDCALL +KiInsertQueue( + IN PKQUEUE Queue, + IN PLIST_ENTRY Entry, + BOOLEAN Head + ) +{ + ULONG InitialState; + + DPRINT("KiInsertQueue(Queue %x, Entry %x)\n", Queue, Entry); + + KeAcquireDispatcherDatabaseLock(FALSE); + + InitialState = Queue->Header.SignalState; + Queue->Header.SignalState++; + + if (Head) + { + InsertHeadList(&Queue->EntryListHead, Entry); + } + else + { + InsertTailList(&Queue->EntryListHead, Entry); + } + + if (Queue->RunningThreads < Queue->MaximumThreads && InitialState == 0) + { + KeDispatcherObjectWake(&Queue->Header); + } + + KeReleaseDispatcherDatabaseLock(FALSE); + return InitialState; +} + + + LONG STDCALL KeInsertHeadQueue(IN PKQUEUE Queue, IN PLIST_ENTRY Entry) { - UNIMPLEMENTED; - return 0; + return KiInsertQueue(Queue,Entry,TRUE); } @@ -72,8 +108,7 @@ LONG STDCALL KeInsertQueue(IN PKQUEUE Queue, IN PLIST_ENTRY Entry) { - UNIMPLEMENTED; - return 0; + return KiInsertQueue(Queue,Entry,FALSE); } @@ -82,16 +117,88 @@ KeRemoveQueue(IN PKQUEUE Queue, IN KPROCESSOR_MODE WaitMode, IN PLARGE_INTEGER Timeout OPTIONAL) { - UNIMPLEMENTED; - return NULL; + PLIST_ENTRY ListEntry; + NTSTATUS Status; + PKTHREAD Thread = KeGetCurrentThread(); + + KeAcquireDispatcherDatabaseLock(FALSE); + + //assiciate new thread with queue? + if (Thread->Queue != Queue) + { + //remove association from other queue + if (!IsListEmpty(&Thread->QueueListEntry)) + { + RemoveEntryList(&Thread->QueueListEntry); + } + + //associate with this queue + InsertHeadList(&Queue->ThreadListHead, &Thread->QueueListEntry); + Queue->RunningThreads++; + Thread->Queue = Queue; + } + + if (Queue->RunningThreads <= Queue->MaximumThreads && !IsListEmpty(&Queue->EntryListHead)) + { + ListEntry = RemoveHeadList(&Queue->EntryListHead); + Queue->Header.SignalState--; + KeReleaseDispatcherDatabaseLock(FALSE); + return ListEntry; + } + + //need to wait for it... + KeReleaseDispatcherDatabaseLock(FALSE); + + Status = KeWaitForSingleObject(Queue, + WrQueue, + WaitMode, + TRUE,//Alertable, + Timeout); + + if (Status == STATUS_TIMEOUT || Status == STATUS_USER_APC) + { + return (PVOID)Status; + } + else + { + KeAcquireDispatcherDatabaseLock(FALSE); + ListEntry = RemoveHeadList(&Queue->EntryListHead); + KeReleaseDispatcherDatabaseLock(FALSE); + return ListEntry; + } + } PLIST_ENTRY STDCALL KeRundownQueue(IN PKQUEUE Queue) { - UNIMPLEMENTED; - return NULL; + PLIST_ENTRY EnumEntry; + PKTHREAD Thread; + + DPRINT("KeRundownQueue(Queue %x)\n", Queue); + + //FIXME: should we wake thread waiting on a queue? + + KeAcquireDispatcherDatabaseLock(FALSE); + + // Clear Queue and QueueListEntry members of all threads associated with this queue + while (!IsListEmpty(&Queue->ThreadListHead)) + { + EnumEntry = RemoveHeadList(&Queue->ThreadListHead); + InitializeListHead(EnumEntry); + Thread = CONTAINING_RECORD(EnumEntry, KTHREAD, QueueListEntry); + Thread->Queue = NULL; + } + + if (!IsListEmpty(&Queue->EntryListHead)) + EnumEntry = Queue->EntryListHead.Flink; + else + EnumEntry = NULL; + + KeReleaseDispatcherDatabaseLock(FALSE); + + return EnumEntry; } /* EOF */