|
|
/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
event.c
Abstract:
This module implements the executive event object. Functions are provided to create, open, set, reset, pulse, and query event objects.
Author:
David N. Cutler (davec) 8-May-1989
Environment:
Kernel mode only.
Revision History:
--*/
#include "exp.h"
//
// Temporary so boost is patchable
//
ULONG ExpEventBoost = EVENT_INCREMENT;
//
// Address of event object type descriptor.
//
POBJECT_TYPE ExEventObjectType;
//
// Structure that describes the mapping of generic access rights to object
// specific access rights for event objects.
//
#ifdef ALLOC_DATA_PRAGMA
#pragma const_seg("INITCONST")
#endif
const GENERIC_MAPPING ExpEventMapping = { STANDARD_RIGHTS_READ | EVENT_QUERY_STATE, STANDARD_RIGHTS_WRITE | EVENT_MODIFY_STATE, STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE, EVENT_ALL_ACCESS }; #ifdef ALLOC_DATA_PRAGMA
#pragma const_seg()
#endif
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, ExpEventInitialization)
#pragma alloc_text(PAGE, NtClearEvent)
#pragma alloc_text(PAGE, NtCreateEvent)
#pragma alloc_text(PAGE, NtOpenEvent)
#pragma alloc_text(PAGE, NtPulseEvent)
#pragma alloc_text(PAGE, NtQueryEvent)
#pragma alloc_text(PAGE, NtResetEvent)
#pragma alloc_text(PAGE, NtSetEvent)
#pragma alloc_text(PAGE, NtSetEventBoostPriority)
#endif
BOOLEAN ExpEventInitialization ( )
/*++
Routine Description:
This function creates the event object type descriptor at system initialization and stores the address of the object type descriptor in global storage.
Arguments:
None.
Return Value:
A value of TRUE is returned if the event object type descriptor is successfully initialized. Otherwise a value of FALSE is returned.
--*/
{
OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; NTSTATUS Status; UNICODE_STRING TypeName;
//
// Initialize string descriptor.
//
RtlInitUnicodeString(&TypeName, L"Event");
//
// Create event object type descriptor.
//
RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer); ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK; ObjectTypeInitializer.GenericMapping = ExpEventMapping; ObjectTypeInitializer.PoolType = NonPagedPool; ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(KEVENT); ObjectTypeInitializer.ValidAccessMask = EVENT_ALL_ACCESS; Status = ObCreateObjectType(&TypeName, &ObjectTypeInitializer, (PSECURITY_DESCRIPTOR)NULL, &ExEventObjectType);
//
// If the event object type descriptor was successfully created, then
// return a value of TRUE. Otherwise return a value of FALSE.
//
return (BOOLEAN)(NT_SUCCESS(Status)); }
NTSTATUS NtClearEvent ( IN HANDLE EventHandle )
/*++
Routine Description:
This function sets an event object to a Not-Signaled state.
Arguments:
EventHandle - Supplies a handle to an event object.
Return Value:
NTSTATUS.
--*/
{
PVOID Event; NTSTATUS Status;
//
// Reference event object by handle.
//
Status = ObReferenceObjectByHandle(EventHandle, EVENT_MODIFY_STATE, ExEventObjectType, KeGetPreviousMode(), &Event, NULL);
//
// If the reference was successful, then set the state of the event
// object to Not-Signaled and dereference event object.
//
if (NT_SUCCESS(Status)) { PERFINFO_DECLARE_OBJECT(Event); KeClearEvent((PKEVENT)Event); ObDereferenceObject(Event); }
//
// Return service status.
//
return Status; }
NTSTATUS NtCreateEvent ( OUT PHANDLE EventHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN EVENT_TYPE EventType, IN BOOLEAN InitialState )
/*++
Routine Description:
This function creates an event object, sets it initial state to the specified value, and opens a handle to the object with the specified desired access.
Arguments:
EventHandle - Supplies a pointer to a variable that will receive the event object handle.
DesiredAccess - Supplies the desired types of access for the event object.
ObjectAttributes - Supplies a pointer to an object attributes structure.
EventType - Supplies the type of the event (autoclearing or notification).
InitialState - Supplies the initial state of the event object.
Return Value:
NTSTATUS.
--*/
{
PVOID Event; HANDLE Handle; KPROCESSOR_MODE PreviousMode; NTSTATUS Status;
//
// Establish an exception handler, probe the output handle address, and
// attempt to create an event object. If the probe fails, then return the
// exception code as the service status. Otherwise return the status value
// returned by the object insertion routine.
//
PreviousMode = KeGetPreviousMode();
//
// Get previous processor mode and probe output handle address if
// necessary.
//
if (PreviousMode != KernelMode) { try { ProbeForWriteHandle(EventHandle); } except(ExSystemExceptionFilter()) { return GetExceptionCode(); } }
//
// Check argument validity.
//
if ((EventType != NotificationEvent) && (EventType != SynchronizationEvent)) { return STATUS_INVALID_PARAMETER; }
//
// Allocate event object.
//
Status = ObCreateObject(PreviousMode, ExEventObjectType, ObjectAttributes, PreviousMode, NULL, sizeof(KEVENT), 0, 0, (PVOID *)&Event);
//
// If the event object was successfully allocated, then initialize the
// event object and attempt to insert the event object in the current
// process' handle table.
//
if (NT_SUCCESS(Status)) { KeInitializeEvent((PKEVENT)Event, EventType, InitialState); Status = ObInsertObject(Event, NULL, DesiredAccess, 0, (PVOID *)NULL, &Handle);
//
// If the event object was successfully inserted in the current
// process' handle table, then attempt to write the event object
// handle value. If the write attempt fails, then do not report
// an error. When the caller attempts to access the handle value,
// an access violation will occur.
//
if (NT_SUCCESS(Status)) { if (PreviousMode != KernelMode) { try { *EventHandle = Handle;
} except(ExSystemExceptionFilter()) { NOTHING; } } else { *EventHandle = Handle; } } }
//
// Return service status.
//
return Status; }
NTSTATUS NtOpenEvent ( OUT PHANDLE EventHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes )
/*++
Routine Description:
This function opens a handle to an event object with the specified desired access.
Arguments:
EventHandle - Supplies a pointer to a variable that will receive the event object handle.
DesiredAccess - Supplies the desired types of access for the event object.
ObjectAttributes - Supplies a pointer to an object attributes structure.
Return Value:
NTSTATUS.
--*/
{
HANDLE Handle; KPROCESSOR_MODE PreviousMode; NTSTATUS Status;
//
// Establish an exception handler, probe the output handle address, and
// attempt to open the event object. If the probe fails, then return the
// exception code as the service status. Otherwise return the status value
// returned by the object open routine.
//
//
// Get previous processor mode and probe output handle address
// if necessary.
//
PreviousMode = KeGetPreviousMode();
if (PreviousMode != KernelMode) { try { ProbeForWriteHandle(EventHandle); } except(ExSystemExceptionFilter()) { return GetExceptionCode(); } }
//
// Open handle to the event object with the specified desired access.
//
Status = ObOpenObjectByName(ObjectAttributes, ExEventObjectType, PreviousMode, NULL, DesiredAccess, NULL, &Handle);
//
// If the open was successful, then attempt to write the event object
// handle value. If the write attempt fails, then do not report an
// error. When the caller attempts to access the handle value, an
// access violation will occur.
//
if (NT_SUCCESS(Status)) { if (PreviousMode != KernelMode) { try { *EventHandle = Handle;
} except(ExSystemExceptionFilter()) { NOTHING; } } else { *EventHandle = Handle; } }
//
// Return service status.
//
return Status; }
NTSTATUS NtPulseEvent ( IN HANDLE EventHandle, OUT PLONG PreviousState OPTIONAL )
/*++
Routine Description:
This function sets an event object to a Signaled state, attempts to satisfy as many waits as possible, and then resets the state of the event object to Not-Signaled.
Arguments:
EventHandle - Supplies a handle to an event object.
PreviousState - Supplies an optional pointer to a variable that will receive the previous state of the event object.
Return Value:
NTSTATUS.
--*/
{
PVOID Event; KPROCESSOR_MODE PreviousMode; LONG State; NTSTATUS Status;
//
// Establish an exception handler, probe the previous state address if
// specified, reference the event object, and pulse the event object. If
// the probe fails, then return the exception code as the service status.
// Otherwise return the status value returned by the reference object by
// handle routine.
//
//
// Get previous processor mode and probe previous state address
// if necessary.
//
PreviousMode = KeGetPreviousMode();
if (ARGUMENT_PRESENT(PreviousState) && (PreviousMode != KernelMode)) { try { ProbeForWriteLong(PreviousState); } except(ExSystemExceptionFilter()) { return GetExceptionCode(); } }
//
// Reference event object by handle.
//
Status = ObReferenceObjectByHandle(EventHandle, EVENT_MODIFY_STATE, ExEventObjectType, PreviousMode, &Event, NULL);
//
// If the reference was successful, then pulse the event object,
// dereference event object, and write the previous state value if
// specified. If the write of the previous state fails, then do not
// report an error. When the caller attempts to access the previous
// state value, an access violation will occur.
//
if (NT_SUCCESS(Status)) { PERFINFO_DECLARE_OBJECT(Event); State = KePulseEvent((PKEVENT)Event, ExpEventBoost, FALSE); ObDereferenceObject(Event); if (ARGUMENT_PRESENT(PreviousState)) { if (PreviousMode != KernelMode) { try { *PreviousState = State;
} except(ExSystemExceptionFilter()) { NOTHING; } } else { *PreviousState = State; } } }
//
// Return service status.
//
return Status; }
NTSTATUS NtQueryEvent ( IN HANDLE EventHandle, IN EVENT_INFORMATION_CLASS EventInformationClass, OUT PVOID EventInformation, IN ULONG EventInformationLength, OUT PULONG ReturnLength OPTIONAL )
/*++
Routine Description:
This function queries the state of an event object and returns the requested information in the specified record structure.
Arguments:
EventHandle - Supplies a handle to an event object.
EventInformationClass - Supplies the class of information being requested.
EventInformation - Supplies a pointer to a record that is to receive the requested information.
EventInformationLength - Supplies the length of the record that is to receive the requested information.
ReturnLength - Supplies an optional pointer to a variable that is to receive the actual length of information that is returned.
Return Value:
NTSTATUS.
--*/
{
PKEVENT Event; KPROCESSOR_MODE PreviousMode; LONG State; NTSTATUS Status; EVENT_TYPE EventType;
//
// Check argument validity.
//
if (EventInformationClass != EventBasicInformation) { return STATUS_INVALID_INFO_CLASS; }
if (EventInformationLength != sizeof(EVENT_BASIC_INFORMATION)) { return STATUS_INFO_LENGTH_MISMATCH; }
//
// Establish an exception handler, probe the output arguments, reference
// the event object, and return the specified information. If the probe
// fails, then return the exception code as the service status. Otherwise
// return the status value returned by the reference object by handle
// routine.
//
//
// Get previous processor mode and probe output arguments if necessary.
//
PreviousMode = KeGetPreviousMode();
if (PreviousMode != KernelMode) { try {
ProbeForWrite(EventInformation, sizeof(EVENT_BASIC_INFORMATION), sizeof(ULONG));
if (ARGUMENT_PRESENT(ReturnLength)) { ProbeForWriteUlong(ReturnLength); } } except(ExSystemExceptionFilter()) { return GetExceptionCode(); } }
//
// Reference event object by handle.
//
Status = ObReferenceObjectByHandle(EventHandle, EVENT_QUERY_STATE, ExEventObjectType, PreviousMode, (PVOID *)&Event, NULL);
//
// If the reference was successful, then read the current state of
// the event object, deference event object, fill in the information
// structure, and return the length of the information structure if
// specified. If the write of the event information or the return
// length fails, then do not report an error. When the caller accesses
// the information structure or length an access violation will occur.
//
if (NT_SUCCESS(Status)) { State = KeReadStateEvent(Event); EventType = Event->Header.Type; ObDereferenceObject(Event);
if (PreviousMode != KernelMode) { try { ((PEVENT_BASIC_INFORMATION)EventInformation)->EventType = EventType; ((PEVENT_BASIC_INFORMATION)EventInformation)->EventState = State; if (ARGUMENT_PRESENT(ReturnLength)) { *ReturnLength = sizeof(EVENT_BASIC_INFORMATION); }
} except(ExSystemExceptionFilter()) { NOTHING; } } else { ((PEVENT_BASIC_INFORMATION)EventInformation)->EventType = EventType; ((PEVENT_BASIC_INFORMATION)EventInformation)->EventState = State; if (ARGUMENT_PRESENT(ReturnLength)) { *ReturnLength = sizeof(EVENT_BASIC_INFORMATION); } } }
//
// Return service status.
//
return Status; }
NTSTATUS NtResetEvent ( IN HANDLE EventHandle, OUT PLONG PreviousState OPTIONAL )
/*++
Routine Description:
This function sets an event object to a Not-Signaled state.
Arguments:
EventHandle - Supplies a handle to an event object.
PreviousState - Supplies an optional pointer to a variable that will receive the previous state of the event object.
Return Value:
NTSTATUS.
--*/
{
PVOID Event; KPROCESSOR_MODE PreviousMode; LONG State; NTSTATUS Status;
//
// Establish an exception handler, probe the previous state address if
// specified, reference the event object, and reset the event object. If
// the probe fails, then return the exception code as the service status.
// Otherwise return the status value returned by the reference object by
// handle routine.
//
//
// Get previous processor mode and probe previous state address
// if necessary.
//
PreviousMode = KeGetPreviousMode();
if ((ARGUMENT_PRESENT(PreviousState)) && (PreviousMode != KernelMode)) {
try { ProbeForWriteLong(PreviousState); } except(ExSystemExceptionFilter()) { return GetExceptionCode(); } }
//
// Reference event object by handle.
//
Status = ObReferenceObjectByHandle(EventHandle, EVENT_MODIFY_STATE, ExEventObjectType, PreviousMode, &Event, NULL);
//
// If the reference was successful, then set the state of the event
// object to Not-Signaled, dereference event object, and write the
// previous state value if specified. If the write of the previous
// state fails, then do not report an error. When the caller attempts
// to access the previous state value, an access violation will occur.
//
if (NT_SUCCESS(Status)) { PERFINFO_DECLARE_OBJECT(Event); State = KeResetEvent((PKEVENT)Event); ObDereferenceObject(Event);
if (ARGUMENT_PRESENT(PreviousState)) { if (PreviousMode != KernelMode) { try { *PreviousState = State;
} except(ExSystemExceptionFilter()) { NOTHING; } } else { *PreviousState = State; } } }
//
// Return service status.
//
return Status; }
NTSTATUS NtSetEvent ( IN HANDLE EventHandle, OUT PLONG PreviousState OPTIONAL )
/*++
Routine Description:
This function sets an event object to a Signaled state and attempts to satisfy as many waits as possible.
Arguments:
EventHandle - Supplies a handle to an event object.
PreviousState - Supplies an optional pointer to a variable that will receive the previous state of the event object.
Return Value:
NTSTATUS.
--*/
{
PVOID Event; KPROCESSOR_MODE PreviousMode; LONG State; NTSTATUS Status; #if DBG
//
// Sneaky trick here to catch sleazy apps (csrss) that erroneously call
// NtSetEvent on an event that happens to be somebody else's
// critical section. Only allow setting a protected handle if the low
// bit of PreviousState is set.
//
OBJECT_HANDLE_INFORMATION HandleInfo;
#endif
//
// Establish an exception handler, probe the previous state address if
// specified, reference the event object, and set the event object. If
// the probe fails, then return the exception code as the service status.
// Otherwise return the status value returned by the reference object by
// handle routine.
//
//
// Get previous processor mode and probe previous state address
// if necessary.
//
PreviousMode = KeGetPreviousMode();
try {
#if DBG
if ((PreviousMode != KernelMode) && (ARGUMENT_PRESENT(PreviousState)) && (PreviousState != (PLONG)1)) { ProbeForWriteLong(PreviousState); } #else
if ((PreviousMode != KernelMode) && (ARGUMENT_PRESENT(PreviousState))) { ProbeForWriteLong(PreviousState); } #endif
//
// Reference event object by handle.
//
#if DBG
Status = ObReferenceObjectByHandle(EventHandle, EVENT_MODIFY_STATE, ExEventObjectType, PreviousMode, &Event, &HandleInfo); if (NT_SUCCESS(Status)) {
if ((HandleInfo.HandleAttributes & 1) && (PreviousState != (PLONG)1)) { #if 0
//
// This is a protected handle. If the low bit of PreviousState is NOT set,
// break into the debugger
//
DbgPrint("NtSetEvent: Illegal call to NtSetEvent on a protected handle\n"); DbgBreakPoint(); PreviousState = NULL; #endif
} } else { if ((KeGetPreviousMode() != KernelMode) && (EventHandle != NULL) && ((NtGlobalFlag & FLG_ENABLE_CLOSE_EXCEPTIONS) || (PsGetCurrentProcess()->DebugPort != NULL))) {
return KeRaiseUserException(STATUS_INVALID_HANDLE);
} } #else
Status = ObReferenceObjectByHandle(EventHandle, EVENT_MODIFY_STATE, ExEventObjectType, PreviousMode, &Event, NULL); #endif
//
// If the reference was successful, then set the event object to the
// Signaled state, dereference event object, and write the previous
// state value if specified. If the write of the previous state fails,
// then do not report an error. When the caller attempts to access the
// previous state value, an access violation will occur.
//
if (NT_SUCCESS(Status)) { PERFINFO_DECLARE_OBJECT(Event); State = KeSetEvent((PKEVENT)Event, ExpEventBoost, FALSE); ObDereferenceObject(Event); if (ARGUMENT_PRESENT(PreviousState)) { try { *PreviousState = State;
} except(ExSystemExceptionFilter()) { } } }
//
// If an exception occurs during the probe of the previous state, then
// always handle the exception and return the exception code as the status
// value.
//
} except(ExSystemExceptionFilter()) { return GetExceptionCode(); }
//
// Return service status.
//
return Status; }
NTSTATUS NtSetEventBoostPriority ( IN HANDLE EventHandle )
/*++
Routine Description:
This function sets an event object to a Signaled state and performs a special priority boost operation.
N.B. This service can only be performed on synchronization events.
Arguments:
EventHandle - Supplies a handle to an event object.
PreviousState - Supplies an optional pointer to a variable that will receive the previous state of the event object.
Return Value:
NTSTATUS.
--*/
{
PKEVENT Event; NTSTATUS Status;
//
// Reference event object by handle.
//
Status = ObReferenceObjectByHandle(EventHandle, EVENT_MODIFY_STATE, ExEventObjectType, KeGetPreviousMode(), &Event, NULL);
//
// If the reference was successful, then check the type of event object.
// If the event object is a notification event, then return an object
// type mismatch status. Otherwise, set the specified event and boost
// the unwaited thread priority as appropriate.
//
if (NT_SUCCESS(Status)) { if (Event->Header.Type == NotificationEvent) { Status = STATUS_OBJECT_TYPE_MISMATCH;
} else { KeSetEventBoostPriority(Event, NULL); }
ObDereferenceObject(Event); }
//
// Return service status.
//
return Status; }
|