- 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
This commit is contained in:
Alex Ionescu 2006-09-14 15:48:02 +00:00
parent bb617c9ac9
commit 1b75e6549e
6 changed files with 338 additions and 291 deletions

View file

@ -622,7 +622,7 @@ KeRemoveQueueApc(PKAPC Apc);
VOID VOID
FASTCALL FASTCALL
KiWakeQueue(IN PKQUEUE Queue); KiActivateWaiterQueue(IN PKQUEUE Queue);
/* INITIALIZATION FUNCTIONS *************************************************/ /* INITIALIZATION FUNCTIONS *************************************************/

View file

@ -219,21 +219,24 @@ KiRecalculateDueTime(IN PLARGE_INTEGER OriginalDueTime,
// //
// Determines wether a thread should be added to the wait list // Determines wether a thread should be added to the wait list
// //
#define KiCheckThreadStackSwap(WaitMode, Thread, Swappable) \ FORCEINLINE
{ \ BOOLEAN
/* Check the required conditions */ \ KiCheckThreadStackSwap(IN PKTHREAD Thread,
if ((WaitMode != KernelMode) && \ IN KPROCESSOR_MODE WaitMode)
(Thread->EnableStackSwap) && \ {
(Thread->Priority >= (LOW_REALTIME_PRIORITY + 9))) \ /* Check the required conditions */
{ \ if ((WaitMode != KernelMode) &&
/* We are go for swap */ \ (Thread->EnableStackSwap) &&
Swappable = TRUE; \ (Thread->Priority >= (LOW_REALTIME_PRIORITY + 9)))
} \ {
else \ /* We are go for swap */
{ \ return TRUE;
/* Don't swap the thread */ \ }
Swappable = FALSE; \ else
} \ {
/* Don't swap the thread */
return FALSE;
}
} }
// //
@ -251,45 +254,134 @@ KiRecalculateDueTime(IN PLARGE_INTEGER OriginalDueTime,
} }
// //
// Rules for checking alertability: // Checks if a wait in progress should be interrupted by APCs or an alertable
// - For Alertable waits ONLY: // state.
// * 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() \ FORCEINLINE
{ \ NTSTATUS
if (Alertable) \ KiCheckAlertability(IN PKTHREAD Thread,
{ \ IN BOOLEAN Alertable,
if (CurrentThread->Alerted[(int)WaitMode]) \ IN KPROCESSOR_MODE WaitMode)
{ \ {
CurrentThread->Alerted[(int)WaitMode] = FALSE; \ /* Check if the wait is alertable */
WaitStatus = STATUS_ALERTED; \ if (Alertable)
break; \ {
} \ /* It is, first check if the thread is alerted in this mode */
else if ((WaitMode != KernelMode) && \ if (Thread->Alerted[WaitMode])
(!IsListEmpty(&CurrentThread-> \ {
ApcState.ApcListHead[UserMode]))) \ /* It is, so bail out of the wait */
{ \ Thread->Alerted[WaitMode] = FALSE;
CurrentThread->ApcState.UserApcPending = TRUE; \ return STATUS_ALERTED;
WaitStatus = STATUS_USER_APC; \ }
break; \ else if ((WaitMode != KernelMode) &&
} \ (!IsListEmpty(&Thread->ApcState.ApcListHead[UserMode])))
else if (CurrentThread->Alerted[KernelMode]) \ {
{ \ /* It's isn't, but this is a user wait with queued user APCs */
CurrentThread->Alerted[KernelMode] = FALSE; \ Thread->ApcState.UserApcPending = TRUE;
WaitStatus = STATUS_ALERTED; \ return STATUS_USER_APC;
break; \ }
} \ else if (Thread->Alerted[KernelMode])
} \ {
else if ((WaitMode != KernelMode) && \ /* It isn't that either, but we're alered in kernel mode */
(CurrentThread->ApcState.UserApcPending)) \ Thread->Alerted[KernelMode] = FALSE;
{ \ return STATUS_ALERTED;
WaitStatus = STATUS_USER_APC; \ }
break; \ }
} \ 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;
} }
// //

