mirror of
https://github.com/reactos/reactos.git
synced 2024-11-27 13:33:32 +08:00
291 lines
6.9 KiB
C
291 lines
6.9 KiB
C
/*
|
|
* PROJECT: ReactOS Kernel
|
|
* LICENSE: GPL - See COPYING in the top level directory
|
|
* FILE: ntoskrnl/ke/eventobj.c
|
|
* PURPOSE: Implements the Event Dispatcher Object
|
|
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
|
|
*/
|
|
|
|
/* INCLUDES ******************************************************************/
|
|
|
|
#include <ntoskrnl.h>
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID
|
|
NTAPI
|
|
KeClearEvent(IN PKEVENT Event)
|
|
{
|
|
ASSERT_EVENT(Event);
|
|
|
|
/* Reset Signal State */
|
|
Event->Header.SignalState = FALSE;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID
|
|
NTAPI
|
|
KeInitializeEvent(OUT PKEVENT Event,
|
|
IN EVENT_TYPE Type,
|
|
IN BOOLEAN State)
|
|
{
|
|
/* Initialize the Dispatcher Header */
|
|
Event->Header.Type = Type;
|
|
//Event->Header.Signalling = FALSE; // fails in kmtest
|
|
Event->Header.Size = sizeof(KEVENT) / sizeof(ULONG);
|
|
Event->Header.SignalState = State;
|
|
InitializeListHead(&(Event->Header.WaitListHead));
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID
|
|
NTAPI
|
|
KeInitializeEventPair(IN PKEVENT_PAIR EventPair)
|
|
{
|
|
/* Initialize the Event Pair Type and Size */
|
|
EventPair->Type = EventPairObject;
|
|
EventPair->Size = sizeof(KEVENT_PAIR);
|
|
|
|
/* Initialize the two Events */
|
|
KeInitializeEvent(&EventPair->LowEvent, SynchronizationEvent, FALSE);
|
|
KeInitializeEvent(&EventPair->HighEvent, SynchronizationEvent, FALSE);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
LONG
|
|
NTAPI
|
|
KePulseEvent(IN PKEVENT Event,
|
|
IN KPRIORITY Increment,
|
|
IN BOOLEAN Wait)
|
|
{
|
|
KIRQL OldIrql;
|
|
LONG PreviousState;
|
|
PKTHREAD Thread;
|
|
ASSERT_EVENT(Event);
|
|
ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
|
|
|
|
/* Lock the Dispatcher Database */
|
|
OldIrql = KiAcquireDispatcherLock();
|
|
|
|
/* Save the Old State */
|
|
PreviousState = Event->Header.SignalState;
|
|
|
|
/* Check if we are non-signaled and we have stuff in the Wait Queue */
|
|
if (!PreviousState && !IsListEmpty(&Event->Header.WaitListHead))
|
|
{
|
|
/* Set the Event to Signaled */
|
|
Event->Header.SignalState = 1;
|
|
|
|
/* Wake the Event */
|
|
KiWaitTest(&Event->Header, Increment);
|
|
}
|
|
|
|
/* Unsignal it */
|
|
Event->Header.SignalState = 0;
|
|
|
|
/* Check what wait state was requested */
|
|
if (Wait == FALSE)
|
|
{
|
|
/* Wait not requested, release Dispatcher Database and return */
|
|
KiReleaseDispatcherLock(OldIrql);
|
|
}
|
|
else
|
|
{
|
|
/* Return Locked and with a Wait */
|
|
Thread = KeGetCurrentThread();
|
|
Thread->WaitNext = TRUE;
|
|
Thread->WaitIrql = OldIrql;
|
|
}
|
|
|
|
/* Return the previous State */
|
|
return PreviousState;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
LONG
|
|
NTAPI
|
|
KeReadStateEvent(IN PKEVENT Event)
|
|
{
|
|
ASSERT_EVENT(Event);
|
|
|
|
/* Return the Signal State */
|
|
return Event->Header.SignalState;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
LONG
|
|
NTAPI
|
|
KeResetEvent(IN PKEVENT Event)
|
|
{
|
|
KIRQL OldIrql;
|
|
LONG PreviousState;
|
|
ASSERT_EVENT(Event);
|
|
ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
|
|
|
|
/* Lock the Dispatcher Database */
|
|
OldIrql = KiAcquireDispatcherLock();
|
|
|
|
/* Save the Previous State */
|
|
PreviousState = Event->Header.SignalState;
|
|
|
|
/* Set it to zero */
|
|
Event->Header.SignalState = 0;
|
|
|
|
/* Release Dispatcher Database and return previous state */
|
|
KiReleaseDispatcherLock(OldIrql);
|
|
return PreviousState;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
LONG
|
|
NTAPI
|
|
KeSetEvent(IN PKEVENT Event,
|
|
IN KPRIORITY Increment,
|
|
IN BOOLEAN Wait)
|
|
{
|
|
KIRQL OldIrql;
|
|
LONG PreviousState;
|
|
PKTHREAD Thread;
|
|
ASSERT_EVENT(Event);
|
|
ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
|
|
|
|
/*
|
|
* Check if this is an signaled notification event without an upcoming wait.
|
|
* In this case, we can immediately return TRUE, without locking.
|
|
*/
|
|
if ((Event->Header.Type == EventNotificationObject) &&
|
|
(Event->Header.SignalState == 1) &&
|
|
!(Wait))
|
|
{
|
|
/* Return the signal state (TRUE/Signalled) */
|
|
return TRUE;
|
|
}
|
|
|
|
/* Lock the Dispathcer Database */
|
|
OldIrql = KiAcquireDispatcherLock();
|
|
|
|
/* Save the Previous State */
|
|
PreviousState = Event->Header.SignalState;
|
|
|
|
/* Set the Event to Signaled */
|
|
Event->Header.SignalState = 1;
|
|
|
|
/* Check if the event just became signaled now, and it has waiters */
|
|
if (!(PreviousState) && !(IsListEmpty(&Event->Header.WaitListHead)))
|
|
{
|
|
/* Check the type of event */
|
|
if (Event->Header.Type == EventNotificationObject)
|
|
{
|
|
/* Unwait the thread */
|
|
KxUnwaitThread(&Event->Header, Increment);
|
|
}
|
|
else
|
|
{
|
|
/* Otherwise unwait the thread and unsignal the event */
|
|
KxUnwaitThreadForEvent(Event, Increment);
|
|
}
|
|
}
|
|
|
|
/* Check what wait state was requested */
|
|
if (!Wait)
|
|
{
|
|
/* Wait not requested, release Dispatcher Database and return */
|
|
KiReleaseDispatcherLock(OldIrql);
|
|
}
|
|
else
|
|
{
|
|
/* Return Locked and with a Wait */
|
|
Thread = KeGetCurrentThread();
|
|
Thread->WaitNext = TRUE;
|
|
Thread->WaitIrql = OldIrql;
|
|
}
|
|
|
|
/* Return the previous State */
|
|
return PreviousState;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID
|
|
NTAPI
|
|
KeSetEventBoostPriority(IN PKEVENT Event,
|
|
IN PKTHREAD *WaitingThread OPTIONAL)
|
|
{
|
|
KIRQL OldIrql;
|
|
PKWAIT_BLOCK WaitBlock;
|
|
PKTHREAD Thread = KeGetCurrentThread(), WaitThread;
|
|
ASSERT(Event->Header.Type == EventSynchronizationObject);
|
|
ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
|
|
|
|
/* Acquire Dispatcher Database Lock */
|
|
OldIrql = KiAcquireDispatcherLock();
|
|
|
|
/* Check if the list is empty */
|
|
if (IsListEmpty(&Event->Header.WaitListHead))
|
|
{
|
|
/* Set the Event to Signaled */
|
|
Event->Header.SignalState = 1;
|
|
|
|
/* Return */
|
|
KiReleaseDispatcherLock(OldIrql);
|
|
return;
|
|
}
|
|
|
|
/* Get the Wait Block */
|
|
WaitBlock = CONTAINING_RECORD(Event->Header.WaitListHead.Flink,
|
|
KWAIT_BLOCK,
|
|
WaitListEntry);
|
|
|
|
/* Check if this is a WaitAll */
|
|
if (WaitBlock->WaitType == WaitAll)
|
|
{
|
|
/* Set the Event to Signaled */
|
|
Event->Header.SignalState = 1;
|
|
|
|
/* Unwait the thread and unsignal the event */
|
|
KxUnwaitThreadForEvent(Event, EVENT_INCREMENT);
|
|
}
|
|
else
|
|
{
|
|
/* Return waiting thread to caller */
|
|
WaitThread = WaitBlock->Thread;
|
|
if (WaitingThread) *WaitingThread = WaitThread;
|
|
|
|
/* Calculate new priority */
|
|
Thread->Priority = KiComputeNewPriority(Thread, 0);
|
|
|
|
/* Unlink the waiting thread */
|
|
KiUnlinkThread(WaitThread, STATUS_SUCCESS);
|
|
|
|
/* Request priority boosting */
|
|
WaitThread->AdjustIncrement = Thread->Priority;
|
|
WaitThread->AdjustReason = AdjustBoost;
|
|
|
|
/* Ready the thread */
|
|
KiReadyThread(WaitThread);
|
|
}
|
|
|
|
/* Release the Dispatcher Database Lock */
|
|
KiReleaseDispatcherLock(OldIrql);
|
|
}
|
|
|
|
/* EOF */
|