From 1b75e6549e407e44c3a58e88c73c1da95b77d1cb Mon Sep 17 00:00:00 2001 From: Alex Ionescu Date: Thu, 14 Sep 2006 15:48:02 +0000 Subject: [PATCH] - Converted some macros to inlined functions. - Modified KeDelayExecutionThread and KeWaitForSingleObject to be much simpler and readable, reducing some of the loops and continues, and 4th-level indentation. Also packed up common wait initialization at the beginning of the function, and into two new inline functions: KxDelayThreadWait and KxSingleThreadWait. No actual semantic changes, just re-ordering. - Rename KiUnwakeQueue to KiActivateWaiterQueue. svn path=/trunk/; revision=24110 --- reactos/ntoskrnl/include/internal/ke.h | 2 +- reactos/ntoskrnl/include/internal/ke_x.h | 198 ++++++++--- reactos/ntoskrnl/ke/gate.c | 2 +- reactos/ntoskrnl/ke/queue.c | 6 +- reactos/ntoskrnl/ke/thrdobj.c | 2 +- reactos/ntoskrnl/ke/wait.c | 405 ++++++++++------------- 6 files changed, 331 insertions(+), 284 deletions(-) diff --git a/reactos/ntoskrnl/include/internal/ke.h b/reactos/ntoskrnl/include/internal/ke.h index 622bf01a2de..f14a2657eb6 100644 --- a/reactos/ntoskrnl/include/internal/ke.h +++ b/reactos/ntoskrnl/include/internal/ke.h @@ -622,7 +622,7 @@ KeRemoveQueueApc(PKAPC Apc); VOID FASTCALL -KiWakeQueue(IN PKQUEUE Queue); +KiActivateWaiterQueue(IN PKQUEUE Queue); /* INITIALIZATION FUNCTIONS *************************************************/ diff --git a/reactos/ntoskrnl/include/internal/ke_x.h b/reactos/ntoskrnl/include/internal/ke_x.h index c70eb871396..0f35b072f56 100644 --- a/reactos/ntoskrnl/include/internal/ke_x.h +++ b/reactos/ntoskrnl/include/internal/ke_x.h @@ -219,21 +219,24 @@ KiRecalculateDueTime(IN PLARGE_INTEGER OriginalDueTime, // // Determines wether a thread should be added to the wait list // -#define KiCheckThreadStackSwap(WaitMode, Thread, Swappable) \ -{ \ - /* Check the required conditions */ \ - if ((WaitMode != KernelMode) && \ - (Thread->EnableStackSwap) && \ - (Thread->Priority >= (LOW_REALTIME_PRIORITY + 9))) \ - { \ - /* We are go for swap */ \ - Swappable = TRUE; \ - } \ - else \ - { \ - /* Don't swap the thread */ \ - Swappable = FALSE; \ - } \ +FORCEINLINE +BOOLEAN +KiCheckThreadStackSwap(IN PKTHREAD Thread, + IN KPROCESSOR_MODE WaitMode) +{ + /* Check the required conditions */ + if ((WaitMode != KernelMode) && + (Thread->EnableStackSwap) && + (Thread->Priority >= (LOW_REALTIME_PRIORITY + 9))) + { + /* We are go for swap */ + return TRUE; + } + else + { + /* Don't swap the thread */ + return FALSE; + } } // @@ -251,45 +254,134 @@ KiRecalculateDueTime(IN PLARGE_INTEGER OriginalDueTime, } // -// 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. +// Checks if a wait in progress should be interrupted by APCs or an alertable +// state. // -#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; \ - } \ +FORCEINLINE +NTSTATUS +KiCheckAlertability(IN PKTHREAD Thread, + IN BOOLEAN Alertable, + IN KPROCESSOR_MODE WaitMode) +{ + /* Check if the wait is alertable */ + if (Alertable) + { + /* It is, first check if the thread is alerted in this mode */ + if (Thread->Alerted[WaitMode]) + { + /* It is, so bail out of the wait */ + Thread->Alerted[WaitMode] = FALSE; + return STATUS_ALERTED; + } + else if ((WaitMode != KernelMode) && + (!IsListEmpty(&Thread->ApcState.ApcListHead[UserMode]))) + { + /* It's isn't, but this is a user wait with queued user APCs */ + Thread->ApcState.UserApcPending = TRUE; + return STATUS_USER_APC; + } + else if (Thread->Alerted[KernelMode]) + { + /* It isn't that either, but we're alered in kernel mode */ + Thread->Alerted[KernelMode] = FALSE; + return STATUS_ALERTED; + } + } + else if ((WaitMode != KernelMode) && (Thread->ApcState.UserApcPending)) + { + /* Not alertable, but this is a user wait with pending user APCs */ + return STATUS_USER_APC; + } + + /* Otherwise, we're fine */ + return STATUS_WAIT_0; +} + +FORCEINLINE +BOOLEAN +KxDelayThreadWait(IN PKTHREAD Thread, + IN BOOLEAN Alertable, + IN KPROCESSOR_MODE WaitMode) +{ + BOOLEAN Swappable; + PKWAIT_BLOCK TimerBlock = &Thread->WaitBlock[TIMER_WAIT_BLOCK]; + + /* Setup the Wait Block */ + Thread->WaitBlockList = TimerBlock; + TimerBlock->NextWaitBlock = TimerBlock; + + /* Link the timer to this Wait Block */ + Thread->Timer.Header.WaitListHead.Flink = &TimerBlock->WaitListEntry; + Thread->Timer.Header.WaitListHead.Blink = &TimerBlock->WaitListEntry; + + /* Clear wait status */ + Thread->WaitStatus = STATUS_WAIT_0; + + /* Setup wait fields */ + Thread->Alertable = Alertable; + Thread->WaitReason = DelayExecution; + Thread->WaitMode = WaitMode; + + /* Check if we can swap the thread's stack */ + Thread->WaitListEntry.Flink = NULL; + Swappable = KiCheckThreadStackSwap(Thread, WaitMode); + + /* Set the wait time */ + Thread->WaitTime = ((PLARGE_INTEGER)&KeTickCount)->LowPart; + return Swappable; +} + +FORCEINLINE +BOOLEAN +KxSingleThreadWait(IN PKTHREAD Thread, + IN PKWAIT_BLOCK WaitBlock, + IN PVOID Object, + IN PLARGE_INTEGER Timeout, + IN BOOLEAN Alertable, + IN KWAIT_REASON WaitReason, + IN KPROCESSOR_MODE WaitMode) +{ + BOOLEAN Swappable; + PKWAIT_BLOCK TimerBlock = &Thread->WaitBlock[TIMER_WAIT_BLOCK]; + + /* Setup the Wait Block */ + Thread->WaitBlockList = WaitBlock; + WaitBlock->WaitKey = STATUS_WAIT_0; + WaitBlock->Object = Object; + WaitBlock->WaitType = WaitAny; + + /* Clear wait status */ + Thread->WaitStatus = STATUS_WAIT_0; + + /* Check if we have a timer */ + if (Timeout) + { + /* Pointer to timer block */ + WaitBlock->NextWaitBlock = TimerBlock; + TimerBlock->NextWaitBlock = WaitBlock; + + /* Link the timer to this Wait Block */ + Thread->Timer.Header.WaitListHead.Flink = &TimerBlock->WaitListEntry; + Thread->Timer.Header.WaitListHead.Blink = &TimerBlock->WaitListEntry; + } + else + { + /* No timer block, just ourselves */ + WaitBlock->NextWaitBlock = WaitBlock; + } + + /* Setup wait fields */ + Thread->Alertable = Alertable; + Thread->WaitReason = WaitReason; + Thread->WaitMode = WaitMode; + + /* Check if we can swap the thread's stack */ + Thread->WaitListEntry.Flink = NULL; + Swappable = KiCheckThreadStackSwap(Thread, WaitMode); + + /* Set the wait time */ + Thread->WaitTime = ((PLARGE_INTEGER)&KeTickCount)->LowPart; + return Swappable; } // diff --git a/reactos/ntoskrnl/ke/gate.c b/reactos/ntoskrnl/ke/gate.c index a8dab73d0b0..7357cfe9560 100644 --- a/reactos/ntoskrnl/ke/gate.c +++ b/reactos/ntoskrnl/ke/gate.c @@ -111,7 +111,7 @@ KeWaitForGate(IN PKGATE Gate, if (Queue) { /* Wake it up */ - KiWakeQueue(Queue); + KiActivateWaiterQueue(Queue); /* Release the dispatcher lock */ KiReleaseDispatcherLockFromDpcLevel(); diff --git a/reactos/ntoskrnl/ke/queue.c b/reactos/ntoskrnl/ke/queue.c index 91d9efed4d6..57e83f2a825 100644 --- a/reactos/ntoskrnl/ke/queue.c +++ b/reactos/ntoskrnl/ke/queue.c @@ -21,7 +21,7 @@ */ VOID FASTCALL -KiWakeQueue(IN PKQUEUE Queue) +KiActivateWaiterQueue(IN PKQUEUE Queue) { PLIST_ENTRY QueueEntry; PLIST_ENTRY WaitEntry; @@ -285,7 +285,7 @@ KeRemoveQueue(IN PKQUEUE Queue, RemoveEntryList(QueueEntry); /* Wake the queue */ - KiWakeQueue(PreviousQueue); + KiActivateWaiterQueue(PreviousQueue); } /* Insert in this new Queue */ @@ -359,7 +359,7 @@ KeRemoveQueue(IN PKQUEUE Queue, /* Check if we can swap the thread's stack */ Thread->WaitListEntry.Flink = NULL; - KiCheckThreadStackSwap(WaitMode, Thread, Swappable); + Swappable = KiCheckThreadStackSwap(Thread, WaitMode); /* We need to wait for the object... check for a timeout */ if (Timeout) diff --git a/reactos/ntoskrnl/ke/thrdobj.c b/reactos/ntoskrnl/ke/thrdobj.c index 12dfb0a327c..e4c683b1a5b 100644 --- a/reactos/ntoskrnl/ke/thrdobj.c +++ b/reactos/ntoskrnl/ke/thrdobj.c @@ -1324,7 +1324,7 @@ KeTerminateThread(IN KPRIORITY Increment) { /* Remove it from the list, and handle the queue */ RemoveEntryList(&Thread->QueueListEntry); - KiWakeQueue(Thread->Queue); + KiActivateWaiterQueue(Thread->Queue); } /* Signal the thread */ diff --git a/reactos/ntoskrnl/ke/wait.c b/reactos/ntoskrnl/ke/wait.c index 950b9d475c4..21bf97560c1 100644 --- a/reactos/ntoskrnl/ke/wait.c +++ b/reactos/ntoskrnl/ke/wait.c @@ -280,113 +280,88 @@ 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; + PKTHREAD Thread = KeGetCurrentThread(); + NTSTATUS WaitStatus; BOOLEAN Swappable; PLARGE_INTEGER OriginalDueTime = Interval; LARGE_INTEGER DueTime, NewDueTime; /* Check if the lock is already held */ - if (CurrentThread->WaitNext) + if (Thread->WaitNext) { /* Lock is held, disable Wait Next */ - CurrentThread->WaitNext = FALSE; + Thread->WaitNext = FALSE; + Swappable = KxDelayThreadWait(Thread, Alertable, WaitMode); } else { /* Lock not held, acquire it */ - CurrentThread->WaitIrql = KiAcquireDispatcherLock(); +WaitStart: + Thread->WaitIrql = KiAcquireDispatcherLock(); + Swappable = KxDelayThreadWait(Thread, Alertable, WaitMode); } - /* 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 ((Thread->ApcState.KernelApcPending) && !(Thread->SpecialApcDisable) && + (Thread->WaitIrql < APC_LEVEL)) { - /* 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 */ - KiReleaseDispatcherLock(CurrentThread->WaitIrql); - } - else - { - /* Check if we can do an alertable wait, if requested */ - KiCheckAlertability(); - - /* Check if we can swap the thread's stack */ - CurrentThread->WaitListEntry.Flink = NULL; - KiCheckThreadStackSwap(WaitMode, CurrentThread, Swappable); - - /* Set status */ - CurrentThread->WaitStatus = STATUS_WAIT_0; - - /* Set Timer */ - ThreadTimer = &CurrentThread->Timer; + /* Unlock the dispatcher */ + KiReleaseDispatcherLock(Thread->WaitIrql); + goto WaitStart; + } - /* Setup the Wait Block */ - CurrentThread->WaitBlockList = TimerWaitBlock; - TimerWaitBlock->NextWaitBlock = TimerWaitBlock; + /* Check if we have to bail out due to an alerted state */ + WaitStatus = KiCheckAlertability(Thread, Alertable, WaitMode); + if (WaitStatus != STATUS_WAIT_0) + { + /* Unlock the dispatcher and return */ + KiReleaseDispatcherLock(Thread->WaitIrql); + return WaitStatus; + } - /* Link the timer to this Wait Block */ - ThreadTimer->Header.WaitListHead.Flink = - &TimerWaitBlock->WaitListEntry; - ThreadTimer->Header.WaitListHead.Blink = - &TimerWaitBlock->WaitListEntry; + /* Set Timer */ + ThreadTimer = &Thread->Timer; - /* 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; - } + /* Insert the Timer into the Timer Lists and enable it */ + if (!KiInsertTimer(ThreadTimer, *Interval)) + { + /* FIXME: We should find a new ready thread */ + KiReleaseDispatcherLock(Thread->WaitIrql); + return STATUS_WAIT_0; + } - /* Save due time */ - DueTime.QuadPart = ThreadTimer->DueTime.QuadPart; + /* Save due time */ + DueTime.QuadPart = ThreadTimer->DueTime.QuadPart; - /* Handle Kernel Queues */ - if (CurrentThread->Queue) KiWakeQueue(CurrentThread->Queue); + /* Handle Kernel Queues */ + if (Thread->Queue) KiActivateWaiterQueue(Thread->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 */ - KiAddThreadToWaitList(CurrentThread, Swappable); - WaitStatus = KiSwapThread(CurrentThread, KeGetCurrentPrcb()); - ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); + /* Setup the wait information */ + Thread->State = Waiting; - /* 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; + /* Add the thread to the wait list */ + KiAddThreadToWaitList(Thread, Swappable); - /* Return Status */ - return WaitStatus; - } + /* Swap the thread */ + ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL); + KiSetThreadSwapBusy(Thread); + WaitStatus = KiSwapThread(Thread, KeGetCurrentPrcb()); - /* Recalculate due times */ - Interval = KiRecalculateDueTime(OriginalDueTime, - &DueTime, - &NewDueTime); - } + /* Check if we were executing an APC or if we timed out */ + if (WaitStatus == STATUS_KERNEL_APC) + { + /* Recalculate due times */ + Interval = KiRecalculateDueTime(OriginalDueTime, + &DueTime, + &NewDueTime); + goto WaitStart; + } - /* Acquire again the lock */ - CurrentThread->WaitIrql = KiAcquireDispatcherLock(); - } while (TRUE); + /* This is a good thing */ + if (WaitStatus == STATUS_TIMEOUT) WaitStatus = STATUS_SUCCESS; - /* Release the Lock, we are done */ - KiReleaseDispatcherLock(CurrentThread->WaitIrql); + /* Return Status */ return WaitStatus; } @@ -403,183 +378,163 @@ KeWaitForSingleObject(IN PVOID Object, { PKMUTANT CurrentObject; PKWAIT_BLOCK WaitBlock; - PKWAIT_BLOCK TimerWaitBlock; PKTIMER ThreadTimer; - PKTHREAD CurrentThread = KeGetCurrentThread(); - NTSTATUS WaitStatus = STATUS_SUCCESS; + PKTHREAD Thread = KeGetCurrentThread(); + NTSTATUS WaitStatus; BOOLEAN Swappable; LARGE_INTEGER DueTime, NewDueTime; PLARGE_INTEGER OriginalDueTime = Timeout; + /* Get wait block */ + WaitBlock = &Thread->WaitBlock[0]; + /* Check if the lock is already held */ - if (CurrentThread->WaitNext) + if (Thread->WaitNext) { /* Lock is held, disable Wait Next */ - CurrentThread->WaitNext = FALSE; + Thread->WaitNext = FALSE; + Swappable = KxSingleThreadWait(Thread, + WaitBlock, + Object, + Timeout, + Alertable, + WaitReason, + WaitMode); } else { +StartWait: /* Lock not held, acquire it */ - CurrentThread->WaitIrql = KiAcquireDispatcherLock(); + Thread->WaitIrql = KiAcquireDispatcherLock(); + Swappable = KxSingleThreadWait(Thread, + WaitBlock, + Object, + Timeout, + WaitReason, + WaitMode, + Alertable); } - /* Start the actual Loop */ - WaitBlock = &CurrentThread->WaitBlock[0]; - do + /* Check if a kernel APC is pending and we're below APC_LEVEL */ + if ((Thread->ApcState.KernelApcPending) && !(Thread->SpecialApcDisable) && + (Thread->WaitIrql < APC_LEVEL)) { - /* 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 */ - KiReleaseDispatcherLock(CurrentThread->WaitIrql); - } - else - { - /* Set default status */ - CurrentThread->WaitStatus = STATUS_WAIT_0; + /* Unlock the dispatcher and wait again */ + KiReleaseDispatcherLock(Thread->WaitIrql); + goto StartWait; + } - /* Get the Current Object */ - CurrentObject = (PKMUTANT)Object; + /* Get the Current Object */ + CurrentObject = (PKMUTANT)Object; + ASSERT(CurrentObject->Header.Type != QueueObject); - /* 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) */ - KiReleaseDispatcherLock(CurrentThread-> - WaitIrql); - ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED); - } - } - } - else if (CurrentObject->Header.SignalState > 0) + /* 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) || + (Thread == CurrentObject->OwnerThread)) + { + /* Just unwait this guy and exit */ + if (CurrentObject->Header.SignalState != (LONG)MINLONG) { - /* Another satisfied object */ - KiSatisfyNonMutantWait(CurrentObject, CurrentThread); - WaitStatus = STATUS_WAIT_0; + /* It has a normal signal state. Unwait and return */ + KiSatisfyMutantWait(CurrentObject, Thread); + WaitStatus = Thread->WaitStatus; goto DontWait; } - - /* Append wait block to the KTHREAD wait block list */ - CurrentThread->WaitBlockList = WaitBlock; - - /* Set up the Wait Block */ - WaitBlock->Object = CurrentObject; - WaitBlock->WaitKey = (USHORT)(STATUS_SUCCESS); - WaitBlock->WaitType = WaitAny; - - /* Make sure we can satisfy the Alertable request */ - KiCheckAlertability(); - - /* Check if we can swap the thread's stack */ - CurrentThread->WaitListEntry.Flink = NULL; - KiCheckThreadStackSwap(WaitMode, CurrentThread, Swappable); - - /* Enable the Timeout Timer if there was any specified */ - if (Timeout) + else { - /* 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; + /* Raise an exception */ + KiReleaseDispatcherLock(Thread->WaitIrql); + ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED); + } + } + } + else if (CurrentObject->Header.SignalState > 0) + { + /* Another satisfied object */ + KiSatisfyNonMutantWait(CurrentObject, Thread); + WaitStatus = STATUS_WAIT_0; + goto DontWait; + } - /* Set up the Timer Wait Block */ - TimerWaitBlock->NextWaitBlock = WaitBlock; + /* Make sure we can satisfy the Alertable request */ + WaitStatus = KiCheckAlertability(Thread, Alertable, WaitMode); + if (WaitStatus != STATUS_WAIT_0) + { + /* Unlock the dispatcher and return */ + KiReleaseDispatcherLock(Thread->WaitIrql); + return WaitStatus; + } - /* Link the timer to this Wait Block */ - ThreadTimer->Header.WaitListHead.Flink = - &TimerWaitBlock->WaitListEntry; - ThreadTimer->Header.WaitListHead.Blink = - &TimerWaitBlock->WaitListEntry; + /* 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; + } - /* 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 the Timer into the Timer Lists and enable it */ + ThreadTimer = &Thread->Timer; + if (!KiInsertTimer(ThreadTimer, *Timeout)) + { + /* Return a timeout if we couldn't insert the timer */ + WaitStatus = STATUS_TIMEOUT; + goto DontWait; + } - /* Set the current due time */ - DueTime.QuadPart = ThreadTimer->DueTime.QuadPart; - } - else - { - /* No timer block, so just set our wait block as next */ - WaitBlock->NextWaitBlock = WaitBlock; - } + /* Set the current due time */ + DueTime.QuadPart = ThreadTimer->DueTime.QuadPart; + } - /* Link the Object to this Wait Block */ - InsertTailList(&CurrentObject->Header.WaitListHead, - &WaitBlock->WaitListEntry); + /* Link the Object to this Wait Block */ + InsertTailList(&CurrentObject->Header.WaitListHead, + &WaitBlock->WaitListEntry); - /* Handle Kernel Queues */ - if (CurrentThread->Queue) KiWakeQueue(CurrentThread->Queue); + /* Handle Kernel Queues */ + if (Thread->Queue) KiActivateWaiterQueue(Thread->Queue); - /* Setup the wait information */ - CurrentThread->Alertable = Alertable; - CurrentThread->WaitMode = WaitMode; - CurrentThread->WaitReason = WaitReason; - CurrentThread->WaitTime = ((PLARGE_INTEGER)&KeTickCount)->LowPart; - CurrentThread->State = Waiting; + /* Setup the wait information */ + Thread->State = Waiting; - /* Find a new thread to run */ - KiAddThreadToWaitList(CurrentThread, Swappable); - WaitStatus = KiSwapThread(CurrentThread, KeGetCurrentPrcb()); - ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); + /* Add the thread to the wait list */ + KiAddThreadToWaitList(Thread, Swappable); - /* Check if we were executing an APC */ - if (WaitStatus != STATUS_KERNEL_APC) return WaitStatus; + /* Swap the thread */ + ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL); + KiSetThreadSwapBusy(Thread); + WaitStatus = KiSwapThread(Thread, KeGetCurrentPrcb()); - /* Check if we had a timeout */ - if (Timeout) - { - /* Recalculate due times */ - Timeout = KiRecalculateDueTime(OriginalDueTime, - &DueTime, - &NewDueTime); - } + /* Check if we were executing an APC */ + if (WaitStatus == STATUS_KERNEL_APC) + { + /* Check if we had a timeout */ + if (Timeout) + { + /* Recalculate due times */ + Timeout = KiRecalculateDueTime(OriginalDueTime, + &DueTime, + &NewDueTime); } - /* Acquire again the lock */ - CurrentThread->WaitIrql = KiAcquireDispatcherLock(); - } while (TRUE); + /* Wait again */ + goto StartWait; + } - /* Release the Lock, we are done */ - KiReleaseDispatcherLock(CurrentThread->WaitIrql); + /* Wait complete */ return WaitStatus; DontWait: /* Adjust the Quantum */ - KiAdjustQuantumThread(CurrentThread); + KiAdjustQuantumThread(Thread); /* Release & Return */ - KiReleaseDispatcherLock(CurrentThread->WaitIrql); + KiReleaseDispatcherLock(Thread->WaitIrql); return WaitStatus; } @@ -769,11 +724,11 @@ KeWaitForMultipleObjects(IN ULONG Count, } /* Make sure we can satisfy the Alertable request */ - KiCheckAlertability(); + WaitStatus = KiCheckAlertability(CurrentThread, Alertable, WaitMode); /* Check if we can swap the thread's stack */ CurrentThread->WaitListEntry.Flink = NULL; - KiCheckThreadStackSwap(WaitMode, CurrentThread, Swappable); + Swappable = KiCheckThreadStackSwap(CurrentThread, WaitMode); /* Enable the Timeout Timer if there was any specified */ if (Timeout) @@ -827,7 +782,7 @@ KeWaitForMultipleObjects(IN ULONG Count, } while (WaitBlock != WaitBlockArray); /* Handle Kernel Queues */ - if (CurrentThread->Queue) KiWakeQueue(CurrentThread->Queue); + if (CurrentThread->Queue) KiActivateWaiterQueue(CurrentThread->Queue); /* Setup the wait information */ CurrentThread->Alertable = Alertable; @@ -880,22 +835,22 @@ NtDelayExecution(IN BOOLEAN Alertable, LARGE_INTEGER SafeInterval; NTSTATUS Status = STATUS_SUCCESS; - /* Check if parameters are valid */ + /* Check the previous mode */ if(PreviousMode != KernelMode) { + /* Enter SEH for probing */ _SEH_TRY { - /* make a copy on the kernel stack and let DelayInterval point to it so - we don't need to wrap KeDelayExecutionThread in SEH! */ + /* Probe and capture the time out */ SafeInterval = ProbeForReadLargeInteger(DelayInterval); DelayInterval = &SafeInterval; } _SEH_HANDLE { + /* Get SEH exception */ Status = _SEH_GetExceptionCode(); } _SEH_END; - if (!NT_SUCCESS(Status)) return Status; } -- 2.17.1