- 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 */ /* Check if a kernel APC is pending and we're below APC_LEVEL */
TimerWaitBlock = &CurrentThread->WaitBlock[TIMER_WAIT_BLOCK]; if ((Thread->ApcState.KernelApcPending) && !(Thread->SpecialApcDisable) &&
(Thread->WaitIrql < APC_LEVEL))
/* Start Wait Loop */
do
{ {
/* Check if a kernel APC is pending and we're below APC_LEVEL */ /* Unlock the dispatcher */
if ((CurrentThread->ApcState.KernelApcPending) && KiReleaseDispatcherLock(Thread->WaitIrql);
!(CurrentThread->SpecialApcDisable) && goto WaitStart;
(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 */ /* Check if we have to bail out due to an alerted state */
CurrentThread->WaitListEntry.Flink = NULL; WaitStatus = KiCheckAlertability(Thread, Alertable, WaitMode);
KiCheckThreadStackSwap(WaitMode, CurrentThread, Swappable); if (WaitStatus != STATUS_WAIT_0)
{
/* Unlock the dispatcher and return */
KiReleaseDispatcherLock(Thread->WaitIrql);
return WaitStatus;
}
/* Set status */ /* Set Timer */
CurrentThread->WaitStatus = STATUS_WAIT_0; ThreadTimer = &Thread->Timer;
/* Set Timer */ /* Insert the Timer into the Timer Lists and enable it */
ThreadTimer = &CurrentThread->Timer; if (!KiInsertTimer(ThreadTimer, *Interval))
{
/* FIXME: We should find a new ready thread */
KiReleaseDispatcherLock(Thread->WaitIrql);
return STATUS_WAIT_0;
}
/* Setup the Wait Block */ /* Save due time */
CurrentThread->WaitBlockList = TimerWaitBlock; DueTime.QuadPart = ThreadTimer->DueTime.QuadPart;
TimerWaitBlock->NextWaitBlock = TimerWaitBlock;
/* Link the timer to this Wait Block */ /* Handle Kernel Queues */
ThreadTimer->Header.WaitListHead.Flink = if (Thread->Queue) KiActivateWaiterQueue(Thread->Queue);
&TimerWaitBlock->WaitListEntry;
ThreadTimer->Header.WaitListHead.Blink =
&TimerWaitBlock->WaitListEntry;
/* Insert the Timer into the Timer Lists and enable it */ /* Setup the wait information */
if (!KiInsertTimer(ThreadTimer, *Interval)) Thread->State = Waiting;
{
/* FIXME: We should find a new ready thread */
WaitStatus = STATUS_SUCCESS;
break;
}
/* Save due time */ /* Add the thread to the wait list */
DueTime.QuadPart = ThreadTimer->DueTime.QuadPart; KiAddThreadToWaitList(Thread, Swappable);
/* Handle Kernel Queues */ /* Swap the thread */
if (CurrentThread->Queue) KiWakeQueue(CurrentThread->Queue); ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL);
KiSetThreadSwapBusy(Thread);
WaitStatus = KiSwapThread(Thread, KeGetCurrentPrcb());
/* Setup the wait information */ /* Check if we were executing an APC or if we timed out */
CurrentThread->Alertable = Alertable; if (WaitStatus == STATUS_KERNEL_APC)
CurrentThread->WaitMode = WaitMode; {
CurrentThread->WaitReason = DelayExecution; /* Recalculate due times */
CurrentThread->WaitTime = ((PLARGE_INTEGER)&KeTickCount)->LowPart; Interval = KiRecalculateDueTime(OriginalDueTime,
CurrentThread->State = Waiting; &DueTime,
&NewDueTime);
goto WaitStart;
}
/* Find a new thread to run */ /* This is a good thing */
KiAddThreadToWaitList(CurrentThread, Swappable); if (WaitStatus == STATUS_TIMEOUT) WaitStatus = STATUS_SUCCESS;
WaitStatus = KiSwapThread(CurrentThread, KeGetCurrentPrcb());
ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
/* Check if we were executing an APC or if we timed out */ /* Return Status */
if (WaitStatus != STATUS_KERNEL_APC)
{
/* This is a good thing */
if (WaitStatus == STATUS_TIMEOUT) WaitStatus = STATUS_SUCCESS;
/* Return Status */
return WaitStatus;
}
/* Recalculate due times */
Interval = KiRecalculateDueTime(OriginalDueTime,
&DueTime,
&NewDueTime);
}
/* Acquire again the lock */
CurrentThread->WaitIrql = KiAcquireDispatcherLock();
} while (TRUE);
/* Release the Lock, we are done */
KiReleaseDispatcherLock(CurrentThread->WaitIrql);
return WaitStatus; return WaitStatus;
} }
@ -403,183 +378,163 @@ 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 */ /* Check if a kernel APC is pending and we're below APC_LEVEL */
WaitBlock = &CurrentThread->WaitBlock[0]; if ((Thread->ApcState.KernelApcPending) && !(Thread->SpecialApcDisable) &&
do (Thread->WaitIrql < APC_LEVEL))
{ {
/* Check if a kernel APC is pending and we're below APC_LEVEL */ /* Unlock the dispatcher and wait again */
if ((CurrentThread->ApcState.KernelApcPending) && KiReleaseDispatcherLock(Thread->WaitIrql);
!(CurrentThread->SpecialApcDisable) && goto StartWait;
(CurrentThread->WaitIrql < APC_LEVEL)) }
{
/* Unlock the dispatcher */
KiReleaseDispatcherLock(CurrentThread->WaitIrql);
}
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 */
if ((CurrentObject->Header.SignalState > 0) ||
(Thread == CurrentObject->OwnerThread))
{
/* Just unwait this guy and exit */
if (CurrentObject->Header.SignalState != (LONG)MINLONG)
{ {
/* Check its signal state or if we own it */ /* It has a normal signal state. Unwait and return */
if ((CurrentObject->Header.SignalState > 0) || KiSatisfyMutantWait(CurrentObject, Thread);
(CurrentThread == CurrentObject->OwnerThread)) WaitStatus = Thread->WaitStatus;
{
/* 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)
{
/* Another satisfied object */
KiSatisfyNonMutantWait(CurrentObject, CurrentThread);
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 */
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)
{
/* 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;
}
/* Set the current due time */
DueTime.QuadPart = ThreadTimer->DueTime.QuadPart;
}
else else
{ {
/* No timer block, so just set our wait block as next */ /* Raise an exception */
WaitBlock->NextWaitBlock = WaitBlock; 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;
}
/* Link the Object to this Wait Block */ /* Make sure we can satisfy the Alertable request */
InsertTailList(&CurrentObject->Header.WaitListHead, WaitStatus = KiCheckAlertability(Thread, Alertable, WaitMode);
&WaitBlock->WaitListEntry); if (WaitStatus != STATUS_WAIT_0)
{
/* Unlock the dispatcher and return */
KiReleaseDispatcherLock(Thread->WaitIrql);
return WaitStatus;
}
/* Handle Kernel Queues */ /* Enable the Timeout Timer if there was any specified */
if (CurrentThread->Queue) KiWakeQueue(CurrentThread->Queue); if (Timeout)
{
/* Setup the wait information */ /* Fail if the timeout interval is actually 0 */
CurrentThread->Alertable = Alertable; if (!Timeout->QuadPart)
CurrentThread->WaitMode = WaitMode; {
CurrentThread->WaitReason = WaitReason; /* Return a timeout */
CurrentThread->WaitTime = ((PLARGE_INTEGER)&KeTickCount)->LowPart; WaitStatus = STATUS_TIMEOUT;
CurrentThread->State = Waiting; goto DontWait;
/* Find a new thread to run */
KiAddThreadToWaitList(CurrentThread, Swappable);
WaitStatus = KiSwapThread(CurrentThread, KeGetCurrentPrcb());
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)
{
/* Recalculate due times */
Timeout = KiRecalculateDueTime(OriginalDueTime,
&DueTime,
&NewDueTime);
}
} }
/* Acquire again the lock */ /* Insert the Timer into the Timer Lists and enable it */
CurrentThread->WaitIrql = KiAcquireDispatcherLock(); ThreadTimer = &Thread->Timer;
} while (TRUE); if (!KiInsertTimer(ThreadTimer, *Timeout))
{
/* Return a timeout if we couldn't insert the timer */
WaitStatus = STATUS_TIMEOUT;
goto DontWait;
}
/* Release the Lock, we are done */ /* Set the current due time */
KiReleaseDispatcherLock(CurrentThread->WaitIrql); DueTime.QuadPart = ThreadTimer->DueTime.QuadPart;
}
/* Link the Object to this Wait Block */
InsertTailList(&CurrentObject->Header.WaitListHead,
&WaitBlock->WaitListEntry);
/* Handle Kernel Queues */
if (Thread->Queue) KiActivateWaiterQueue(Thread->Queue);
/* Setup the wait information */
Thread->State = Waiting;
/* Add the thread to the wait list */
KiAddThreadToWaitList(Thread, Swappable);
/* Swap the thread */
ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL);
KiSetThreadSwapBusy(Thread);
WaitStatus = KiSwapThread(Thread, KeGetCurrentPrcb());
/* 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);
}
/* Wait again */
goto StartWait;
}
/* Wait complete */
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;
} }