initial work on I/O completion

svn path=/trunk/; revision=4352
This commit is contained in:
Gunnar Dalsnes 2003-03-19 23:17:52 +00:00
parent fc1366d624
commit 957f814a24
12 changed files with 621 additions and 190 deletions

View file

@ -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 #ifndef __INCLUDE_DDK_EXTYPES_H
#define __INCLUDE_DDK_EXTYPES_H #define __INCLUDE_DDK_EXTYPES_H
@ -7,10 +7,12 @@
extern POBJECT_TYPE EXPORTED ExDesktopObjectType; extern POBJECT_TYPE EXPORTED ExDesktopObjectType;
extern POBJECT_TYPE EXPORTED ExEventObjectType; extern POBJECT_TYPE EXPORTED ExEventObjectType;
extern POBJECT_TYPE EXPORTED ExWindowStationObjectType; extern POBJECT_TYPE EXPORTED ExWindowStationObjectType;
extern POBJECT_TYPE EXPORTED ExIoCompletionType;
#else #else
extern POBJECT_TYPE IMPORTED ExDesktopObjectType; extern POBJECT_TYPE IMPORTED ExDesktopObjectType;
extern POBJECT_TYPE IMPORTED ExEventObjectType; extern POBJECT_TYPE IMPORTED ExEventObjectType;
extern POBJECT_TYPE IMPORTED ExWindowStationObjectType; extern POBJECT_TYPE IMPORTED ExWindowStationObjectType;
extern POBJECT_TYPE IMPORTED ExIoCompletionType;
#endif #endif
typedef ULONG INTERLOCKED_RESULT; typedef ULONG INTERLOCKED_RESULT;

View file

