You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
983 lines
26 KiB
983 lines
26 KiB
/*++
|
|
|
|
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))) {
|
|
|
|
if (!KeIsAttachedProcess()) {
|
|
KeRaiseUserException (STATUS_INVALID_HANDLE);
|
|
}
|
|
return Status;
|
|
}
|
|
}
|
|
#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;
|
|
}
|