Author: ion Date: Fri Jul 14 01:48:45 2006 New Revision: 23050
URL: http://svn.reactos.org/svn/reactos?rev=23050&view=rev Log: - Cleanup + formatting fixes for wait.c - Move some inlined functions from ke.h to ke_x.h - Add checks for special apc disabled (guarded regions) in wait code.
Modified: trunk/reactos/ntoskrnl/include/internal/ke.h trunk/reactos/ntoskrnl/include/internal/ke_x.h trunk/reactos/ntoskrnl/ke/wait.c
Modified: trunk/reactos/ntoskrnl/include/internal/ke.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/k... ============================================================================== --- trunk/reactos/ntoskrnl/include/internal/ke.h (original) +++ trunk/reactos/ntoskrnl/include/internal/ke.h Fri Jul 14 01:48:45 2006 @@ -79,99 +79,6 @@ InitializeListHead(&((Header)->WaitListHead)); \ }
-/* The following macro satisfies the wait of any dispatcher object */ -#define KiSatisfyObjectWait(Object, Thread) \ -{ \ - /* Special case for Mutants */ \ - if ((Object)->Header.Type == MutantObject) \ - { \ - /* Decrease the Signal State */ \ - (Object)->Header.SignalState--; \ - \ - /* Check if it's now non-signaled */ \ - if (!(Object)->Header.SignalState) \ - { \ - /* Set the Owner Thread */ \ - (Object)->OwnerThread = Thread; \ - \ - /* Disable APCs if needed */ \ - Thread->KernelApcDisable -= (Object)->ApcDisable; \ - \ - /* Check if it's abandoned */ \ - if ((Object)->Abandoned) \ - { \ - /* Unabandon it */ \ - (Object)->Abandoned = FALSE; \ - \ - /* Return Status */ \ - Thread->WaitStatus = STATUS_ABANDONED; \ - } \ - \ - /* Insert it into the Mutant List */ \ - InsertHeadList(&Thread->MutantListHead, \ - &(Object)->MutantListEntry); \ - } \ - } \ - else if (((Object)->Header.Type & TIMER_OR_EVENT_TYPE) == \ - EventSynchronizationObject) \ - { \ - /* Synchronization Timers and Events just get un-signaled */ \ - (Object)->Header.SignalState = 0; \ - } \ - else if ((Object)->Header.Type == SemaphoreObject) \ - { \ - /* These ones can have multiple states, so we only decrease it */ \ - (Object)->Header.SignalState--; \ - } \ -} - -/* The following macro satisfies the wait of a mutant dispatcher object */ -#define KiSatisfyMutantWait(Object, Thread) \ -{ \ - /* Decrease the Signal State */ \ - (Object)->Header.SignalState--; \ - \ - /* Check if it's now non-signaled */ \ - if (!(Object)->Header.SignalState) \ - { \ - /* Set the Owner Thread */ \ - (Object)->OwnerThread = Thread; \ - \ - /* Disable APCs if needed */ \ - Thread->KernelApcDisable -= (Object)->ApcDisable; \ - \ - /* Check if it's abandoned */ \ - if ((Object)->Abandoned) \ - { \ - /* Unabandon it */ \ - (Object)->Abandoned = FALSE; \ - \ - /* Return Status */ \ - Thread->WaitStatus = STATUS_ABANDONED; \ - } \ - \ - /* Insert it into the Mutant List */ \ - InsertHeadList(&Thread->MutantListHead, \ - &(Object)->MutantListEntry); \ - } \ -} - -/* The following macro satisfies the wait of any nonmutant dispatcher object */ -#define KiSatisfyNonMutantWait(Object, Thread) \ -{ \ - if (((Object)->Header.Type & TIMER_OR_EVENT_TYPE) == \ - EventSynchronizationObject) \ - { \ - /* Synchronization Timers and Events just get un-signaled */ \ - (Object)->Header.SignalState = 0; \ - } \ - else if ((Object)->Header.Type == SemaphoreObject) \ - { \ - /* These ones can have multiple states, so we only decrease it */ \ - (Object)->Header.SignalState--; \ - } \ -} - extern KSPIN_LOCK DispatcherDatabaseLock;
#define KeEnterCriticalRegion() \
Modified: trunk/reactos/ntoskrnl/include/internal/ke_x.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/k... ============================================================================== --- trunk/reactos/ntoskrnl/include/internal/ke_x.h (original) +++ trunk/reactos/ntoskrnl/include/internal/ke_x.h Fri Jul 14 01:48:45 2006 @@ -7,7 +7,7 @@ */
// -// Guarded Region Routines +// Enters a Critical Region // #define KeEnterGuardedRegion() \ { \ @@ -23,6 +23,9 @@ Thread->SpecialApcDisable--; \ }
+// +// Leaves a Critical Region +// #define KeLeaveGuardedRegion() \ { \ PKTHREAD Thread = KeGetCurrentThread(); \ @@ -54,6 +57,142 @@ //
// -// TODO: Wait Routines +// Satisfies the wait of any dispatcher object // +#define KiSatisfyObjectWait(Object, Thread) \ +{ \ + /* Special case for Mutants */ \ + if ((Object)->Header.Type == MutantObject) \ + { \ + /* Decrease the Signal State */ \ + (Object)->Header.SignalState--; \ + \ + /* Check if it's now non-signaled */ \ + if (!(Object)->Header.SignalState) \ + { \ + /* Set the Owner Thread */ \ + (Object)->OwnerThread = Thread; \ + \ + /* Disable APCs if needed */ \ + Thread->KernelApcDisable -= (Object)->ApcDisable; \ + \ + /* Check if it's abandoned */ \ + if ((Object)->Abandoned) \ + { \ + /* Unabandon it */ \ + (Object)->Abandoned = FALSE; \ + \ + /* Return Status */ \ + Thread->WaitStatus = STATUS_ABANDONED; \ + } \ + \ + /* Insert it into the Mutant List */ \ + InsertHeadList(&Thread->MutantListHead, \ + &(Object)->MutantListEntry); \ + } \ + } \ + else if (((Object)->Header.Type & TIMER_OR_EVENT_TYPE) == \ + EventSynchronizationObject) \ + { \ + /* Synchronization Timers and Events just get un-signaled */ \ + (Object)->Header.SignalState = 0; \ + } \ + else if ((Object)->Header.Type == SemaphoreObject) \ + { \ + /* These ones can have multiple states, so we only decrease it */ \ + (Object)->Header.SignalState--; \ + } \ +}
+// +// Satisfies the wait of a mutant dispatcher object +// +#define KiSatisfyMutantWait(Object, Thread) \ +{ \ + /* Decrease the Signal State */ \ + (Object)->Header.SignalState--; \ + \ + /* Check if it's now non-signaled */ \ + if (!(Object)->Header.SignalState) \ + { \ + /* Set the Owner Thread */ \ + (Object)->OwnerThread = Thread; \ + \ + /* Disable APCs if needed */ \ + Thread->KernelApcDisable -= (Object)->ApcDisable; \ + \ + /* Check if it's abandoned */ \ + if ((Object)->Abandoned) \ + { \ + /* Unabandon it */ \ + (Object)->Abandoned = FALSE; \ + \ + /* Return Status */ \ + Thread->WaitStatus = STATUS_ABANDONED; \ + } \ + \ + /* Insert it into the Mutant List */ \ + InsertHeadList(&Thread->MutantListHead, \ + &(Object)->MutantListEntry); \ + } \ +} + +// +// Satisfies the wait of any nonmutant dispatcher object +// +#define KiSatisfyNonMutantWait(Object, Thread) \ +{ \ + if (((Object)->Header.Type & TIMER_OR_EVENT_TYPE) == \ + EventSynchronizationObject) \ + { \ + /* Synchronization Timers and Events just get un-signaled */ \ + (Object)->Header.SignalState = 0; \ + } \ + else if ((Object)->Header.Type == SemaphoreObject) \ + { \ + /* These ones can have multiple states, so we only decrease it */ \ + (Object)->Header.SignalState--; \ + } \ +} + +// +// Rules for checking alertability: +// - For Alertable waits ONLY: +// * We don't wait and return STATUS_ALERTED if the thread is alerted +// in EITHER the specified wait mode OR in Kernel Mode. +// - For BOTH Alertable AND Non-Alertable waits: +// * We don't want and return STATUS_USER_APC if the User Mode APC list +// is not empty AND the wait mode is User Mode. +// +#define KiCheckAlertability() \ +{ \ + if (Alertable) \ + { \ + if (CurrentThread->Alerted[(int)WaitMode]) \ + { \ + CurrentThread->Alerted[(int)WaitMode] = FALSE; \ + WaitStatus = STATUS_ALERTED; \ + break; \ + } \ + else if ((WaitMode != KernelMode) && \ + (!IsListEmpty(&CurrentThread-> \ + ApcState.ApcListHead[UserMode]))) \ + { \ + CurrentThread->ApcState.UserApcPending = TRUE; \ + WaitStatus = STATUS_USER_APC; \ + break; \ + } \ + else if (CurrentThread->Alerted[KernelMode]) \ + { \ + CurrentThread->Alerted[KernelMode] = FALSE; \ + WaitStatus = STATUS_ALERTED; \ + break; \ + } \ + } \ + else if ((WaitMode != KernelMode) && \ + (CurrentThread->ApcState.UserApcPending)) \ + { \ + WaitStatus = STATUS_USER_APC; \ + break; \ + } \ +}
Modified: trunk/reactos/ntoskrnl/ke/wait.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/wait.c?rev=2305... ============================================================================== --- trunk/reactos/ntoskrnl/ke/wait.c (original) +++ trunk/reactos/ntoskrnl/ke/wait.c Fri Jul 14 01:48:45 2006 @@ -1,16 +1,15 @@ /* - * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory * FILE: ntoskrnl/ke/wait.c * PURPOSE: Manages waiting for Dispatcher Objects - * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) * Gunnar Dalsnes */
/* INCLUDES ******************************************************************/
#include <ntoskrnl.h> - #define NDEBUG #include <internal/debug.h>
@@ -19,47 +18,6 @@ KSPIN_LOCK DispatcherDatabaseLock;
/* PRIVATE FUNCTIONS *********************************************************/ - -/* - * Rules for checking alertability: - * - For Alertable waits ONLY: - * * We don't wait and return STATUS_ALERTED if the thread is alerted - * in EITHER the specified wait mode OR in Kernel Mode. - * - For BOTH Alertable AND Non-Alertable waits: - * * We don't want and return STATUS_USER_APC if the User Mode APC list - * is not empty AND the wait mode is User Mode. - */ -#define KiCheckAlertability() \ - if (Alertable) \ - { \ - if (CurrentThread->Alerted[(int)WaitMode]) \ - { \ - CurrentThread->Alerted[(int)WaitMode] = FALSE; \ - WaitStatus = STATUS_ALERTED; \ - break; \ - } \ - else if ((WaitMode != KernelMode) && \ - (!IsListEmpty(&CurrentThread->ApcState.ApcListHead[UserMode])))\ - { \ - CurrentThread->ApcState.UserApcPending = TRUE; \ - WaitStatus = STATUS_USER_APC; \ - break; \ - } \ - else if (CurrentThread->Alerted[KernelMode]) \ - { \ - CurrentThread->Alerted[KernelMode] = FALSE; \ - WaitStatus = STATUS_ALERTED; \ - break; \ - } \ - } \ - else if ((WaitMode != KernelMode) && \ - (CurrentThread->ApcState.UserApcPending)) \ - { \ - WaitStatus = STATUS_USER_APC; \ - break; \ - } \ - -/* PUBLIC FUNCTIONS **********************************************************/
VOID FASTCALL @@ -82,607 +40,6 @@ WaitBlock = WaitBlock->NextWaitBlock; } while (WaitBlock != FirstBlock); -} - -/* - * @implemented - * - * FUNCTION: Puts the current thread into an alertable or nonalertable - * wait state for a given internal - * ARGUMENTS: - * WaitMode = Processor mode in which the caller is waiting - * Altertable = Specifies if the wait is alertable - * Interval = Specifies the interval to wait - * RETURNS: Status - */ -NTSTATUS -STDCALL -KeDelayExecutionThread(KPROCESSOR_MODE WaitMode, - BOOLEAN Alertable, - PLARGE_INTEGER Interval) -{ - PKWAIT_BLOCK TimerWaitBlock; - PKTIMER ThreadTimer; - PKTHREAD CurrentThread = KeGetCurrentThread(); - NTSTATUS WaitStatus = STATUS_SUCCESS; - DPRINT("Entering KeDelayExecutionThread\n"); - - /* Check if the lock is already held */ - if (CurrentThread->WaitNext) - { - /* Lock is held, disable Wait Next */ - DPRINT("Lock is held\n"); - CurrentThread->WaitNext = FALSE; - } - else - { - /* Lock not held, acquire it */ - DPRINT("Lock is not held, acquiring\n"); - CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock(); - } - - /* Use built-in Wait block */ - TimerWaitBlock = &CurrentThread->WaitBlock[TIMER_WAIT_BLOCK]; - - /* Start Wait Loop */ - do - { - /* Check if a kernel APC is pending and we were below APC_LEVEL */ - if ((CurrentThread->ApcState.KernelApcPending) && - (CurrentThread->WaitIrql < APC_LEVEL)) - { - /* Unlock the dispatcher */ - KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql); - goto SkipWait; - } - - /* Check if we can do an alertable wait, if requested */ - KiCheckAlertability(); - - /* Set status */ - CurrentThread->WaitStatus = STATUS_WAIT_0; - - /* Set Timer */ - ThreadTimer = &CurrentThread->Timer; - - /* Setup the Wait Block */ - CurrentThread->WaitBlockList = TimerWaitBlock; - TimerWaitBlock->NextWaitBlock = TimerWaitBlock; - - /* Link the timer to this Wait Block */ - ThreadTimer->Header.WaitListHead.Flink = &TimerWaitBlock->WaitListEntry; - ThreadTimer->Header.WaitListHead.Blink = &TimerWaitBlock->WaitListEntry; - - /* Insert the Timer into the Timer Lists and enable it */ - if (!KiInsertTimer(ThreadTimer, *Interval)) - { - /* FIXME: The timer already expired, we should find a new ready thread */ - WaitStatus = STATUS_SUCCESS; - break; - } - - /* Handle Kernel Queues */ - if (CurrentThread->Queue) - { - DPRINT("Waking Queue\n"); - KiWakeQueue(CurrentThread->Queue); - } - - /* Setup the wait information */ - CurrentThread->Alertable = Alertable; - CurrentThread->WaitMode = WaitMode; - CurrentThread->WaitReason = DelayExecution; - CurrentThread->WaitTime = ((PLARGE_INTEGER)&KeTickCount)->LowPart; - CurrentThread->State = Waiting; - - /* Find a new thread to run */ - DPRINT("Swapping threads\n"); - WaitStatus = KiSwapThread(); - - /* Check if we were executing an APC or if we timed out */ - if (WaitStatus != STATUS_KERNEL_APC) - { - /* This is a good thing */ - if (WaitStatus == STATUS_TIMEOUT) WaitStatus = STATUS_SUCCESS; - - /* Return Status */ - return WaitStatus; - } - - /* FIXME: Fixup interval */ - - /* Acquire again the lock */ -SkipWait: - DPRINT("Looping again\n"); - CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock(); - } - while (TRUE); - - /* Release the Lock, we are done */ - DPRINT("Returning from KeDelayExecutionThread(), %x. Status: %d\n", - KeGetCurrentThread(), Status); - KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql); - return WaitStatus; -} - -/* - * @implemented - * - * FUNCTION: Puts the current thread into a wait state until the - * given dispatcher object is set to signalled - * ARGUMENTS: - * Object = Object to wait on - * WaitReason = Reason for the wait (debugging aid) - * WaitMode = Can be KernelMode or UserMode, if UserMode then - * user-mode APCs can be delivered and the thread's - * stack can be paged out - * Altertable = Specifies if the wait is a alertable - * Timeout = Optional timeout value - * RETURNS: Status - */ -NTSTATUS -STDCALL -KeWaitForSingleObject(PVOID Object, - KWAIT_REASON WaitReason, - KPROCESSOR_MODE WaitMode, - BOOLEAN Alertable, - PLARGE_INTEGER Timeout) -{ - PKMUTANT CurrentObject; - PKWAIT_BLOCK WaitBlock; - PKWAIT_BLOCK TimerWaitBlock; - PKTIMER ThreadTimer; - PKTHREAD CurrentThread = KeGetCurrentThread(); - NTSTATUS WaitStatus = STATUS_SUCCESS; - DPRINT("Entering KeWaitForSingleObject\n"); - - /* Check if the lock is already held */ - if (CurrentThread->WaitNext) - { - /* Lock is held, disable Wait Next */ - DPRINT("Lock is held\n"); - CurrentThread->WaitNext = FALSE; - } - else - { - /* Lock not held, acquire it */ - DPRINT("Lock is not held, acquiring\n"); - CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock(); - } - - /* Start the actual Loop */ - do - { - /* Check if a kernel APC is pending and we were below APC_LEVEL */ - if ((CurrentThread->ApcState.KernelApcPending) && - (CurrentThread->WaitIrql < APC_LEVEL)) - { - /* Unlock the dispatcher */ - KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql); - goto SkipWait; - } - - /* Set default status */ - CurrentThread->WaitStatus = STATUS_WAIT_0; - - /* Append wait block to the KTHREAD wait block list */ - CurrentThread->WaitBlockList = WaitBlock = &CurrentThread->WaitBlock[0]; - - /* Get the Current Object */ - CurrentObject = (PKMUTANT)Object; - - /* Check if it's a mutant */ - if (CurrentObject->Header.Type == MutantObject) - { - /* Check its signal state or if we own it */ - if ((CurrentObject->Header.SignalState > 0) || - (CurrentThread == CurrentObject->OwnerThread)) - { - /* Just unwait this guy and exit */ - if (CurrentObject->Header.SignalState != (LONG)MINLONG) - { - /* It has a normal signal state, so unwait it and return */ - KiSatisfyMutantWait(CurrentObject, CurrentThread); - WaitStatus = CurrentThread->WaitStatus; - goto DontWait; - } - else - { - /* According to wasm.ru, we must raise this exception (tested and true) */ - KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql); - ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED); - } - } - } - else if (CurrentObject->Header.SignalState > 0) - { - /* Another satisfied object */ - KiSatisfyNonMutantWait(CurrentObject, CurrentThread); - WaitStatus = STATUS_WAIT_0; - goto DontWait; - } - - /* Set up the Wait Block */ - WaitBlock->Object = CurrentObject; - WaitBlock->Thread = CurrentThread; - WaitBlock->WaitKey = (USHORT)(STATUS_SUCCESS); - WaitBlock->WaitType = WaitAny; - WaitBlock->NextWaitBlock = WaitBlock; - - /* Make sure we can satisfy the Alertable request */ - KiCheckAlertability(); - - /* Enable the Timeout Timer if there was any specified */ - if (Timeout) - { - /* Fail if the timeout interval is actually 0 */ - if (!Timeout->QuadPart) - { - /* Return a timeout */ - WaitStatus = STATUS_TIMEOUT; - goto DontWait; - } - - /* Point to Timer Wait Block and Thread Timer */ - TimerWaitBlock = &CurrentThread->WaitBlock[TIMER_WAIT_BLOCK]; - ThreadTimer = &CurrentThread->Timer; - - /* Connect the Timer Wait Block */ - WaitBlock->NextWaitBlock = TimerWaitBlock; - - /* Set up the Timer Wait Block */ - TimerWaitBlock->NextWaitBlock = WaitBlock; - - /* Link the timer to this Wait Block */ - ThreadTimer->Header.WaitListHead.Flink = &TimerWaitBlock->WaitListEntry; - ThreadTimer->Header.WaitListHead.Blink = &TimerWaitBlock->WaitListEntry; - - /* Insert the Timer into the Timer Lists and enable it */ - if (!KiInsertTimer(ThreadTimer, *Timeout)) - { - /* Return a timeout if we couldn't insert the timer */ - WaitStatus = STATUS_TIMEOUT; - goto DontWait; - } - } - - /* Link the Object to this Wait Block */ - InsertTailList(&CurrentObject->Header.WaitListHead, - &WaitBlock->WaitListEntry); - - /* Handle Kernel Queues */ - if (CurrentThread->Queue) - { - DPRINT("Waking Queue\n"); - KiWakeQueue(CurrentThread->Queue); - } - - /* Setup the wait information */ - CurrentThread->Alertable = Alertable; - CurrentThread->WaitMode = WaitMode; - CurrentThread->WaitReason = WaitReason; - CurrentThread->WaitTime = ((PLARGE_INTEGER)&KeTickCount)->LowPart; - CurrentThread->State = Waiting; - - /* Find a new thread to run */ - DPRINT("Swapping threads\n"); - WaitStatus = KiSwapThread(); - - /* Check if we were executing an APC */ - if (WaitStatus != STATUS_KERNEL_APC) - { - /* Return Status */ - return WaitStatus; - } - - /* Check if we had a timeout */ - if (Timeout) - { - /* FIXME: Fixup interval */ - } - - /* Acquire again the lock */ -SkipWait: - DPRINT("Looping again\n"); - CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock(); - } - while (TRUE); - - /* Release the Lock, we are done */ - DPRINT("Returning from KeWaitForMultipleObjects(), %x. Status: %d\n", - KeGetCurrentThread(), WaitStatus); - KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql); - return WaitStatus; - -DontWait: - /* Adjust the Quantum */ - KiAdjustQuantumThread(CurrentThread); - - /* Release & Return */ - DPRINT("Quick-return from KeWaitForMultipleObjects(), %x. Status: %d\n.", - KeGetCurrentThread(), WaitStatus); - KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql); - return WaitStatus; -} - -/* - * @implemented - */ -NTSTATUS -STDCALL -KeWaitForMultipleObjects(ULONG Count, - PVOID Object[], - WAIT_TYPE WaitType, - KWAIT_REASON WaitReason, - KPROCESSOR_MODE WaitMode, - BOOLEAN Alertable, - PLARGE_INTEGER Timeout, - PKWAIT_BLOCK WaitBlockArray) -{ - PKMUTANT CurrentObject; - PKWAIT_BLOCK WaitBlock; - PKWAIT_BLOCK TimerWaitBlock; - PKTIMER ThreadTimer; - PKTHREAD CurrentThread = KeGetCurrentThread(); - ULONG AllObjectsSignaled; - ULONG WaitIndex; - NTSTATUS WaitStatus = STATUS_SUCCESS; - DPRINT("Entering KeWaitForMultipleObjects(Count %lu Object[] %p) " - "PsGetCurrentThread() %x, Timeout %x\n", - Count, Object, PsGetCurrentThread(), Timeout); - - /* Set the Current Thread */ - CurrentThread = KeGetCurrentThread(); - - /* Check if the lock is already held */ - if (CurrentThread->WaitNext) - { - /* Lock is held, disable Wait Next */ - DPRINT("Lock is held\n"); - CurrentThread->WaitNext = FALSE; - } - else - { - /* Lock not held, acquire it */ - DPRINT("Lock is not held, acquiring\n"); - CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock(); - } - - /* Make sure the Wait Count is valid for the Thread and Maximum Wait Objects */ - if (!WaitBlockArray) - { - /* Check in regards to the Thread Object Limit */ - if (Count > THREAD_WAIT_OBJECTS) KEBUGCHECK(MAXIMUM_WAIT_OBJECTS_EXCEEDED); - - /* Use the Thread's Wait Block */ - WaitBlockArray = &CurrentThread->WaitBlock[0]; - } - else - { - /* Using our own Block Array. Check in regards to System Object Limit */ - if (Count > MAXIMUM_WAIT_OBJECTS) KEBUGCHECK(MAXIMUM_WAIT_OBJECTS_EXCEEDED); - } - - /* Start the actual Loop */ - do - { - /* Check if a kernel APC is pending and we were below APC_LEVEL */ - if ((CurrentThread->ApcState.KernelApcPending) && - (CurrentThread->WaitIrql < APC_LEVEL)) - { - /* Unlock the dispatcher */ - KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql); - goto SkipWait; - } - - /* Append wait block to the KTHREAD wait block list */ - CurrentThread->WaitBlockList = WaitBlock = WaitBlockArray; - - /* Set default wait status */ - CurrentThread->WaitStatus = STATUS_WAIT_0; - - /* Check if the wait is (already) satisfied */ - AllObjectsSignaled = TRUE; - - /* First, we'll try to satisfy the wait directly */ - for (WaitIndex = 0; WaitIndex < Count; WaitIndex++) - { - /* Get the Current Object */ - CurrentObject = (PKMUTANT)Object[WaitIndex]; - - /* Check the type of wait */ - if (WaitType == WaitAny) - { - /* Check if the Object is a mutant */ - if (CurrentObject->Header.Type == MutantObject) - { - /* Check if it's signaled */ - if ((CurrentObject->Header.SignalState > 0) || - (CurrentThread == CurrentObject->OwnerThread)) - { - /* This is a Wait Any, so just unwait this and exit */ - if (CurrentObject->Header.SignalState != (LONG)MINLONG) - { - /* Normal signal state, so unwait it and return */ - KiSatisfyMutantWait(CurrentObject, CurrentThread); - WaitStatus = CurrentThread->WaitStatus | WaitIndex; - goto DontWait; - } - else - { - /* According to wasm.ru, we must raise this exception (tested and true) */ - KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql); - ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED); - } - } - } - else if (CurrentObject->Header.SignalState > 0) - { - /* Another signaled object, unwait and return */ - KiSatisfyNonMutantWait(CurrentObject, CurrentThread); - WaitStatus = WaitIndex; - goto DontWait; - } - } - else - { - /* Check if we're dealing with a mutant again */ - if (CurrentObject->Header.Type == MutantObject) - { - /* Check if it has an invalid count */ - if ((CurrentThread == CurrentObject->OwnerThread) && - (CurrentObject->Header.SignalState == MINLONG)) - { - /* Raise an exception */ - KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql); - ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED); - } - else if ((CurrentObject->Header.SignalState <= 0) && - (CurrentThread != CurrentObject->OwnerThread)) - { - /* We don't own it, can't satisfy the wait */ - AllObjectsSignaled = FALSE; - } - } - else if (CurrentObject->Header.SignalState <= 0) - { - /* Not signaled, can't satisfy */ - AllObjectsSignaled = FALSE; - } - } - - /* Set up a Wait Block for this Object */ - WaitBlock->Object = CurrentObject; - WaitBlock->Thread = CurrentThread; - WaitBlock->WaitKey = (USHORT)WaitIndex; - WaitBlock->WaitType = (USHORT)WaitType; - WaitBlock->NextWaitBlock = WaitBlock + 1; - - /* Move to the next Wait Block */ - WaitBlock = WaitBlock->NextWaitBlock; - } - - /* Return to the Root Wait Block */ - WaitBlock--; - WaitBlock->NextWaitBlock = WaitBlockArray; - - /* Check if this is a Wait All and all the objects are signaled */ - if ((WaitType == WaitAll) && (AllObjectsSignaled)) - { - /* Return to the Root Wait Block */ - WaitBlock = CurrentThread->WaitBlockList; - - /* Satisfy their Waits and return to the caller */ - KiWaitSatisfyAll(WaitBlock); - WaitStatus = CurrentThread->WaitStatus; - goto DontWait; - } - - /* Make sure we can satisfy the Alertable request */ - KiCheckAlertability(); - - /* Enable the Timeout Timer if there was any specified */ - if (Timeout) - { - /* Make sure the timeout interval isn't actually 0 */ - if (!Timeout->QuadPart) - { - /* Return a timeout */ - WaitStatus = STATUS_TIMEOUT; - goto DontWait; - } - - /* Point to Timer Wait Block and Thread Timer */ - TimerWaitBlock = &CurrentThread->WaitBlock[TIMER_WAIT_BLOCK]; - ThreadTimer = &CurrentThread->Timer; - - /* Connect the Timer Wait Block */ - WaitBlock->NextWaitBlock = TimerWaitBlock; - - /* Set up the Timer Wait Block */ - TimerWaitBlock->NextWaitBlock = WaitBlockArray; - - /* Initialize the list head */ - InitializeListHead(&ThreadTimer->Header.WaitListHead); - - /* Insert the Timer into the Timer Lists and enable it */ - if (!KiInsertTimer(ThreadTimer, *Timeout)) - { - /* Return a timeout if we couldn't insert the timer */ - WaitStatus = STATUS_TIMEOUT; - goto DontWait; - } - } - - /* Insert into Object's Wait List*/ - WaitBlock = CurrentThread->WaitBlockList; - do - { - /* Get the Current Object */ - CurrentObject = WaitBlock->Object; - - /* Link the Object to this Wait Block */ - InsertTailList(&CurrentObject->Header.WaitListHead, - &WaitBlock->WaitListEntry); - - /* Move to the next Wait Block */ - WaitBlock = WaitBlock->NextWaitBlock; - } - while (WaitBlock != WaitBlockArray); - - /* Handle Kernel Queues */ - if (CurrentThread->Queue) - { - DPRINT("Waking Queue\n"); - KiWakeQueue(CurrentThread->Queue); - } - - /* Setup the wait information */ - CurrentThread->Alertable = Alertable; - CurrentThread->WaitMode = WaitMode; - CurrentThread->WaitReason = WaitReason; - CurrentThread->WaitTime = ((PLARGE_INTEGER)&KeTickCount)->LowPart; - CurrentThread->State = Waiting; - - /* Find a new thread to run */ - DPRINT("Swapping threads\n"); - WaitStatus = KiSwapThread(); - - /* Check if we were executing an APC */ - DPRINT("Thread is back\n"); - if (WaitStatus != STATUS_KERNEL_APC) - { - /* Return Status */ - return WaitStatus; - } - - /* Check if we had a timeout */ - if (Timeout) - { - /* FIXME: Fixup interval */ - } - - /* Acquire again the lock */ -SkipWait: - DPRINT("Looping again\n"); - CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock(); - } - while (TRUE); - - /* Release the Lock, we are done */ - DPRINT("Returning, %x. Status: %d\n", KeGetCurrentThread(), WaitStatus); - KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql); - return WaitStatus; - -DontWait: - /* Adjust the Quantum */ - KiAdjustQuantumThread(CurrentThread); - - /* Release & Return */ - DPRINT("Returning, %x. Status: %d\n. We did not wait.", - KeGetCurrentThread(), WaitStatus); - KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql); - return WaitStatus; }
VOID @@ -852,4 +209,561 @@ KeLowerIrql(OldIrql); }
+/* PUBLIC FUNCTIONS **********************************************************/ + +/* + * @implemented + */ +NTSTATUS +NTAPI +KeDelayExecutionThread(IN KPROCESSOR_MODE WaitMode, + IN BOOLEAN Alertable, + IN PLARGE_INTEGER Interval OPTIONAL) +{ + PKWAIT_BLOCK TimerWaitBlock; + PKTIMER ThreadTimer; + PKTHREAD CurrentThread = KeGetCurrentThread(); + NTSTATUS WaitStatus = STATUS_SUCCESS; + + /* Check if the lock is already held */ + if (CurrentThread->WaitNext) + { + /* Lock is held, disable Wait Next */ + CurrentThread->WaitNext = FALSE; + } + else + { + /* Lock not held, acquire it */ + CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock(); + } + + /* Use built-in Wait block */ + TimerWaitBlock = &CurrentThread->WaitBlock[TIMER_WAIT_BLOCK]; + + /* Start Wait Loop */ + do + { + /* Check if a kernel APC is pending and we're below APC_LEVEL */ + if ((CurrentThread->ApcState.KernelApcPending) && + !(CurrentThread->SpecialApcDisable) && + (CurrentThread->WaitIrql < APC_LEVEL)) + { + /* Unlock the dispatcher */ + KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql); + } + else + { + /* Check if we can do an alertable wait, if requested */ + KiCheckAlertability(); + + /* Set status */ + CurrentThread->WaitStatus = STATUS_WAIT_0; + + /* Set Timer */ + ThreadTimer = &CurrentThread->Timer; + + /* Setup the Wait Block */ + CurrentThread->WaitBlockList = TimerWaitBlock; + TimerWaitBlock->NextWaitBlock = TimerWaitBlock; + + /* Link the timer to this Wait Block */ + ThreadTimer->Header.WaitListHead.Flink = + &TimerWaitBlock->WaitListEntry; + ThreadTimer->Header.WaitListHead.Blink = + &TimerWaitBlock->WaitListEntry; + + /* Insert the Timer into the Timer Lists and enable it */ + if (!KiInsertTimer(ThreadTimer, *Interval)) + { + /* FIXME: We should find a new ready thread */ + WaitStatus = STATUS_SUCCESS; + break; + } + + /* Handle Kernel Queues */ + if (CurrentThread->Queue) KiWakeQueue(CurrentThread->Queue); + + /* Setup the wait information */ + CurrentThread->Alertable = Alertable; + CurrentThread->WaitMode = WaitMode; + CurrentThread->WaitReason = DelayExecution; + CurrentThread->WaitTime = ((PLARGE_INTEGER)&KeTickCount)->LowPart; + CurrentThread->State = Waiting; + + /* Find a new thread to run */ + WaitStatus = KiSwapThread(); + ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); + + /* Check if we were executing an APC or if we timed out */ + if (WaitStatus != STATUS_KERNEL_APC) + { + /* This is a good thing */ + if (WaitStatus == STATUS_TIMEOUT) WaitStatus = STATUS_SUCCESS; + + /* Return Status */ + return WaitStatus; + } + + /* FIXME: Fixup interval */ + } + + /* Acquire again the lock */ + CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock(); + } while (TRUE); + + /* Release the Lock, we are done */ + KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql); + return WaitStatus; +} + +/* + * @implemented + */ +NTSTATUS +NTAPI +KeWaitForSingleObject(PVOID Object, + KWAIT_REASON WaitReason, + KPROCESSOR_MODE WaitMode, + BOOLEAN Alertable, + PLARGE_INTEGER Timeout) +{ + PKMUTANT CurrentObject; + PKWAIT_BLOCK WaitBlock; + PKWAIT_BLOCK TimerWaitBlock; + PKTIMER ThreadTimer; + PKTHREAD CurrentThread = KeGetCurrentThread(); + NTSTATUS WaitStatus = STATUS_SUCCESS; + + /* Check if the lock is already held */ + if (CurrentThread->WaitNext) + { + /* Lock is held, disable Wait Next */ + CurrentThread->WaitNext = FALSE; + } + else + { + /* Lock not held, acquire it */ + CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock(); + } + + /* Start the actual Loop */ + do + { + /* Check if a kernel APC is pending and we're below APC_LEVEL */ + if ((CurrentThread->ApcState.KernelApcPending) && + !(CurrentThread->SpecialApcDisable) && + (CurrentThread->WaitIrql < APC_LEVEL)) + { + /* Unlock the dispatcher */ + KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql); + } + else + { + /* Set default status */ + CurrentThread->WaitStatus = STATUS_WAIT_0; + + /* Append wait block to the KTHREAD wait block list */ + WaitBlock = &CurrentThread->WaitBlock[0]; + CurrentThread->WaitBlockList = WaitBlock; + + /* Get the Current Object */ + CurrentObject = (PKMUTANT)Object; + + /* Check if it's a mutant */ + if (CurrentObject->Header.Type == MutantObject) + { + /* Check its signal state or if we own it */ + if ((CurrentObject->Header.SignalState > 0) || + (CurrentThread == CurrentObject->OwnerThread)) + { + /* Just unwait this guy and exit */ + if (CurrentObject->Header.SignalState != (LONG)MINLONG) + { + /* It has a normal signal state. Unwait and return */ + KiSatisfyMutantWait(CurrentObject, CurrentThread); + WaitStatus = CurrentThread->WaitStatus; + goto DontWait; + } + else + { + /* Raise an exception (see wasm.ru) */ + KeReleaseDispatcherDatabaseLock(CurrentThread-> + WaitIrql); + ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED); + } + } + } + else if (CurrentObject->Header.SignalState > 0) + { + /* Another satisfied object */ + KiSatisfyNonMutantWait(CurrentObject, CurrentThread); + WaitStatus = STATUS_WAIT_0; + goto DontWait; + } + + /* Set up the Wait Block */ + WaitBlock->Object = CurrentObject; + WaitBlock->Thread = CurrentThread; + WaitBlock->WaitKey = (USHORT)(STATUS_SUCCESS); + WaitBlock->WaitType = WaitAny; + WaitBlock->NextWaitBlock = WaitBlock; + + /* Make sure we can satisfy the Alertable request */ + KiCheckAlertability(); + + /* Enable the Timeout Timer if there was any specified */ + if (Timeout) + { + /* Fail if the timeout interval is actually 0 */ + if (!Timeout->QuadPart) + { + /* Return a timeout */ + WaitStatus = STATUS_TIMEOUT; + goto DontWait; + } + + /* Point to Timer Wait Block and Thread Timer */ + TimerWaitBlock = &CurrentThread->WaitBlock[TIMER_WAIT_BLOCK]; + ThreadTimer = &CurrentThread->Timer; + + /* Connect the Timer Wait Block */ + WaitBlock->NextWaitBlock = TimerWaitBlock; + + /* Set up the Timer Wait Block */ + TimerWaitBlock->NextWaitBlock = WaitBlock; + + /* Link the timer to this Wait Block */ + ThreadTimer->Header.WaitListHead.Flink = + &TimerWaitBlock->WaitListEntry; + ThreadTimer->Header.WaitListHead.Blink = + &TimerWaitBlock->WaitListEntry; + + /* Insert the Timer into the Timer Lists and enable it */ + if (!KiInsertTimer(ThreadTimer, *Timeout)) + { + /* Return a timeout if we couldn't insert the timer */ + WaitStatus = STATUS_TIMEOUT; + goto DontWait; + } + } + + /* Link the Object to this Wait Block */ + InsertTailList(&CurrentObject->Header.WaitListHead, + &WaitBlock->WaitListEntry); + + /* Handle Kernel Queues */ + if (CurrentThread->Queue) KiWakeQueue(CurrentThread->Queue); + + /* Setup the wait information */ + CurrentThread->Alertable = Alertable; + CurrentThread->WaitMode = WaitMode; + CurrentThread->WaitReason = WaitReason; + CurrentThread->WaitTime = ((PLARGE_INTEGER)&KeTickCount)->LowPart; + CurrentThread->State = Waiting; + + /* Find a new thread to run */ + WaitStatus = KiSwapThread(); + ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); + + /* Check if we were executing an APC */ + if (WaitStatus != STATUS_KERNEL_APC) return WaitStatus; + + /* Check if we had a timeout */ + if (Timeout) + { + /* FIXME: Fixup interval */ + } + } + + /* Acquire again the lock */ + CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock(); + } while (TRUE); + + /* Release the Lock, we are done */ + KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql); + return WaitStatus; + +DontWait: + /* Adjust the Quantum */ + KiAdjustQuantumThread(CurrentThread); + + /* Release & Return */ + KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql); + return WaitStatus; +} + +/* + * @implemented + */ +NTSTATUS +NTAPI +KeWaitForMultipleObjects(IN ULONG Count, + IN PVOID Object[], + IN WAIT_TYPE WaitType, + IN KWAIT_REASON WaitReason, + IN KPROCESSOR_MODE WaitMode, + IN BOOLEAN Alertable, + IN PLARGE_INTEGER Timeout OPTIONAL, + OUT PKWAIT_BLOCK WaitBlockArray OPTIONAL) +{ + PKMUTANT CurrentObject; + PKWAIT_BLOCK WaitBlock; + PKWAIT_BLOCK TimerWaitBlock; + PKTIMER ThreadTimer; + PKTHREAD CurrentThread = KeGetCurrentThread(); + ULONG AllObjectsSignaled; + ULONG WaitIndex; + NTSTATUS WaitStatus = STATUS_SUCCESS; + + /* Set the Current Thread */ + CurrentThread = KeGetCurrentThread(); + + /* Check if the lock is already held */ + if (CurrentThread->WaitNext) + { + /* Lock is held, disable Wait Next */ + CurrentThread->WaitNext = FALSE; + } + else + { + /* Lock not held, acquire it */ + CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock(); + } + + /* Make sure the Wait Count is valid */ + if (!WaitBlockArray) + { + /* Check in regards to the Thread Object Limit */ + if (Count > THREAD_WAIT_OBJECTS) + { + /* Bugcheck */ + KEBUGCHECK(MAXIMUM_WAIT_OBJECTS_EXCEEDED); + } + + /* Use the Thread's Wait Block */ + WaitBlockArray = &CurrentThread->WaitBlock[0]; + } + else + { + /* Using our own Block Array, so check with the System Object Limit */ + if (Count > MAXIMUM_WAIT_OBJECTS) + { + /* Bugcheck */ + KEBUGCHECK(MAXIMUM_WAIT_OBJECTS_EXCEEDED); + } + } + + /* Start the actual Loop */ + do + { + /* Check if a kernel APC is pending and we're below APC_LEVEL */ + if ((CurrentThread->ApcState.KernelApcPending) && + !(CurrentThread->SpecialApcDisable) && + (CurrentThread->WaitIrql < APC_LEVEL)) + { + /* Unlock the dispatcher */ + KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql); + } + else + { + /* Append wait block to the KTHREAD wait block list */ + CurrentThread->WaitBlockList = WaitBlock = WaitBlockArray; + + /* Set default wait status */ + CurrentThread->WaitStatus = STATUS_WAIT_0; + + /* Check if the wait is (already) satisfied */ + AllObjectsSignaled = TRUE; + + /* First, we'll try to satisfy the wait directly */ + for (WaitIndex = 0; WaitIndex < Count; WaitIndex++) + { + /* Get the Current Object */ + CurrentObject = (PKMUTANT)Object[WaitIndex]; + + /* Check the type of wait */ + if (WaitType == WaitAny) + { + /* Check if the Object is a mutant */ + if (CurrentObject->Header.Type == MutantObject) + { + /* Check if it's signaled */ + if ((CurrentObject->Header.SignalState > 0) || + (CurrentThread == CurrentObject->OwnerThread)) + { + /* This is a Wait Any, so unwait this and exit */ + if (CurrentObject->Header.SignalState != + (LONG)MINLONG) + { + /* Normal signal state, unwait it and return */ + KiSatisfyMutantWait(CurrentObject, + CurrentThread); + WaitStatus = CurrentThread->WaitStatus | + WaitIndex; + goto DontWait; + } + else + { + /* Raise an exception (see wasm.ru) */ + KeReleaseDispatcherDatabaseLock(CurrentThread-> + WaitIrql); + ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED); + } + } + } + else if (CurrentObject->Header.SignalState > 0) + { + /* Another signaled object, unwait and return */ + KiSatisfyNonMutantWait(CurrentObject, CurrentThread); + WaitStatus = WaitIndex; + goto DontWait; + } + } + else + { + /* Check if we're dealing with a mutant again */ + if (CurrentObject->Header.Type == MutantObject) + { + /* Check if it has an invalid count */ + if ((CurrentThread == CurrentObject->OwnerThread) && + (CurrentObject->Header.SignalState == MINLONG)) + { + /* Raise an exception */ + KeReleaseDispatcherDatabaseLock(CurrentThread-> + WaitIrql); + ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED); + } + else if ((CurrentObject->Header.SignalState <= 0) && + (CurrentThread != CurrentObject->OwnerThread)) + { + /* We don't own it, can't satisfy the wait */ + AllObjectsSignaled = FALSE; + } + } + else if (CurrentObject->Header.SignalState <= 0) + { + /* Not signaled, can't satisfy */ + AllObjectsSignaled = FALSE; + } + } + + /* Set up a Wait Block for this Object */ + WaitBlock->Object = CurrentObject; + WaitBlock->Thread = CurrentThread; + WaitBlock->WaitKey = (USHORT)WaitIndex; + WaitBlock->WaitType = (USHORT)WaitType; + WaitBlock->NextWaitBlock = WaitBlock + 1; + + /* Move to the next Wait Block */ + WaitBlock = WaitBlock->NextWaitBlock; + } + + /* Return to the Root Wait Block */ + WaitBlock--; + WaitBlock->NextWaitBlock = WaitBlockArray; + + /* Check if this is a Wait All and all the objects are signaled */ + if ((WaitType == WaitAll) && (AllObjectsSignaled)) + { + /* Return to the Root Wait Block */ + WaitBlock = CurrentThread->WaitBlockList; + + /* Satisfy their Waits and return to the caller */ + KiWaitSatisfyAll(WaitBlock); + WaitStatus = CurrentThread->WaitStatus; + goto DontWait; + } + + /* Make sure we can satisfy the Alertable request */ + KiCheckAlertability(); + + /* Enable the Timeout Timer if there was any specified */ + if (Timeout) + { + /* Make sure the timeout interval isn't actually 0 */ + if (!Timeout->QuadPart) + { + /* Return a timeout */ + WaitStatus = STATUS_TIMEOUT; + goto DontWait; + } + + /* Point to Timer Wait Block and Thread Timer */ + TimerWaitBlock = &CurrentThread->WaitBlock[TIMER_WAIT_BLOCK]; + ThreadTimer = &CurrentThread->Timer; + + /* Connect the Timer Wait Block */ + WaitBlock->NextWaitBlock = TimerWaitBlock; + + /* Set up the Timer Wait Block */ + TimerWaitBlock->NextWaitBlock = WaitBlockArray; + + /* Initialize the list head */ + InitializeListHead(&ThreadTimer->Header.WaitListHead); + + /* Insert the Timer into the Timer Lists and enable it */ + if (!KiInsertTimer(ThreadTimer, *Timeout)) + { + /* Return a timeout if we couldn't insert the timer */ + WaitStatus = STATUS_TIMEOUT; + goto DontWait; + } + } + + /* Insert into Object's Wait List*/ + WaitBlock = CurrentThread->WaitBlockList; + do + { + /* Get the Current Object */ + CurrentObject = WaitBlock->Object; + + /* Link the Object to this Wait Block */ + InsertTailList(&CurrentObject->Header.WaitListHead, + &WaitBlock->WaitListEntry); + + /* Move to the next Wait Block */ + WaitBlock = WaitBlock->NextWaitBlock; + } while (WaitBlock != WaitBlockArray); + + /* Handle Kernel Queues */ + if (CurrentThread->Queue) KiWakeQueue(CurrentThread->Queue); + + /* Setup the wait information */ + CurrentThread->Alertable = Alertable; + CurrentThread->WaitMode = WaitMode; + CurrentThread->WaitReason = WaitReason; + CurrentThread->WaitTime = ((PLARGE_INTEGER)&KeTickCount)->LowPart; + CurrentThread->State = Waiting; + + /* Find a new thread to run */ + WaitStatus = KiSwapThread(); + ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); + + /* Check if we were executing an APC */ + if (WaitStatus != STATUS_KERNEL_APC) return WaitStatus; + + /* Check if we had a timeout */ + if (Timeout) + { + /* FIXME: Fixup interval */ + } + + /* Acquire again the lock */ + CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock(); + } + } while (TRUE); + + /* Release the Lock, we are done */ + KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql); + return WaitStatus; + +DontWait: + /* Adjust the Quantum */ + KiAdjustQuantumThread(CurrentThread); + + /* Release & Return */ + KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql); + return WaitStatus; +} + /* EOF */