reactos/ntoskrnl/ex/event.c

549 lines
15 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Kernel
* FILE: ntoskrnl/ex/event.c
* PURPOSE: Event support
* PROGRAMMERS: Alex Ionescu(alex@relsoft.net)
* Thomas Weidenmueller
*/
/* INCLUDES *****************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
#if defined (ALLOC_PRAGMA)
#pragma alloc_text(INIT, ExpInitializeEventImplementation)
#endif
/* GLOBALS *******************************************************************/
POBJECT_TYPE ExEventObjectType = NULL;
GENERIC_MAPPING ExpEventMapping =
{
STANDARD_RIGHTS_READ | EVENT_QUERY_STATE,
STANDARD_RIGHTS_WRITE | EVENT_MODIFY_STATE,
STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE,
EVENT_ALL_ACCESS
};
static const INFORMATION_CLASS_INFO ExEventInfoClass[] =
{
/* EventBasicInformation */
ICI_SQ_SAME( sizeof(EVENT_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY),
};
/* FUNCTIONS *****************************************************************/
BOOLEAN
INIT_FUNCTION
NTAPI
ExpInitializeEventImplementation(VOID)
{
OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
UNICODE_STRING Name;
NTSTATUS Status;
DPRINT("Creating Event Object Type\n");
/* Create the Event Object Type */
RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
RtlInitUnicodeString(&Name, L"Event");
ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(KEVENT);
ObjectTypeInitializer.GenericMapping = ExpEventMapping;
ObjectTypeInitializer.PoolType = NonPagedPool;
ObjectTypeInitializer.ValidAccessMask = EVENT_ALL_ACCESS;
ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK;
Status = ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &ExEventObjectType);
if (!NT_SUCCESS(Status)) return FALSE;
return TRUE;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
NtClearEvent(IN HANDLE EventHandle)
{
PKEVENT Event;
NTSTATUS Status;
PAGED_CODE();
/* Reference the Object */
Status = ObReferenceObjectByHandle(EventHandle,
EVENT_MODIFY_STATE,
ExEventObjectType,
ExGetPreviousMode(),
(PVOID*)&Event,
NULL);
/* Check for Success */
if(NT_SUCCESS(Status))
{
/* Clear the Event and Dereference */
KeClearEvent(Event);
ObDereferenceObject(Event);
}
/* Return Status */
return Status;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
NtCreateEvent(OUT PHANDLE EventHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
IN EVENT_TYPE EventType,
IN BOOLEAN InitialState)
{
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
PKEVENT Event;
HANDLE hEvent;
NTSTATUS Status;
PAGED_CODE();
DPRINT("NtCreateEvent(0x%p, 0x%x, 0x%p)\n",
EventHandle, DesiredAccess, ObjectAttributes);
/* Check if we were called from user-mode */
if (PreviousMode != KernelMode)
{
/* Enter SEH Block */
_SEH2_TRY
{
/* Check handle pointer */
ProbeForWriteHandle(EventHandle);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Return the exception code */
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
/* Create the Object */
Status = ObCreateObject(PreviousMode,
ExEventObjectType,
ObjectAttributes,
PreviousMode,
NULL,
sizeof(KEVENT),
0,
0,
(PVOID*)&Event);
/* Check for Success */
if (NT_SUCCESS(Status))
{
/* Initialize the Event */
KeInitializeEvent(Event,
EventType,
InitialState);
/* Insert it */
Status = ObInsertObject((PVOID)Event,
NULL,
DesiredAccess,
0,
NULL,
&hEvent);
/* Check for success */
if (NT_SUCCESS(Status))
{
/* Enter SEH for return */
_SEH2_TRY
{
/* Return the handle to the caller */
*EventHandle = hEvent;
}
_SEH2_EXCEPT(ExSystemExceptionFilter())
{
/* Get the exception code */
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
}
}
/* Return Status */
return Status;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
NtOpenEvent(OUT PHANDLE EventHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes)
{
HANDLE hEvent;
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
NTSTATUS Status;
PAGED_CODE();
DPRINT("NtOpenEvent(0x%p, 0x%x, 0x%p)\n",
EventHandle, DesiredAccess, ObjectAttributes);
/* Check if we were called from user-mode */
if (PreviousMode != KernelMode)
{
/* Enter SEH Block */
_SEH2_TRY
{
/* Check handle pointer */
ProbeForWriteHandle(EventHandle);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Return the exception code */
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
/* Open the Object */
Status = ObOpenObjectByName(ObjectAttributes,
ExEventObjectType,
PreviousMode,
NULL,
DesiredAccess,
NULL,
&hEvent);
/* Check for success */
if (NT_SUCCESS(Status))
{
/* Enter SEH for return */
_SEH2_TRY
{
/* Return the handle to the caller */
*EventHandle = hEvent;
}
_SEH2_EXCEPT(ExSystemExceptionFilter())
{
/* Get the exception code */
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
}
/* Return status */
return Status;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
NtPulseEvent(IN HANDLE EventHandle,
OUT PLONG PreviousState OPTIONAL)
{
PKEVENT Event;
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
NTSTATUS Status;
PAGED_CODE();
DPRINT("NtPulseEvent(EventHandle 0%p PreviousState 0%p)\n",
EventHandle, PreviousState);
/* Check if we were called from user-mode */
if((PreviousState) && (PreviousMode != KernelMode))
{
/* Entry SEH Block */
_SEH2_TRY
{
/* Make sure the state pointer is valid */
ProbeForWriteLong(PreviousState);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Return the exception code */
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
/* Open the Object */
Status = ObReferenceObjectByHandle(EventHandle,
EVENT_MODIFY_STATE,
ExEventObjectType,
PreviousMode,
(PVOID*)&Event,
NULL);
/* Check for success */
if(NT_SUCCESS(Status))
{
/* Pulse the Event */
LONG Prev = KePulseEvent(Event, EVENT_INCREMENT, FALSE);
ObDereferenceObject(Event);
/* Check if caller wants the old state back */
if(PreviousState)
{
/* Entry SEH Block for return */
_SEH2_TRY
{
/* Return previous state */
*PreviousState = Prev;
}
_SEH2_EXCEPT(ExSystemExceptionFilter())
{
/* Get the exception code */
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
}
}
/* Return Status */
return Status;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
NtQueryEvent(IN HANDLE EventHandle,
IN EVENT_INFORMATION_CLASS EventInformationClass,
OUT PVOID EventInformation,
IN ULONG EventInformationLength,
OUT PULONG ReturnLength OPTIONAL)
{
PKEVENT Event;
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
NTSTATUS Status;
PEVENT_BASIC_INFORMATION BasicInfo =
(PEVENT_BASIC_INFORMATION)EventInformation;
PAGED_CODE();
DPRINT("NtQueryEvent(0x%p, 0x%x)\n", EventHandle, EventInformationClass);
/* Check buffers and class validity */
Status = DefaultQueryInfoBufferCheck(EventInformationClass,
ExEventInfoClass,
sizeof(ExEventInfoClass) /
sizeof(ExEventInfoClass[0]),
EventInformation,
EventInformationLength,
ReturnLength,
NULL,
PreviousMode);
if(!NT_SUCCESS(Status))
{
/* Invalid buffers */
DPRINT("NtQuerySemaphore() failed, Status: 0x%x\n", Status);
return Status;
}
/* Get the Object */
Status = ObReferenceObjectByHandle(EventHandle,
EVENT_QUERY_STATE,
ExEventObjectType,
PreviousMode,
(PVOID*)&Event,
NULL);
/* Check for success */
if(NT_SUCCESS(Status))
{
/* Entry SEH Block */
_SEH2_TRY
{
/* Return Event Type and State */
BasicInfo->EventType = Event->Header.Type;
BasicInfo->EventState = KeReadStateEvent(Event);
/* Return length */
if(ReturnLength) *ReturnLength = sizeof(EVENT_BASIC_INFORMATION);
}
_SEH2_EXCEPT(ExSystemExceptionFilter())
{
/* Get the exception code */
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
/* Dereference the Object */
ObDereferenceObject(Event);
}
/* Return status */
return Status;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
NtResetEvent(IN HANDLE EventHandle,
OUT PLONG PreviousState OPTIONAL)
{
PKEVENT Event;
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
NTSTATUS Status;
PAGED_CODE();
DPRINT("NtResetEvent(EventHandle 0%p PreviousState 0%p)\n",
EventHandle, PreviousState);
/* Check if we were called from user-mode */
if ((PreviousState) && (PreviousMode != KernelMode))
{
/* Entry SEH Block */
_SEH2_TRY
{
/* Make sure the state pointer is valid */
ProbeForWriteLong(PreviousState);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Return the exception code */
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
/* Open the Object */
Status = ObReferenceObjectByHandle(EventHandle,
EVENT_MODIFY_STATE,
ExEventObjectType,
PreviousMode,
(PVOID*)&Event,
NULL);
/* Check for success */
if(NT_SUCCESS(Status))
{
/* Reset the Event */
LONG Prev = KeResetEvent(Event);
ObDereferenceObject(Event);
/* Check if caller wants the old state back */
if(PreviousState)
{
/* Entry SEH Block for return */
_SEH2_TRY
{
/* Return previous state */
*PreviousState = Prev;
}
_SEH2_EXCEPT(ExSystemExceptionFilter())
{
/* Get the exception code */
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
}
}
/* Return Status */
return Status;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
NtSetEvent(IN HANDLE EventHandle,
OUT PLONG PreviousState OPTIONAL)
{
PKEVENT Event;
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
NTSTATUS Status;
PAGED_CODE();
DPRINT("NtSetEvent(EventHandle 0%p PreviousState 0%p)\n",
EventHandle, PreviousState);
/* Check if we were called from user-mode */
if ((PreviousState) && (PreviousMode != KernelMode))
{
/* Entry SEH Block */
_SEH2_TRY
{
/* Make sure the state pointer is valid */
ProbeForWriteLong(PreviousState);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Return the exception code */
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
/* Open the Object */
Status = ObReferenceObjectByHandle(EventHandle,
EVENT_MODIFY_STATE,
ExEventObjectType,
PreviousMode,
(PVOID*)&Event,
NULL);
if (NT_SUCCESS(Status))
{
/* Set the Event */
LONG Prev = KeSetEvent(Event, EVENT_INCREMENT, FALSE);
ObDereferenceObject(Event);
/* Check if caller wants the old state back */
if (PreviousState)
{
/* Entry SEH Block for return */
_SEH2_TRY
{
/* Return previous state */
*PreviousState = Prev;
}
_SEH2_EXCEPT(ExSystemExceptionFilter())
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
}
}
/* Return Status */
return Status;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
NtSetEventBoostPriority(IN HANDLE EventHandle)
{
PKEVENT Event;
NTSTATUS Status;
PAGED_CODE();
/* Open the Object */
Status = ObReferenceObjectByHandle(EventHandle,
EVENT_MODIFY_STATE,
ExEventObjectType,
ExGetPreviousMode(),
(PVOID*)&Event,
NULL);
if (NT_SUCCESS(Status))
{
/* Set the Event */
KeSetEventBoostPriority(Event, NULL);
ObDereferenceObject(Event);
}
/* Return Status */
return Status;
}
/* EOF */