982 lines
24 KiB
C
982 lines
24 KiB
C
/*++
|
||
|
||
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;
|
||
}
|