reactos/ntoskrnl/ke/gate.c

233 lines
6.7 KiB
C

/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/ke/gate.c
* PURPOSE: Implements the Gate Dispatcher Object
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES *****************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
/* FUNCTIONS ****************************************************************/
VOID
FASTCALL
KeInitializeGate(IN PKGATE Gate)
{
/* Initialize the Dispatcher Header */
Gate->Header.Type = GateObject;
Gate->Header.Signalling = FALSE;
Gate->Header.Size = sizeof(KGATE) / sizeof(ULONG);
Gate->Header.SignalState = 0;
InitializeListHead(&(Gate->Header.WaitListHead));
}
VOID
FASTCALL
KeWaitForGate(IN PKGATE Gate,
IN KWAIT_REASON WaitReason,
IN KPROCESSOR_MODE WaitMode)
{
KLOCK_QUEUE_HANDLE ApcLock;
PKTHREAD Thread = KeGetCurrentThread();
PKWAIT_BLOCK GateWaitBlock;
LONG_PTR Status;
PKQUEUE Queue;
ASSERT_GATE(Gate);
ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
/* Start wait loop */
do
{
/* Acquire the APC lock */
KiAcquireApcLock(Thread, &ApcLock);
/* Check if a kernel APC is pending and we're below APC_LEVEL */
if ((Thread->ApcState.KernelApcPending) &&
!(Thread->SpecialApcDisable) &&
(ApcLock.OldIrql < APC_LEVEL))
{
/* Release the lock, this will fire the APC */
KiReleaseApcLock(&ApcLock);
}
else
{
/* Check if we have a queue and lock the dispatcher if so */
Queue = Thread->Queue;
if (Queue) KiAcquireDispatcherLockAtDpcLevel();
/* Lock the thread */
KiAcquireThreadLock(Thread);
/* Lock the gate */
KiAcquireDispatcherObject(&Gate->Header);
/* Check if it's already signaled */
if (Gate->Header.SignalState)
{
/* Unsignal it */
Gate->Header.SignalState = 0;
/* Release the gate and thread locks */
KiReleaseDispatcherObject(&Gate->Header);
KiReleaseThreadLock(Thread);
/* Release the gate lock */
if (Queue) KiReleaseDispatcherLockFromDpcLevel();
/* Release the APC lock and return */
KiReleaseApcLock(&ApcLock);
break;
}
/* Setup a Wait Block */
GateWaitBlock = &Thread->WaitBlock[0];
GateWaitBlock->Object = (PVOID)Gate;
GateWaitBlock->Thread = Thread;
/* Set the Thread Wait Data */
Thread->WaitMode = WaitMode;
Thread->WaitReason = WaitReason;
Thread->WaitIrql = ApcLock.OldIrql;
Thread->State = GateWait;
Thread->GateObject = Gate;
/* Insert into the Wait List */
InsertTailList(&Gate->Header.WaitListHead,
&GateWaitBlock->WaitListEntry);
/* Release the gate lock */
KiReleaseDispatcherObject(&Gate->Header);
/* Set swap busy */
KiSetThreadSwapBusy(Thread);
/* Release the thread lock */
KiReleaseThreadLock(Thread);
/* Check if we had a queue */
if (Queue)
{
/* Wake it up */
KiActivateWaiterQueue(Queue);
/* Release the dispatcher lock */
KiReleaseDispatcherLockFromDpcLevel();
}
/* Release the APC lock but stay at DPC level */
KiReleaseApcLockFromDpcLevel(&ApcLock);
/* Find a new thread to run */
Status = KiSwapThread(Thread, KeGetCurrentPrcb());
/* Make sure we weren't executing an APC */
if (Status == STATUS_SUCCESS) return;
}
} while (TRUE);
}
VOID
FASTCALL
KeSignalGateBoostPriority(IN PKGATE Gate)
{
PKTHREAD WaitThread;
PKWAIT_BLOCK WaitBlock;
KIRQL OldIrql;
ASSERT_GATE(Gate);
ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
/* Start entry loop */
for (;;)
{
/* Raise to synch level */
OldIrql = KeRaiseIrqlToSynchLevel();
/* Lock the gate */
KiAcquireDispatcherObject(&Gate->Header);
/* Make sure we're not already signaled or that the list is empty */
if (Gate->Header.SignalState) break;
/* Check if our wait list is empty */
if (IsListEmpty(&Gate->Header.WaitListHead))
{
/* It is, so signal the event */
Gate->Header.SignalState = 1;
break;
}
else
{
/* Get WaitBlock */
WaitBlock = CONTAINING_RECORD(Gate->Header.WaitListHead.Flink,
KWAIT_BLOCK,
WaitListEntry);
/* Get the Associated thread */
WaitThread = WaitBlock->Thread;
/* Check to see if the waiting thread is locked */
if (KiTryThreadLock(WaitThread))
{
/* Unlock the gate */
KiReleaseDispatcherObject(&Gate->Header);
/* Lower IRQL and loop again */
KeLowerIrql(OldIrql);
continue;
}
/* Remove it */
RemoveEntryList(&WaitBlock->WaitListEntry);
/* Clear wait status */
WaitThread->WaitStatus = STATUS_SUCCESS;
/* Set state and CPU */
WaitThread->State = DeferredReady;
WaitThread->DeferredProcessor = KeGetCurrentPrcb()->Number;
/* Release the gate lock */
KiReleaseDispatcherObject(&Gate->Header);
/* Release the thread lock */
KiReleaseThreadLock(WaitThread);
/* FIXME: Boosting */
/* Check if we have a queue */
if (WaitThread->Queue)
{
/* Acquire the dispatcher lock */
KiAcquireDispatcherLockAtDpcLevel();
/* Check if we still have one */
if (WaitThread->Queue)
{
/* Increment active threads */
WaitThread->Queue->CurrentCount++;
}
/* Release lock */
KiReleaseDispatcherLockFromDpcLevel();
}
/* Make the thread ready */
KiReadyThread(WaitThread);
/* Exit the dispatcher */
KiExitDispatcher(OldIrql);
return;
}
}
/* If we got here, then there's no rescheduling. */
KiReleaseDispatcherObject(&Gate->Header);
KeLowerIrql(OldIrql);
}
/* EOF */