/* * 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 #define NDEBUG #include /* 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 */