From 9f34d2cfc720702d796adc382b3e67cd3401b981 Mon Sep 17 00:00:00 2001 From: Timo Kreuzer Date: Fri, 20 Apr 2012 19:31:07 +0000 Subject: [PATCH] [NTOSKRNL] Implement keyed events (untested) svn path=/trunk/; revision=56373 --- reactos/ntoskrnl/ex/init.c | 1 + reactos/ntoskrnl/ex/keyedevt.c | 432 +++++++++++++++++++++++-- reactos/ntoskrnl/include/internal/ex.h | 4 +- 3 files changed, 411 insertions(+), 26 deletions(-) diff --git a/reactos/ntoskrnl/ex/init.c b/reactos/ntoskrnl/ex/init.c index c6048ef36c3..1ba18e2de67 100644 --- a/reactos/ntoskrnl/ex/init.c +++ b/reactos/ntoskrnl/ex/init.c @@ -664,6 +664,7 @@ ExpInitSystemPhase1(VOID) /* Initialize events and event pairs */ ExpInitializeEventImplementation(); ExpInitializeEventPairImplementation(); + ExpInitializeKeyedEventImplementation(); /* Initialize callbacks */ ExpInitializeCallbacks(); diff --git a/reactos/ntoskrnl/ex/keyedevt.c b/reactos/ntoskrnl/ex/keyedevt.c index 1d409ba9887..832b71a9bcb 100644 --- a/reactos/ntoskrnl/ex/keyedevt.c +++ b/reactos/ntoskrnl/ex/keyedevt.c @@ -12,51 +12,435 @@ #define NDEBUG #include +/* INTERNAL TYPES *************************************************************/ + +#define NUM_KEY_HASH_BUCKETS 23 +typedef struct _EX_KEYED_EVENT +{ + struct + { + EX_PUSH_LOCK Lock; + LIST_ENTRY WaitListHead; + LIST_ENTRY ReleaseListHead; + } HashTable[NUM_KEY_HASH_BUCKETS]; +} EX_KEYED_EVENT, *PEX_KEYED_EVENT; + +VOID +NTAPI +ExpInitializeKeyedEvent( + _Out_ PEX_KEYED_EVENT KeyedEvent); + +#define KeGetCurrentProcess() ((PKPROCESS)PsGetCurrentProcess) + /* GLOBALS *******************************************************************/ +PEX_KEYED_EVENT ExpCritSecOutOfMemoryEvent; +POBJECT_TYPE ExKeyedEventObjectType; + +static +GENERIC_MAPPING ExpKeyedEventMapping = +{ + STANDARD_RIGHTS_READ | EVENT_QUERY_STATE, + STANDARD_RIGHTS_WRITE | EVENT_MODIFY_STATE, + STANDARD_RIGHTS_EXECUTE | EVENT_QUERY_STATE, + EVENT_ALL_ACCESS +}; + + /* FUNCTIONS *****************************************************************/ -NTSTATUS +VOID NTAPI -NtCreateKeyedEvent(OUT PHANDLE KeyedEventHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes, - IN ULONG Flags) +ExpInitializeKeyedEventImplementation(VOID) { - UNIMPLEMENTED; - return STATUS_NOT_IMPLEMENTED; + OBJECT_TYPE_INITIALIZER ObjectTypeInitializer = {0}; + UNICODE_STRING TypeName = RTL_CONSTANT_STRING(L"KeyedEvent"); + NTSTATUS Status; + + /* Set up the object type initializer */ + ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer); + ObjectTypeInitializer.GenericMapping = ExpKeyedEventMapping; + ObjectTypeInitializer.PoolType = NonPagedPool; + //ObjectTypeInitializer.DeleteProcedure = ???; + //ObjectTypeInitializer.OkayToCloseProcedure = ???; + + /* Create the keyed event object type */ + Status = ObCreateObjectType(&TypeName, + &ObjectTypeInitializer, + NULL, + &ExKeyedEventObjectType); + + /* Check for success */ + if (!NT_SUCCESS(Status)) + { + // FIXME + KeBugCheck(0); + } + + /* Create the global keyed event for critical sections on low memory */ + Status = ObCreateObject(KernelMode, + ExKeyedEventObjectType, + NULL, + UserMode, + NULL, + sizeof(EX_KEYED_EVENT), + 0, + 0, + (PVOID*)&ExpCritSecOutOfMemoryEvent); + + /* Check for success */ + if (!NT_SUCCESS(Status)) + { + // FIXME + KeBugCheck(0); + } + + /* Initalize the keyed event */ + ExpInitializeKeyedEvent(ExpCritSecOutOfMemoryEvent); +} + +VOID +NTAPI +ExpInitializeKeyedEvent( + _Out_ PEX_KEYED_EVENT KeyedEvent) +{ + ULONG i; + + /* Loop all hash buckets */ + for (i = 0; i < NUM_KEY_HASH_BUCKETS; i++) + { + /* Initialize the mutex and the wait lists */ + ExInitializePushLock(&KeyedEvent->HashTable[i].Lock); + InitializeListHead(&KeyedEvent->HashTable[i].WaitListHead); + InitializeListHead(&KeyedEvent->HashTable[i].ReleaseListHead); + } } NTSTATUS NTAPI -NtOpenKeyedEvent(OUT PHANDLE EventHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes) +ExpReleaseOrWaitForKeyedEvent( + _Inout_ PEX_KEYED_EVENT KeyedEvent, + _In_ PVOID KeyedWaitValue, + _In_ BOOLEAN Alertable, + _In_ PLARGE_INTEGER Timeout, + _In_ BOOLEAN Release) { - UNIMPLEMENTED; - return STATUS_NOT_IMPLEMENTED; + PETHREAD Thread, CurrentThread; + PKPROCESS CurrentProcess; + PLIST_ENTRY ListEntry, WaitListHead1, WaitListHead2; + NTSTATUS Status; + ULONG_PTR HashIndex; + + /* Get the current process */ + CurrentProcess = KeGetCurrentProcess(); + + /* Calculate the hash index */ + HashIndex = (ULONG_PTR)KeyedWaitValue >> 5; + HashIndex ^= (ULONG_PTR)CurrentProcess >> 6; + HashIndex %= NUM_KEY_HASH_BUCKETS; + + /* Lock the lists */ + ExAcquirePushLockExclusive(&KeyedEvent->HashTable[HashIndex].Lock); + + /* Get the lists for search and wait, depending on whether + we want to wait for the event or signal it */ + if (Release) + { + WaitListHead1 = &KeyedEvent->HashTable[HashIndex].WaitListHead; + WaitListHead2 = &KeyedEvent->HashTable[HashIndex].ReleaseListHead; + } + else + { + WaitListHead1 = &KeyedEvent->HashTable[HashIndex].ReleaseListHead; + WaitListHead2 = &KeyedEvent->HashTable[HashIndex].WaitListHead; + } + + /* loop the first wait list */ + ListEntry = WaitListHead1->Flink; + while (ListEntry != WaitListHead1) + { + Thread = CONTAINING_RECORD(ListEntry, ETHREAD, KeyedWaitChain); + + /* Check if this thread is a correct waiter */ + if ((Thread->Tcb.Process == CurrentProcess) && + (Thread->KeyedWaitValue == KeyedWaitValue)) + { + /* Remove the thread from the list */ + RemoveEntryList(&Thread->KeyedWaitChain); + + /* Wake the thread */ + KeReleaseSemaphore(&Thread->KeyedWaitSemaphore, 0, 1, FALSE); + + /* Unlock the lists */ + ExReleasePushLockExclusive(&KeyedEvent->HashTable[HashIndex].Lock); + + return STATUS_SUCCESS; + } + } + + /* Get the current thread */ + CurrentThread = PsGetCurrentThread(); + + /* Set the wait key */ + CurrentThread->KeyedWaitValue = KeyedWaitValue; + + /* Initialize the wait semaphore */ + KeInitializeSemaphore(&CurrentThread->KeyedWaitSemaphore, 0, 1); + + /* Insert the current thread into the secondary wait list */ + InsertTailList(WaitListHead2, &CurrentThread->KeyedWaitChain); + + /* Unlock the lists */ + ExReleasePushLockExclusive(&KeyedEvent->HashTable[HashIndex].Lock); + + /* Wait for the keyed wait semaphore */ + Status = KeWaitForSingleObject(&CurrentThread->KeyedWaitSemaphore, + WrKeyedEvent, + KernelMode, + Alertable, + Timeout); + + return STATUS_SUCCESS; } NTSTATUS NTAPI -NtReleaseKeyedEvent(IN HANDLE EventHandle, - IN PVOID Key, - IN BOOLEAN Alertable, - IN PLARGE_INTEGER Timeout OPTIONAL) +ExpWaitForKeyedEvent( + _Inout_ PEX_KEYED_EVENT KeyedEvent, + _In_ PVOID KeyedWaitValue, + _In_ BOOLEAN Alertable, + _In_ PLARGE_INTEGER Timeout) { - UNIMPLEMENTED; - return STATUS_NOT_IMPLEMENTED; + /* Call the generic internal function */ + return ExpReleaseOrWaitForKeyedEvent(KeyedEvent, + KeyedWaitValue, + Alertable, + Timeout, + FALSE); } NTSTATUS NTAPI -NtWaitForKeyedEvent(IN HANDLE EventHandle, - IN PVOID Key, - IN BOOLEAN Alertable, - IN PLARGE_INTEGER Timeout OPTIONAL) +ExpReleaseKeyedEvent( + _Inout_ PEX_KEYED_EVENT KeyedEvent, + _In_ PVOID KeyedWaitValue, + _In_ BOOLEAN Alertable, + _In_ PLARGE_INTEGER Timeout) { - UNIMPLEMENTED; - return STATUS_NOT_IMPLEMENTED; + /* Call the generic internal function */ + return ExpReleaseOrWaitForKeyedEvent(KeyedEvent, + KeyedWaitValue, + Alertable, + Timeout, + TRUE); +} + +NTSTATUS +NTAPI +NtCreateKeyedEvent( + _Out_ PHANDLE OutHandle, + _In_ ACCESS_MASK AccessMask, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ ULONG Flags) +{ + KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); + PEX_KEYED_EVENT KeyedEvent; + HANDLE KeyedEventHandle; + NTSTATUS Status; + + /* Check flags */ + if (Flags != 0) + { + /* We don't support any flags yet */ + return STATUS_INVALID_PARAMETER; + } + + /* Create the object */ + Status = ObCreateObject(PreviousMode, + ExKeyedEventObjectType, + ObjectAttributes, + PreviousMode, + NULL, + sizeof(EX_KEYED_EVENT), + 0, + 0, + (PVOID*)&KeyedEvent); + + /* Check for success */ + if (!NT_SUCCESS(Status)) return Status; + + /* Initalize the keyed event */ + ExpInitializeKeyedEvent(KeyedEvent); + + /* Insert it */ + Status = ObInsertObject(KeyedEvent, + NULL, + AccessMask, + 0, + NULL, + &KeyedEventHandle); + + /* Check for success (ObInsertObject dereferences!) */ + if (!NT_SUCCESS(Status)) return Status; + + if (PreviousMode != KernelMode) + { + /* Enter SEH for return */ + _SEH2_TRY + { + /* Return the handle to the caller */ + ProbeForWrite(OutHandle, sizeof(HANDLE), sizeof(HANDLE)); + *OutHandle = KeyedEventHandle; + } + _SEH2_EXCEPT(ExSystemExceptionFilter()) + { + /* Get the exception code */ + Status = _SEH2_GetExceptionCode(); + + /* Cleanup */ + ObCloseHandle(KeyedEventHandle, PreviousMode); + } + _SEH2_END; + } + else + { + *OutHandle = KeyedEventHandle; + } + + /* Return Status */ + return Status; +} + +NTSTATUS +NTAPI +NtOpenKeyedEvent( + _Out_ PHANDLE OutHandle, + _In_ ACCESS_MASK AccessMask, + _In_ POBJECT_ATTRIBUTES ObjectAttributes) +{ + KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); + HANDLE KeyedEventHandle; + NTSTATUS Status; + + /* Open the object */ + Status = ObOpenObjectByName(ObjectAttributes, + ExKeyedEventObjectType, + PreviousMode, + NULL, + AccessMask, + NULL, + &KeyedEventHandle); + + /* Check for success */ + if (!NT_SUCCESS(Status)) return Status; + + /* Enter SEH for return */ + if (PreviousMode != KernelMode) + { + _SEH2_TRY + { + /* Return the handle to the caller */ + ProbeForWrite(OutHandle, sizeof(HANDLE), sizeof(HANDLE)); + *OutHandle = KeyedEventHandle; + } + _SEH2_EXCEPT(ExSystemExceptionFilter()) + { + /* Get the exception code */ + Status = _SEH2_GetExceptionCode(); + } + _SEH2_END; + } + else + { + *OutHandle = KeyedEventHandle; + } + + /* Return status */ + return Status; +} + +NTSTATUS +NTAPI +NtWaitForKeyedEvent( + _In_ HANDLE Handle, + _In_ PVOID Key, + _In_ BOOLEAN Alertable, + _In_ PLARGE_INTEGER Timeout) +{ + KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); + PEX_KEYED_EVENT KeyedEvent; + NTSTATUS Status; + + /* Check if the caller provided a handle */ + if (Handle != NULL) + { + /* Get the keyed event object */ + Status = ObReferenceObjectByHandle(Handle, + EVENT_MODIFY_STATE, + ExKeyedEventObjectType, + PreviousMode, + (PVOID*)&KeyedEvent, + NULL); + + /* Check for success */ + if (!NT_SUCCESS(Status)) return Status; + } + else + { + /* Use the default keyed event for low memory critical sections */ + KeyedEvent = ExpCritSecOutOfMemoryEvent; + } + + /* Do the wait */ + Status = ExpWaitForKeyedEvent(KeyedEvent, Key, Alertable, Timeout); + + /* Dereference the keyed event */ + ObDereferenceObject(KeyedEvent); + + /* Return the status */ + return Status; +} + +NTSTATUS +NTAPI +NtReleaseKeyedEvent( + _In_ HANDLE Handle, + _In_ PVOID Key, + _In_ BOOLEAN Alertable, + _In_ PLARGE_INTEGER Timeout) +{ + KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); + PEX_KEYED_EVENT KeyedEvent; + NTSTATUS Status; + + /* Check if the caller provided a handle */ + if (Handle != NULL) + { + /* Get the keyed event object */ + Status = ObReferenceObjectByHandle(Handle, + EVENT_MODIFY_STATE, + ExKeyedEventObjectType, + PreviousMode, + (PVOID*)&KeyedEvent, + NULL); + + /* Check for success */ + if (!NT_SUCCESS(Status)) return Status; + } + else + { + /* Use the default keyed event for low memory critical sections */ + KeyedEvent = ExpCritSecOutOfMemoryEvent; + } + + /* Do the wait */ + Status = ExpReleaseKeyedEvent(KeyedEvent, Key, Alertable, Timeout); + + /* Dereference the keyed event */ + ObDereferenceObject(KeyedEvent); + + /* Return the status */ + return Status; } /* EOF */ diff --git a/reactos/ntoskrnl/include/internal/ex.h b/reactos/ntoskrnl/include/internal/ex.h index ca369395fcb..4f23eb58e5c 100644 --- a/reactos/ntoskrnl/include/internal/ex.h +++ b/reactos/ntoskrnl/include/internal/ex.h @@ -137,7 +137,7 @@ ExGetPoolTagInfo( IN ULONG SystemInformationLength, IN OUT PULONG ReturnLength OPTIONAL ); - + /* INITIALIZATION FUNCTIONS *************************************************/ VOID @@ -208,7 +208,7 @@ ExpInitializeEventImplementation(VOID); VOID NTAPI -ExpInitializeEventImplementation(VOID); +ExpInitializeKeyedEventImplementation(VOID); VOID NTAPI