@ -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; ULONG Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; } 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 typedef struct _IO_PIPE_CREATE_BUFFER
{ {

View file

@ -135,6 +135,9 @@ VOID STDCALL
KeInitializeQueue(IN PKQUEUE Queue, KeInitializeQueue(IN PKQUEUE Queue,
IN ULONG Count); IN ULONG Count);
PLIST_ENTRY STDCALL
KeRundownQueue(IN PKQUEUE Queue);
VOID STDCALL KeInitializeSemaphore (PKSEMAPHORE Semaphore, VOID STDCALL KeInitializeSemaphore (PKSEMAPHORE Semaphore,
LONG Count, LONG Count,
LONG Limit); LONG Limit);

View file

@ -122,9 +122,9 @@ typedef struct _KQUEUE
{ {
DISPATCHER_HEADER Header; DISPATCHER_HEADER Header;
LIST_ENTRY EntryListHead; LIST_ENTRY EntryListHead;
ULONG CurrentCount; ULONG RunningThreads;
ULONG MaximumCount; ULONG MaximumThreads;
LIST_ENTRY ThreadListEntry; LIST_ENTRY ThreadListHead;
} KQUEUE, *PKQUEUE; } KQUEUE, *PKQUEUE;
struct _KDPC; struct _KDPC;

View file

@ -27,6 +27,9 @@
#define TIMER_ALL_ACCESS (0x1f0003L) #define TIMER_ALL_ACCESS (0x1f0003L)
#define TIMER_QUERY_STATE (1) #define TIMER_QUERY_STATE (1)
#define TIMER_MODIFY_STATE (2) #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 */ #endif /* !__USE_W32API */

View file

@ -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 * COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel * PROJECT: ReactOS kernel
@ -497,21 +497,20 @@ ZwCreateFile(
NTSTATUS NTSTATUS
STDCALL STDCALL
NtCreateIoCompletion( NtCreateIoCompletion(
OUT PHANDLE CompletionPort, OUT PHANDLE IoCompletionHandle,
IN ACCESS_MASK DesiredAccess, IN ACCESS_MASK DesiredAccess,
OUT PIO_STATUS_BLOCK IoStatusBlock, IN POBJECT_ATTRIBUTES ObjectAttributes,
IN ULONG NumberOfConcurrentThreads IN ULONG NumberOfConcurrentThreads
); );
NTSTATUS NTSTATUS
STDCALL STDCALL
ZwCreateIoCompletion( ZwCreateIoCompletion(
OUT PHANDLE CompletionPort, OUT PHANDLE IoCompletionHandle,
IN ACCESS_MASK DesiredAccess, IN ACCESS_MASK DesiredAccess,
OUT PIO_STATUS_BLOCK IoStatusBlock, IN POBJECT_ATTRIBUTES ObjectAttributes,
IN ULONG NumberOfConcurrentThreads IN ULONG NumberOfConcurrentThreads
); );
/* /*
* FUNCTION: Creates a registry key * FUNCTION: Creates a registry key
@ -2357,20 +2356,22 @@ ZwQueryInformationToken(
NTSTATUS NTSTATUS
STDCALL STDCALL
NtQueryIoCompletion( NtQueryIoCompletion(
IN HANDLE CompletionPort, IN HANDLE IoCompletionHandle,
IN ULONG CompletionKey, IN IO_COMPLETION_INFORMATION_CLASS IoCompletionInformationClass,
OUT PIO_STATUS_BLOCK IoStatusBlock, OUT PVOID IoCompletionInformation,
OUT PULONG NumberOfBytesTransferred IN ULONG IoCompletionInformationLength,
); OUT PULONG ResultLength OPTIONAL
);
NTSTATUS NTSTATUS
STDCALL STDCALL
ZwQueryIoCompletion( ZwQueryIoCompletion(
IN HANDLE CompletionPort, IN HANDLE IoCompletionHandle,
IN ULONG CompletionKey, IN IO_COMPLETION_INFORMATION_CLASS IoCompletionInformationClass,
OUT PIO_STATUS_BLOCK IoStatusBlock, OUT PVOID IoCompletionInformation,
OUT PULONG NumberOfBytesTransferred IN ULONG IoCompletionInformationLength,
); OUT PULONG ResultLength OPTIONAL
);
/* /*
* FUNCTION: Queries the information of a registry key object. * FUNCTION: Queries the information of a registry key object.
@ -2990,22 +2991,23 @@ ZwReleaseSemaphore(
NTSTATUS NTSTATUS
STDCALL STDCALL
NtRemoveIoCompletion( NtRemoveIoCompletion(
IN HANDLE CompletionPort, IN HANDLE IoCompletionHandle,
OUT PULONG CompletionKey, OUT PULONG CompletionKey,
OUT PIO_STATUS_BLOCK IoStatusBlock, OUT PULONG CompletionValue,
OUT PULONG CompletionStatus, OUT PIO_STATUS_BLOCK IoStatusBlock,
IN PLARGE_INTEGER WaitTime IN PLARGE_INTEGER Timeout OPTIONAL
); );
NTSTATUS NTSTATUS
STDCALL STDCALL
ZwRemoveIoCompletion( ZwRemoveIoCompletion(
IN HANDLE CompletionPort, IN HANDLE IoCompletionHandle,
OUT PULONG CompletionKey, OUT PULONG CompletionKey,
OUT PIO_STATUS_BLOCK IoStatusBlock, OUT PULONG CompletionValue,
OUT PULONG CompletionStatus, OUT PIO_STATUS_BLOCK IoStatusBlock,
IN PLARGE_INTEGER WaitTime IN PLARGE_INTEGER Timeout OPTIONAL
); );
/* /*
* FUNCTION: Replaces one registry key with another * FUNCTION: Replaces one registry key with another
* ARGUMENTS: * ARGUMENTS:
@ -3392,21 +3394,22 @@ ZwSetInformationToken(
NTSTATUS NTSTATUS
STDCALL STDCALL
NtSetIoCompletion( NtSetIoCompletion(
IN HANDLE CompletionPort, IN HANDLE IoCompletionPortHandle,
IN ULONG CompletionKey, IN ULONG CompletionKey,
OUT PIO_STATUS_BLOCK IoStatusBlock, IN ULONG CompletionValue,
IN ULONG NumberOfBytesToTransfer, IN NTSTATUS CompletionStatus,
OUT PULONG NumberOfBytesTransferred IN ULONG CompletionInformation
); );
NTSTATUS NTSTATUS
STDCALL STDCALL
ZwSetIoCompletion( ZwSetIoCompletion(
IN HANDLE CompletionPort, IN HANDLE IoCompletionPortHandle,
IN ULONG CompletionKey, IN ULONG CompletionKey,
OUT PIO_STATUS_BLOCK IoStatusBlock, IN ULONG CompletionValue,
IN ULONG NumberOfBytesToTransfer, IN NTSTATUS CompletionStatus,
OUT PULONG NumberOfBytesTransferred IN ULONG CompletionInformation
); );
/* /*
* FUNCTION: Set properties for profiling * FUNCTION: Set properties for profiling

View file

@ -881,6 +881,11 @@ typedef struct _FILE_COMPRESSION_INFORMATION {
UCHAR Reserved[3]; UCHAR Reserved[3];
} FILE_COMPRESSION_INFORMATION, *PFILE_COMPRESSION_INFORMATION; } 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 { typedef struct _FILE_ALL_INFORMATION {
FILE_BASIC_INFORMATION BasicInformation; FILE_BASIC_INFORMATION BasicInformation;
FILE_STANDARD_INFORMATION StandardInformation; FILE_STANDARD_INFORMATION StandardInformation;
@ -1069,6 +1074,14 @@ typedef enum SHUTDOWN_ACTION_TAG {
ShutdownPowerOff ShutdownPowerOff
} SHUTDOWN_ACTION; } 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 */ #else /* __USE_W32API */
#define DebugDbgLoadSymbols ((DEBUG_CONTROL_CODE)0xffffffff) #define DebugDbgLoadSymbols ((DEBUG_CONTROL_CODE)0xffffffff)

View file

@ -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 * COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS system libraries * PROJECT: ReactOS system libraries
@ -14,23 +14,6 @@
#include <kernel32/error.h> #include <kernel32/error.h>
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 HANDLE
STDCALL STDCALL
CreateIoCompletionPort( CreateIoCompletionPort(
@ -40,99 +23,146 @@ CreateIoCompletionPort(
DWORD NumberOfConcurrentThreads DWORD NumberOfConcurrentThreads
) )
{ {
HANDLE CompletionPort = NULL; HANDLE CompletionPort = NULL;
NTSTATUS errCode; NTSTATUS errCode;
FILE_COMPLETION_INFORMATION CompletionInformation; FILE_COMPLETION_INFORMATION CompletionInformation;
IO_STATUS_BLOCK IoStatusBlock; IO_STATUS_BLOCK IoStatusBlock;
if ( ExistingCompletionPort == NULL && FileHandle == INVALID_HANDLE_VALUE ) { if ( ExistingCompletionPort == NULL && FileHandle == INVALID_HANDLE_VALUE )
SetLastErrorByStatus (STATUS_INVALID_PARAMETER); {
return FALSE; SetLastErrorByStatus (STATUS_INVALID_PARAMETER);
} return FALSE;
}
if ( ExistingCompletionPort != NULL ) { if ( ExistingCompletionPort != NULL )
CompletionPort = ExistingCompletionPort; {
} CompletionPort = ExistingCompletionPort;
else { }
errCode = NtCreateIoCompletion(&CompletionPort,GENERIC_ALL,&IoStatusBlock,NumberOfConcurrentThreads); else
if (!NT_SUCCESS(errCode) ) { {
SetLastErrorByStatus (errCode);
return FALSE;
}
} errCode = NtCreateIoCompletion(&CompletionPort,
if ( FileHandle != INVALID_HANDLE_VALUE ) { IO_COMPLETION_ALL_ACCESS,
NULL,//ObjectAttributes
NumberOfConcurrentThreads);
CompletionInformation.CompletionPort = CompletionPort; if (!NT_SUCCESS(errCode) )
CompletionInformation.CompletionKey = CompletionKey; {
SetLastErrorByStatus (errCode);
return FALSE;
}
errCode = NtSetInformationFile(FileHandle, &IoStatusBlock,&CompletionInformation,sizeof(FILE_COMPLETION_INFORMATION),FileCompletionInformation); }
if ( !NT_SUCCESS(errCode) ) {
if ( ExistingCompletionPort == NULL ) if ( FileHandle != INVALID_HANDLE_VALUE )
NtClose(CompletionPort); {
SetLastErrorByStatus (errCode); CompletionInformation.IoCompletionHandle = CompletionPort;
return FALSE; 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 WINBOOL
STDCALL STDCALL
GetQueuedCompletionStatus( GetQueuedCompletionStatus(
HANDLE CompletionPort, HANDLE CompletionHandle,
LPDWORD lpNumberOfBytesTransferred, LPDWORD lpNumberOfBytesTransferred,
LPDWORD lpCompletionKey, LPDWORD lpCompletionKey,
LPOVERLAPPED *lpOverlapped, LPOVERLAPPED *lpOverlapped,
DWORD dwMilliseconds DWORD dwMilliseconds
) )
{ {
NTSTATUS errCode; NTSTATUS errCode;
ULONG CompletionStatus; IO_STATUS_BLOCK IoStatus;
LARGE_INTEGER TimeToWait; LARGE_INTEGER Interval;
errCode = NtRemoveIoCompletion(CompletionPort,(PULONG)lpCompletionKey,(PIO_STATUS_BLOCK)lpOverlapped,&CompletionStatus,&TimeToWait); if (!lpNumberOfBytesTransferred||!lpCompletionKey||!lpOverlapped)
if (!NT_SUCCESS(errCode) ) { {
SetLastErrorByStatus (errCode); return ERROR_INVALID_PARAMETER;
return FALSE; }
}
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 WINBOOL
STDCALL STDCALL
PostQueuedCompletionStatus( PostQueuedCompletionStatus(
HANDLE CompletionPort, HANDLE CompletionHandle,
DWORD dwNumberOfBytesTransferred, DWORD dwNumberOfBytesTransferred,
DWORD dwCompletionKey, DWORD dwCompletionKey,
LPOVERLAPPED lpOverlapped LPOVERLAPPED lpOverlapped
) )
{ {
NTSTATUS errCode; NTSTATUS errCode;
errCode = NtSetIoCompletion(CompletionPort, dwCompletionKey, (PIO_STATUS_BLOCK)lpOverlapped , 0, (PULONG)&dwNumberOfBytesTransferred );
if ( !NT_SUCCESS(errCode) ) { errCode = NtSetIoCompletion(CompletionHandle,
SetLastErrorByStatus (errCode); dwCompletionKey,
return FALSE; dwNumberOfBytesTransferred,//CompletionValue
} 0, //IoStatusBlock->Status
return TRUE; (ULONG)lpOverlapped ); //IoStatusBlock->Information
}
if ( !NT_SUCCESS(errCode) )
// this should be a place holder ?????????????????? {
VOID SetLastErrorByStatus (errCode);
STDCALL return FALSE;
FileIOCompletionRoutine( }
DWORD dwErrorCode, return TRUE;
DWORD dwNumberOfBytesTransfered,
LPOVERLAPPED lpOverlapped
)
{
return;
} }

View file

@ -58,6 +58,8 @@ VOID
KiDeliverNormalApc(VOID); KiDeliverNormalApc(VOID);
BOOLEAN STDCALL KeRemoveQueueApc (PKAPC Apc); BOOLEAN STDCALL KeRemoveQueueApc (PKAPC Apc);
PLIST_ENTRY STDCALL KeRundownQueue(IN PKQUEUE Queue);
/* INITIALIZATION FUNCTIONS *************************************************/ /* INITIALIZATION FUNCTIONS *************************************************/

View file

@ -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 * COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel * PROJECT: ReactOS kernel
@ -236,7 +236,39 @@ NtSetInformationFile(HANDLE FileHandle,
} }
DPRINT("FileObject %x\n", FileObject); 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; DeviceObject = FileObject->DeviceObject;
Irp = IoAllocateIrp(DeviceObject->StackSize, Irp = IoAllocateIrp(DeviceObject->StackSize,

View file

@ -11,73 +11,303 @@
/* INCLUDES *****************************************************************/ /* INCLUDES *****************************************************************/
#include <limits.h>
#include <ddk/ntddk.h> #include <ddk/ntddk.h>
#include <ntos/synch.h>
#define NDEBUG
#include <internal/debug.h> #include <internal/debug.h>
#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 *****************************************************************/ /* FUNCTIONS *****************************************************************/
NTSTATUS NTSTATUS
STDCALL STDCALL
NtCreateIoCompletion ( NtpCreateIoCompletion(
OUT PHANDLE CompletionPort, PVOID ObjectBody,
IN ACCESS_MASK DesiredAccess, PVOID Parent,
OUT PIO_STATUS_BLOCK IoStatusBlock, PWSTR RemainingPath,
IN ULONG NumberOfConcurrentThreads 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 NTSTATUS
STDCALL STDCALL
NtOpenIoCompletion ( NtCreateIoCompletion(
OUT PHANDLE CompletionPort, OUT PHANDLE IoCompletionHandle,
IN ACCESS_MASK DesiredAccess, IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes 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 NTSTATUS
STDCALL STDCALL
NtQueryIoCompletion ( NtQueryIoCompletion(
IN HANDLE CompletionPort, IN HANDLE IoCompletionHandle,
IN ULONG CompletionKey, IN IO_COMPLETION_INFORMATION_CLASS IoCompletionInformationClass,
OUT PIO_STATUS_BLOCK IoStatusBlock, OUT PVOID IoCompletionInformation,
OUT PULONG NumberOfBytesTransferred 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 NTSTATUS
STDCALL STDCALL
NtRemoveIoCompletion ( NtRemoveIoCompletion(
IN HANDLE CompletionPort, IN HANDLE IoCompletionHandle,
OUT PULONG CompletionKey, OUT PULONG CompletionKey,
OUT PIO_STATUS_BLOCK IoStatusBlock, OUT PULONG CompletionValue,
OUT PULONG CompletionStatus, OUT PIO_STATUS_BLOCK IoStatusBlock,
PLARGE_INTEGER WaitTime 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 NTSTATUS
STDCALL STDCALL
NtSetIoCompletion ( NtSetIoCompletion(
IN HANDLE CompletionPort, IN HANDLE IoCompletionPortHandle,
IN ULONG CompletionKey, IN ULONG CompletionKey,
OUT PIO_STATUS_BLOCK IoStatusBlock, IN ULONG CompletionValue,
IN ULONG NumberOfBytesToTransfer, IN NTSTATUS CompletionStatus,
OUT PULONG NumberOfBytesTransferred 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;
} }

View file

@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * 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 * PROJECT: ReactOS kernel
* FILE: ntoskrnl/ke/queue.c * FILE: ntoskrnl/ke/queue.c
@ -31,6 +31,7 @@
#include <ddk/ntddk.h> #include <ddk/ntddk.h>
#include <internal/ke.h> #include <internal/ke.h>
#include <internal/id.h> #include <internal/id.h>
#include <internal/ps.h>
#define NDEBUG #define NDEBUG
#include <internal/debug.h> #include <internal/debug.h>
@ -46,9 +47,9 @@ KeInitializeQueue(IN PKQUEUE Queue,
sizeof(KQUEUE)/sizeof(ULONG), sizeof(KQUEUE)/sizeof(ULONG),
0); 0);
InitializeListHead(&Queue->EntryListHead); InitializeListHead(&Queue->EntryListHead);
InitializeListHead(&Queue->ThreadListEntry); InitializeListHead(&Queue->ThreadListHead);
Queue->CurrentCount = 0; Queue->RunningThreads = 0;
Queue->MaximumCount = (Count == 0) ? (ULONG) KeNumberProcessors : Count; 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 LONG STDCALL
KeInsertHeadQueue(IN PKQUEUE Queue, KeInsertHeadQueue(IN PKQUEUE Queue,
IN PLIST_ENTRY Entry) IN PLIST_ENTRY Entry)
{ {
UNIMPLEMENTED; return KiInsertQueue(Queue,Entry,TRUE);
return 0;
} }
@ -72,8 +108,7 @@ LONG STDCALL
KeInsertQueue(IN PKQUEUE Queue, KeInsertQueue(IN PKQUEUE Queue,
IN PLIST_ENTRY Entry) IN PLIST_ENTRY Entry)
{ {
UNIMPLEMENTED; return KiInsertQueue(Queue,Entry,FALSE);
return 0;
} }
@ -82,16 +117,88 @@ KeRemoveQueue(IN PKQUEUE Queue,
IN KPROCESSOR_MODE WaitMode, IN KPROCESSOR_MODE WaitMode,
IN PLARGE_INTEGER Timeout OPTIONAL) IN PLARGE_INTEGER Timeout OPTIONAL)
{ {
UNIMPLEMENTED; PLIST_ENTRY ListEntry;
return NULL; 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 PLIST_ENTRY STDCALL
KeRundownQueue(IN PKQUEUE Queue) KeRundownQueue(IN PKQUEUE Queue)
{ {
UNIMPLEMENTED; PLIST_ENTRY EnumEntry;
return NULL; 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 */ /* EOF */