* 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
*/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
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[] =
{
IQS_SAME(EVENT_BASIC_INFORMATION, ULONG, ICIF_QUERY),
};
CODE_SEG("INIT")
BOOLEAN
NTAPI
ExpInitializeEventImplementation(VOID)
{
OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
UNICODE_STRING Name;
NTSTATUS Status;
DPRINT("Creating Event Object Type\n");
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();
Status = ObReferenceObjectByHandle(EventHandle,
EVENT_MODIFY_STATE,
ExEventObjectType,
ExGetPreviousMode(),
(PVOID*)&Event,
NULL);
if(NT_SUCCESS(Status))
{
KeClearEvent(Event);
ObDereferenceObject(Event);
}
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);
if ((EventType != NotificationEvent) &&
(EventType != SynchronizationEvent))
{
return STATUS_INVALID_PARAMETER;
}
if (PreviousMode != KernelMode)
{
_SEH2_TRY
{
ProbeForWriteHandle(EventHandle);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
Status = ObCreateObject(PreviousMode,
ExEventObjectType,
ObjectAttributes,
PreviousMode,
NULL,
sizeof(KEVENT),
0,
0,
(PVOID*)&Event);
if (!NT_SUCCESS(Status))
{
DPRINT1("ObCreateObject failed: 0x%X\n", Status);
return Status;
}
KeInitializeEvent(Event, EventType, InitialState);
Status = ObInsertObject((PVOID)Event,
NULL,
DesiredAccess,
0,
NULL,
&hEvent);
if (!NT_SUCCESS(Status))
{
DPRINT1("ObInsertObject failed: 0x%X\n", Status);
return Status;
}
_SEH2_TRY
{
*EventHandle = hEvent;
}
_SEH2_EXCEPT(ExSystemExceptionFilter())
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
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);
if (PreviousMode != KernelMode)
{
_SEH2_TRY
{
ProbeForWriteHandle(EventHandle);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
Status = ObOpenObjectByName(ObjectAttributes,
ExEventObjectType,
PreviousMode,
NULL,
DesiredAccess,
NULL,
&hEvent);
if (NT_SUCCESS(Status))
{
_SEH2_TRY
{
*EventHandle = hEvent;
}
_SEH2_EXCEPT(ExSystemExceptionFilter())
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
}
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);
if((PreviousState) && (PreviousMode != KernelMode))
{
_SEH2_TRY
{
ProbeForWriteLong(PreviousState);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
Status = ObReferenceObjectByHandle(EventHandle,
EVENT_MODIFY_STATE,
ExEventObjectType,
PreviousMode,
(PVOID*)&Event,
NULL);
if(NT_SUCCESS(Status))
{
LONG Prev = KePulseEvent(Event, EVENT_INCREMENT, FALSE);
ObDereferenceObject(Event);
if(PreviousState)
{
_SEH2_TRY
{
*PreviousState = Prev;
}
_SEH2_EXCEPT(ExSystemExceptionFilter())
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
}
}
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);
Status = DefaultQueryInfoBufferCheck(EventInformationClass,
ExEventInfoClass,
sizeof(ExEventInfoClass) /
sizeof(ExEventInfoClass[0]),
ICIF_PROBE_READ_WRITE,
EventInformation,
EventInformationLength,
ReturnLength,
NULL,
PreviousMode);
if(!NT_SUCCESS(Status))
{
DPRINT("NtQuerySemaphore() failed, Status: 0x%x\n", Status);
return Status;
}
Status = ObReferenceObjectByHandle(EventHandle,
EVENT_QUERY_STATE,
ExEventObjectType,
PreviousMode,
(PVOID*)&Event,
NULL);
if(NT_SUCCESS(Status))
{
_SEH2_TRY
{
BasicInfo->EventType = Event->Header.Type;
BasicInfo->EventState = KeReadStateEvent(Event);
if(ReturnLength) *ReturnLength = sizeof(EVENT_BASIC_INFORMATION);
}
_SEH2_EXCEPT(ExSystemExceptionFilter())
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
ObDereferenceObject(Event);
}
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);
if ((PreviousState) && (PreviousMode != KernelMode))
{
_SEH2_TRY
{
ProbeForWriteLong(PreviousState);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
Status = ObReferenceObjectByHandle(EventHandle,
EVENT_MODIFY_STATE,
ExEventObjectType,
PreviousMode,
(PVOID*)&Event,
NULL);
if(NT_SUCCESS(Status))
{
LONG Prev = KeResetEvent(Event);
ObDereferenceObject(Event);
if(PreviousState)
{
_SEH2_TRY
{
*PreviousState = Prev;
}
_SEH2_EXCEPT(ExSystemExceptionFilter())
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
}
}
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);
if ((PreviousState) && (PreviousMode != KernelMode))
{
_SEH2_TRY
{
ProbeForWriteLong(PreviousState);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
Status = ObReferenceObjectByHandle(EventHandle,
EVENT_MODIFY_STATE,
ExEventObjectType,
PreviousMode,
(PVOID*)&Event,
NULL);
if (NT_SUCCESS(Status))
{
LONG Prev = KeSetEvent(Event, EVENT_INCREMENT, FALSE);
ObDereferenceObject(Event);
if (PreviousState)
{
_SEH2_TRY
{
*PreviousState = Prev;
}
_SEH2_EXCEPT(ExSystemExceptionFilter())
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
}
}
return Status;
}
* @implemented
*/
NTSTATUS
NTAPI
NtSetEventBoostPriority(IN HANDLE EventHandle)
{
PKEVENT Event;
NTSTATUS Status;
PAGED_CODE();
Status = ObReferenceObjectByHandle(EventHandle,
EVENT_MODIFY_STATE,
ExEventObjectType,
ExGetPreviousMode(),
(PVOID*)&Event,
NULL);
if (NT_SUCCESS(Status))
{
KeSetEventBoostPriority(Event, NULL);
ObDereferenceObject(Event);
}
return Status;
}