View file

@ -111,7 +111,7 @@ KeWaitForGate(IN PKGATE Gate,
if (Queue) if (Queue)
{ {
/* Wake it up */ /* Wake it up */
KiWakeQueue(Queue); KiActivateWaiterQueue(Queue);
/* Release the dispatcher lock */ /* Release the dispatcher lock */
KiReleaseDispatcherLockFromDpcLevel(); KiReleaseDispatcherLockFromDpcLevel();

View file

@ -21,7 +21,7 @@
*/ */
VOID VOID
FASTCALL FASTCALL
KiWakeQueue(IN PKQUEUE Queue) KiActivateWaiterQueue(IN PKQUEUE Queue)
{ {
PLIST_ENTRY QueueEntry; PLIST_ENTRY QueueEntry;
PLIST_ENTRY WaitEntry; PLIST_ENTRY WaitEntry;
@ -285,7 +285,7 @@ KeRemoveQueue(IN PKQUEUE Queue,
RemoveEntryList(QueueEntry); RemoveEntryList(QueueEntry);
/* Wake the queue */ /* Wake the queue */
KiWakeQueue(PreviousQueue); KiActivateWaiterQueue(PreviousQueue);
} }
/* Insert in this new Queue */ /* Insert in this new Queue */
@ -359,7 +359,7 @@ KeRemoveQueue(IN PKQUEUE Queue,
/* Check if we can swap the thread's stack */ /* Check if we can swap the thread's stack */
Thread->WaitListEntry.Flink = NULL; Thread->WaitListEntry.Flink = NULL;
KiCheckThreadStackSwap(WaitMode, Thread, Swappable); Swappable = KiCheckThreadStackSwap(Thread, WaitMode);
/* We need to wait for the object... check for a timeout */ /* We need to wait for the object... check for a timeout */
if (Timeout) if (Timeout)

View file

@ -1324,7 +1324,7 @@ KeTerminateThread(IN KPRIORITY Increment)
{ {
/* Remove it from the list, and handle the queue */ /* Remove it from the list, and handle the queue */
RemoveEntryList(&Thread->QueueListEntry); RemoveEntryList(&Thread->QueueListEntry);
KiWakeQueue(Thread->Queue); KiActivateWaiterQueue(Thread->Queue);
} }
/* Signal the thread */ /* Signal the thread */

View file

@ -280,113 +280,88 @@ KeDelayExecutionThread(IN KPROCESSOR_MODE WaitMode,
IN BOOLEAN Alertable, IN BOOLEAN Alertable,
IN PLARGE_INTEGER Interval OPTIONAL) IN PLARGE_INTEGER Interval OPTIONAL)
{ {
PKWAIT_BLOCK TimerWaitBlock;
PKTIMER ThreadTimer; PKTIMER ThreadTimer;
PKTHREAD CurrentThread = KeGetCurrentThread(); PKTHREAD Thread = KeGetCurrentThread();
NTSTATUS WaitStatus = STATUS_SUCCESS; NTSTATUS WaitStatus;
BOOLEAN Swappable; BOOLEAN Swappable;
PLARGE_INTEGER OriginalDueTime = Interval; PLARGE_INTEGER OriginalDueTime = Interval;
LARGE_INTEGER DueTime, NewDueTime; LARGE_INTEGER DueTime, NewDueTime;
/* Check if the lock is already held */ /* Check if the lock is already held */
if (CurrentThread->WaitNext) if (Thread->WaitNext)
{ {
/* Lock is held, disable Wait Next */ /* Lock is held, disable Wait Next */
CurrentThread->WaitNext = FALSE; Thread->WaitNext = FALSE;
Swappable = KxDelayThreadWait(Thread, Alertable, WaitMode);
} }
else else
{ {
/* Lock not held, acquire it */ /* 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 */ /* Check if a kernel APC is pending and we're below APC_LEVEL */
if ((CurrentThread->ApcState.KernelApcPending) && if ((Thread->ApcState.KernelApcPending) && !(Thread->SpecialApcDisable) &&
!(CurrentThread->SpecialApcDisable) && (Thread->WaitIrql < APC_LEVEL))
(CurrentThread->WaitIrql < APC_LEVEL))
{ {
/* Unlock the dispatcher */ /* Unlock the dispatcher */
KiReleaseDispatcherLock(CurrentThread->WaitIrql); KiReleaseDispatcherLock(Thread->WaitIrql);
goto WaitStart;
} }
else
/* Check if we have to bail out due to an alerted state */
WaitStatus = KiCheckAlertability(Thread, Alertable, WaitMode);
if (WaitStatus != STATUS_WAIT_0)
{ {
/* Check if we can do an alertable wait, if requested */ /* Unlock the dispatcher and return */
KiCheckAlertability(); KiReleaseDispatcherLock(Thread->WaitIrql);
return WaitStatus;
/* 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 */ /* Set Timer */
ThreadTimer = &CurrentThread->Timer; ThreadTimer = &Thread->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 */ /* Insert the Timer into the Timer Lists and enable it */
if (!KiInsertTimer(ThreadTimer, *Interval)) if (!KiInsertTimer(ThreadTimer, *Interval))
{ {
/* FIXME: We should find a new ready thread */ /* FIXME: We should find a new ready thread */
WaitStatus = STATUS_SUCCESS; KiReleaseDispatcherLock(Thread->WaitIrql);
break; return STATUS_WAIT_0;
} }
/* Save due time */ /* Save due time */
DueTime.QuadPart = ThreadTimer->DueTime.QuadPart; DueTime.QuadPart = ThreadTimer->DueTime.QuadPart;
/* Handle Kernel Queues */ /* Handle Kernel Queues */
if (CurrentThread->Queue) KiWakeQueue(CurrentThread->Queue); if (Thread->Queue) KiActivateWaiterQueue(Thread->Queue);
/* Setup the wait information */ /* Setup the wait information */
CurrentThread->Alertable = Alertable; Thread->State = Waiting;
CurrentThread->WaitMode = WaitMode;
CurrentThread->WaitReason = DelayExecution;
CurrentThread->WaitTime = ((PLARGE_INTEGER)&KeTickCount)->LowPart;
CurrentThread->State = Waiting;
/* Find a new thread to run */ /* Add the thread to the wait list */
KiAddThreadToWaitList(CurrentThread, Swappable); KiAddThreadToWaitList(Thread, Swappable);
WaitStatus = KiSwapThread(CurrentThread, KeGetCurrentPrcb());
ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); /* Swap the thread */
ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL);
KiSetThreadSwapBusy(Thread);
WaitStatus = KiSwapThread(Thread, KeGetCurrentPrcb());
/* Check if we were executing an APC or if we timed out */ /* Check if we were executing an APC or if we timed out */
if (WaitStatus != STATUS_KERNEL_APC) if (WaitStatus == STATUS_KERNEL_APC)
{ {
/* This is a good thing */
if (WaitStatus == STATUS_TIMEOUT) WaitStatus = STATUS_SUCCESS;
/* Return Status */
return WaitStatus;
}
/* Recalculate due times */ /* Recalculate due times */
Interval = KiRecalculateDueTime(OriginalDueTime, Interval = KiRecalculateDueTime(OriginalDueTime,
&DueTime, &DueTime,
&NewDueTime); &NewDueTime);
goto WaitStart;
} }
/* Acquire again the lock */ /* This is a good thing */
CurrentThread->WaitIrql = KiAcquireDispatcherLock(); if (WaitStatus == STATUS_TIMEOUT) WaitStatus = STATUS_SUCCESS;
} while (TRUE);
/* Release the Lock, we are done */ /* Return Status */
KiReleaseDispatcherLock(CurrentThread->WaitIrql);
return WaitStatus; return WaitStatus;
} }
@ -403,66 +378,75 @@ KeWaitForSingleObject(IN PVOID Object,
{ {
PKMUTANT CurrentObject; PKMUTANT CurrentObject;
PKWAIT_BLOCK WaitBlock; PKWAIT_BLOCK WaitBlock;
PKWAIT_BLOCK TimerWaitBlock;
PKTIMER ThreadTimer; PKTIMER ThreadTimer;
PKTHREAD CurrentThread = KeGetCurrentThread(); PKTHREAD Thread = KeGetCurrentThread();
NTSTATUS WaitStatus = STATUS_SUCCESS; NTSTATUS WaitStatus;
BOOLEAN Swappable; BOOLEAN Swappable;
LARGE_INTEGER DueTime, NewDueTime; LARGE_INTEGER DueTime, NewDueTime;
PLARGE_INTEGER OriginalDueTime = Timeout; PLARGE_INTEGER OriginalDueTime = Timeout;
/* Get wait block */
WaitBlock = &Thread->WaitBlock[0];
/* Check if the lock is already held */ /* Check if the lock is already held */
if (CurrentThread->WaitNext) if (Thread->WaitNext)
{ {
/* Lock is held, disable Wait Next */ /* Lock is held, disable Wait Next */
CurrentThread->WaitNext = FALSE; Thread->WaitNext = FALSE;
Swappable = KxSingleThreadWait(Thread,
WaitBlock,
Object,
Timeout,
Alertable,
WaitReason,
WaitMode);
} }
else else
{ {
StartWait:
/* Lock not held, acquire it */ /* 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 */ /* Check if a kernel APC is pending and we're below APC_LEVEL */
if ((CurrentThread->ApcState.KernelApcPending) && if ((Thread->ApcState.KernelApcPending) && !(Thread->SpecialApcDisable) &&
!(CurrentThread->SpecialApcDisable) && (Thread->WaitIrql < APC_LEVEL))
(CurrentThread->WaitIrql < APC_LEVEL))
{ {
/* Unlock the dispatcher */ /* Unlock the dispatcher and wait again */
KiReleaseDispatcherLock(CurrentThread->WaitIrql); KiReleaseDispatcherLock(Thread->WaitIrql);
goto StartWait;
} }
else
{
/* Set default status */
CurrentThread->WaitStatus = STATUS_WAIT_0;
/* Get the Current Object */ /* Get the Current Object */
CurrentObject = (PKMUTANT)Object; CurrentObject = (PKMUTANT)Object;
ASSERT(CurrentObject->Header.Type != QueueObject);
/* Check if it's a mutant */ /* Check if it's a mutant */
if (CurrentObject->Header.Type == MutantObject) if (CurrentObject->Header.Type == MutantObject)
{ {
/* Check its signal state or if we own it */ /* Check its signal state or if we own it */
if ((CurrentObject->Header.SignalState > 0) || if ((CurrentObject->Header.SignalState > 0) ||
(CurrentThread == CurrentObject->OwnerThread)) (Thread == CurrentObject->OwnerThread))
{ {
/* Just unwait this guy and exit */ /* Just unwait this guy and exit */
if (CurrentObject->Header.SignalState != (LONG)MINLONG) if (CurrentObject->Header.SignalState != (LONG)MINLONG)
{ {
/* It has a normal signal state. Unwait and return */ /* It has a normal signal state. Unwait and return */
KiSatisfyMutantWait(CurrentObject, CurrentThread); KiSatisfyMutantWait(CurrentObject, Thread);
WaitStatus = CurrentThread->WaitStatus; WaitStatus = Thread->WaitStatus;
goto DontWait; goto DontWait;
} }
else else
{ {
/* Raise an exception (see wasm.ru) */ /* Raise an exception */
KiReleaseDispatcherLock(CurrentThread-> KiReleaseDispatcherLock(Thread->WaitIrql);
WaitIrql);
ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED); ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED);
} }
} }
@ -470,25 +454,19 @@ KeWaitForSingleObject(IN PVOID Object,
else if (CurrentObject->Header.SignalState > 0) else if (CurrentObject->Header.SignalState > 0)
{ {
/* Another satisfied object */ /* Another satisfied object */
KiSatisfyNonMutantWait(CurrentObject, CurrentThread); KiSatisfyNonMutantWait(CurrentObject, Thread);
WaitStatus = STATUS_WAIT_0; WaitStatus = STATUS_WAIT_0;
goto DontWait; 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 */ /* Make sure we can satisfy the Alertable request */
KiCheckAlertability(); WaitStatus = KiCheckAlertability(Thread, Alertable, WaitMode);
if (WaitStatus != STATUS_WAIT_0)
/* Check if we can swap the thread's stack */ {
CurrentThread->WaitListEntry.Flink = NULL; /* Unlock the dispatcher and return */
KiCheckThreadStackSwap(WaitMode, CurrentThread, Swappable); KiReleaseDispatcherLock(Thread->WaitIrql);
return WaitStatus;
}
/* Enable the Timeout Timer if there was any specified */ /* Enable the Timeout Timer if there was any specified */
if (Timeout) if (Timeout)
@ -501,23 +479,8 @@ KeWaitForSingleObject(IN PVOID Object,
goto DontWait; 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 */ /* Insert the Timer into the Timer Lists and enable it */
ThreadTimer = &Thread->Timer;
if (!KiInsertTimer(ThreadTimer, *Timeout)) if (!KiInsertTimer(ThreadTimer, *Timeout))
{ {
/* Return a timeout if we couldn't insert the timer */ /* Return a timeout if we couldn't insert the timer */
@ -528,34 +491,28 @@ KeWaitForSingleObject(IN PVOID Object,
/* Set the current due time */ /* Set the current due time */
DueTime.QuadPart = ThreadTimer->DueTime.QuadPart; DueTime.QuadPart = ThreadTimer->DueTime.QuadPart;
} }
else
{
/* No timer block, so just set our wait block as next */
WaitBlock->NextWaitBlock = WaitBlock;
}
/* Link the Object to this Wait Block */ /* Link the Object to this Wait Block */
InsertTailList(&CurrentObject->Header.WaitListHead, InsertTailList(&CurrentObject->Header.WaitListHead,
&WaitBlock->WaitListEntry); &WaitBlock->WaitListEntry);
/* Handle Kernel Queues */ /* Handle Kernel Queues */
if (CurrentThread->Queue) KiWakeQueue(CurrentThread->Queue); if (Thread->Queue) KiActivateWaiterQueue(Thread->Queue);
/* Setup the wait information */ /* Setup the wait information */
CurrentThread->Alertable = Alertable; Thread->State = Waiting;
CurrentThread->WaitMode = WaitMode;
CurrentThread->WaitReason = WaitReason;
CurrentThread->WaitTime = ((PLARGE_INTEGER)&KeTickCount)->LowPart;
CurrentThread->State = Waiting;
/* Find a new thread to run */ /* Add the thread to the wait list */
KiAddThreadToWaitList(CurrentThread, Swappable); KiAddThreadToWaitList(Thread, Swappable);
WaitStatus = KiSwapThread(CurrentThread, KeGetCurrentPrcb());
ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); /* Swap the thread */
ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL);
KiSetThreadSwapBusy(Thread);
WaitStatus = KiSwapThread(Thread, KeGetCurrentPrcb());
/* Check if we were executing an APC */ /* Check if we were executing an APC */
if (WaitStatus != STATUS_KERNEL_APC) return WaitStatus; if (WaitStatus == STATUS_KERNEL_APC)
{
/* Check if we had a timeout */ /* Check if we had a timeout */
if (Timeout) if (Timeout)
{ {
@ -564,22 +521,20 @@ KeWaitForSingleObject(IN PVOID Object,
&DueTime, &DueTime,
&NewDueTime); &NewDueTime);
} }
/* Wait again */
goto StartWait;
} }
/* Acquire again the lock */ /* Wait complete */
CurrentThread->WaitIrql = KiAcquireDispatcherLock();
} while (TRUE);
/* Release the Lock, we are done */
KiReleaseDispatcherLock(CurrentThread->WaitIrql);
return WaitStatus; return WaitStatus;
DontWait: DontWait:
/* Adjust the Quantum */ /* Adjust the Quantum */
KiAdjustQuantumThread(CurrentThread); KiAdjustQuantumThread(Thread);
/* Release & Return */ /* Release & Return */
KiReleaseDispatcherLock(CurrentThread->WaitIrql); KiReleaseDispatcherLock(Thread->WaitIrql);
return WaitStatus; return WaitStatus;
} }
@ -769,11 +724,11 @@ KeWaitForMultipleObjects(IN ULONG Count,
} }
/* Make sure we can satisfy the Alertable request */ /* Make sure we can satisfy the Alertable request */
KiCheckAlertability(); WaitStatus = KiCheckAlertability(CurrentThread, Alertable, WaitMode);
/* Check if we can swap the thread's stack */ /* Check if we can swap the thread's stack */
CurrentThread->WaitListEntry.Flink = NULL; CurrentThread->WaitListEntry.Flink = NULL;
KiCheckThreadStackSwap(WaitMode, CurrentThread, Swappable); Swappable = KiCheckThreadStackSwap(CurrentThread, WaitMode);
/* Enable the Timeout Timer if there was any specified */ /* Enable the Timeout Timer if there was any specified */
if (Timeout) if (Timeout)
@ -827,7 +782,7 @@ KeWaitForMultipleObjects(IN ULONG Count,
} while (WaitBlock != WaitBlockArray); } while (WaitBlock != WaitBlockArray);
/* Handle Kernel Queues */ /* Handle Kernel Queues */
if (CurrentThread->Queue) KiWakeQueue(CurrentThread->Queue); if (CurrentThread->Queue) KiActivateWaiterQueue(CurrentThread->Queue);
/* Setup the wait information */ /* Setup the wait information */
CurrentThread->Alertable = Alertable; CurrentThread->Alertable = Alertable;
@ -880,22 +835,22 @@ NtDelayExecution(IN BOOLEAN Alertable,
LARGE_INTEGER SafeInterval; LARGE_INTEGER SafeInterval;
NTSTATUS Status = STATUS_SUCCESS; NTSTATUS Status = STATUS_SUCCESS;
/* Check if parameters are valid */ /* Check the previous mode */
if(PreviousMode != KernelMode) if(PreviousMode != KernelMode)
{ {
/* Enter SEH for probing */
_SEH_TRY _SEH_TRY
{ {
/* make a copy on the kernel stack and let DelayInterval point to it so /* Probe and capture the time out */
we don't need to wrap KeDelayExecutionThread in SEH! */
SafeInterval = ProbeForReadLargeInteger(DelayInterval); SafeInterval = ProbeForReadLargeInteger(DelayInterval);
DelayInterval = &SafeInterval; DelayInterval = &SafeInterval;
} }
_SEH_HANDLE _SEH_HANDLE
{ {
/* Get SEH exception */
Status = _SEH_GetExceptionCode(); Status = _SEH_GetExceptionCode();
} }
_SEH_END; _SEH_END;
if (!NT_SUCCESS(Status)) return Status; if (!NT_SUCCESS(Status)) return Status;
} }