mirror of
https://github.com/reactos/reactos.git
synced 2024-07-02 10:45:24 +00:00
- 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:
parent
bb617c9ac9
commit
1b75e6549e
|
@ -622,7 +622,7 @@ KeRemoveQueueApc(PKAPC Apc);
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
FASTCALL
|
FASTCALL
|
||||||
KiWakeQueue(IN PKQUEUE Queue);
|
KiActivateWaiterQueue(IN PKQUEUE Queue);
|
||||||
|
|
||||||
/* INITIALIZATION FUNCTIONS *************************************************/
|
/* INITIALIZATION FUNCTIONS *************************************************/
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue