mirror of
https://github.com/reactos/reactos.git
synced 2025-02-23 08:55:19 +00:00
[NTOSKRNL]
Implement keyed events (untested) svn path=/trunk/; revision=56373
This commit is contained in:
parent
3da4729f56
commit
9f34d2cfc7
3 changed files with 411 additions and 26 deletions
|
@ -664,6 +664,7 @@ ExpInitSystemPhase1(VOID)
|
|||
/* Initialize events and event pairs */
|
||||
ExpInitializeEventImplementation();
|
||||
ExpInitializeEventPairImplementation();
|
||||
ExpInitializeKeyedEventImplementation();
|
||||
|
||||
/* Initialize callbacks */
|
||||
ExpInitializeCallbacks();
|
||||
|
|
|
@ -12,51 +12,435 @@
|
|||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
/* 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 */
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue