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