Author: ion
Date: Tue Jan 23 21:39:47 2007
New Revision: 25605
URL:
http://svn.reactos.org/svn/reactos?rev=25605&view=rev
Log:
- Convert KxDelayThreadWait, KxSingleThreadWait, KxMultiThreadWait into macros.
- Add KxQueueThreadWait macro based on previous ones.
- Add KxSetTimerForThreadWait to initialize the timer during the macros above. Wait timer
setup is now done in two phases, which will be required with the new timer code anyway.
- Remove IRQL hack from idle loop when delivering DPCs.
- Make the wait code use the new macros and make it scale better.
- Add some missing definitions to asm.h
Modified:
trunk/reactos/include/ndk/asm.h
trunk/reactos/ntoskrnl/include/internal/ke_x.h
trunk/reactos/ntoskrnl/ke/i386/ctxswitch.S
trunk/reactos/ntoskrnl/ke/queue.c
trunk/reactos/ntoskrnl/ke/wait.c
Modified: trunk/reactos/include/ndk/asm.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/include/ndk/asm.h?rev=2560…
==============================================================================
--- trunk/reactos/include/ndk/asm.h (original)
+++ trunk/reactos/include/ndk/asm.h Tue Jan 23 21:39:47 2007
@@ -19,6 +19,8 @@
#ifndef _ASM_H
#define _ASM_H
+
+//#define NEW_SCHEDULER
//
// PCR Access
@@ -138,6 +140,16 @@
#define EPROCESS_VDM_OBJECTS 0x144
//
+// KTIMER_TABLE Offsets
+//
+#ifdef __ASM__
+#define KTIMER_TABLE_ENTRY 0x00
+#define KTIMER_TABLE_TIME 0x08
+#define TIMER_ENTRY_SIZE 0x10
+#define TIMER_TABLE_SIZE 0x200
+#endif
+
+//
// KPRCB Offsets
//
#define KPRCB_DR0 0x2F8
@@ -146,6 +158,8 @@
#define KPRCB_DR3 0x304
#define KPRCB_DR6 0x308
#define KPRCB_DR7 0x20C
+#define KPRCB_TIMER_HAND 0x964
+#define KPRCB_TIMER_REQUEST 0x968
//
// KPCR Offsets
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 Tue Jan 23 21:39:47 2007
@@ -373,126 +373,220 @@
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
-KxMultiThreadWait(IN PKTHREAD Thread,
- IN PKWAIT_BLOCK WaitBlock,
- IN BOOLEAN Alertable,
- IN KWAIT_REASON WaitReason,
- IN KPROCESSOR_MODE WaitMode)
-{
- BOOLEAN Swappable;
- PKTIMER ThreadTimer = &Thread->Timer;
-
- /* Set default wait status */
- Thread->WaitStatus = STATUS_WAIT_0;
-
- /* Link wait block array to the thread */
- Thread->WaitBlockList = WaitBlock;
-
- /* Initialize the timer list */
- InitializeListHead(&ThreadTimer->Header.WaitListHead);
-
- /* Set wait settings */
- Thread->Alertable = Alertable;
- Thread->WaitMode = WaitMode;
- Thread->WaitReason = WaitReason;
-
- /* 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;
-}
+VOID
+FORCEINLINE
+KxSetTimerForThreadWait(IN PKTIMER Timer,
+ IN LARGE_INTEGER Interval)
+{
+ LARGE_INTEGER InterruptTime, SystemTime, TimeDifference;
+
+ /* Check the timer's interval to see if it's absolute */
+ Timer->Header.Absolute = FALSE;
+ if (!Timer->Period) Timer->Header.SignalState = FALSE;
+ if (Interval.HighPart >= 0)
+ {
+ /* Get the system time and calculate the relative time */
+ KeQuerySystemTime(&SystemTime);
+ TimeDifference.QuadPart = SystemTime.QuadPart - Interval.QuadPart;
+ Timer->Header.Absolute = TRUE;
+
+ /* Check if we've already expired */
+ if (TimeDifference.HighPart >= 0)
+ {
+ /* Reset everything */
+ Timer->DueTime.QuadPart = 0;
+ Timer->Header.SignalState = TRUE;
+ return;
+ }
+ else
+ {
+ /* Update the interval */
+ Interval = TimeDifference;
+ }
+ }
+
+ /* Calculate the due time */
+ InterruptTime.QuadPart = KeQueryInterruptTime();
+ Timer->DueTime.QuadPart = InterruptTime.QuadPart - Interval.QuadPart;
+}
+
+#define KxDelayThreadWait() \
+ \
+ /* Setup the Wait Block */ \
+ Thread->WaitBlockList = TimerBlock; \
+ \
+ /* Setup the timer */ \
+ KxSetTimerForThreadWait(Timer, *Interval); \
+ \
+ /* Save the due time for the caller */ \
+ DueTime.QuadPart = Timer->DueTime.QuadPart; \
+ \
+ /* Link the timer to this Wait Block */ \
+ TimerBlock->NextWaitBlock = TimerBlock; \
+ Timer->Header.WaitListHead.Flink = &TimerBlock->WaitListEntry; \
+ Timer->Header.WaitListHead.Blink = &TimerBlock->WaitListEntry; \
+ \
+ /* Clear wait status */ \
+ Thread->WaitStatus = STATUS_SUCCESS; \
+ \
+ /* 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 = KeTickCount.LowPart;
+
+#define KxMultiThreadWait() \
+ /* Link wait block array to the thread */ \
+ Thread->WaitBlockList = WaitBlockArray; \
+ \
+ /* Reset the index */ \
+ Index = 0; \
+ \
+ /* Loop wait blocks */ \
+ do \
+ { \
+ /* Fill out the wait block */ \
+ WaitBlock = &WaitBlockArray[Index]; \
+ WaitBlock->Object = Object[Index]; \
+ WaitBlock->WaitKey = Index; \
+ WaitBlock->WaitType = WaitType; \
+ WaitBlock->Thread = Thread; \
+ \
+ /* Link to next block */ \
+ WaitBlock->NextWaitBlock = &WaitBlockArray[Index + 1]; \
+ Index++; \
+ } while (Index < Count); \
+ \
+ /* Link the last block */ \
+ WaitBlock->NextWaitBlock = WaitBlockArray; \
+ \
+ /* Set default wait status */ \
+ Thread->WaitStatus = STATUS_WAIT_0; \
+ \
+ /* Check if we have a timer */ \
+ if (Timeout) \
+ { \
+ /* Link to the block */ \
+ TimerBlock->NextWaitBlock = WaitBlockArray; \
+ \
+ /* Setup the timer */ \
+ KxSetTimerForThreadWait(Timer, *Timeout); \
+ \
+ /* Save the due time for the caller */ \
+ DueTime.QuadPart = Timer->DueTime.QuadPart; \
+ \
+ /* Initialize the list */ \
+ InitializeListHead(&Timer->Header.WaitListHead); \
+ } \
+ \
+ /* Set wait settings */ \
+ Thread->Alertable = Alertable; \
+ Thread->WaitMode = WaitMode; \
+ Thread->WaitReason = WaitReason; \
+ \
+ /* Check if we can swap the thread's stack */ \
+ Thread->WaitListEntry.Flink = NULL; \
+ Swappable = KiCheckThreadStackSwap(Thread, WaitMode); \
+ \
+ /* Set the wait time */ \
+ Thread->WaitTime = KeTickCount.LowPart;
+
+#define KxSingleThreadWait() \
+ /* Setup the Wait Block */ \
+ Thread->WaitBlockList = WaitBlock; \
+ WaitBlock->WaitKey = STATUS_SUCCESS; \
+ WaitBlock->Object = Object; \
+ WaitBlock->WaitType = WaitAny; \
+ \
+ /* Clear wait status */ \
+ Thread->WaitStatus = STATUS_SUCCESS; \
+ \
+ /* Check if we have a timer */ \
+ if (Timeout) \
+ { \
+ /* Setup the timer */ \
+ KxSetTimerForThreadWait(Timer, *Timeout); \
+ \
+ /* Save the due time for the caller */ \
+ DueTime.QuadPart = Timer->DueTime.QuadPart; \
+ \
+ /* Pointer to timer block */ \
+ WaitBlock->NextWaitBlock = TimerBlock; \
+ TimerBlock->NextWaitBlock = WaitBlock; \
+ \
+ /* Link the timer to this Wait Block */ \
+ Timer->Header.WaitListHead.Flink = &TimerBlock->WaitListEntry; \
+ Timer->Header.WaitListHead.Blink = &TimerBlock->WaitListEntry; \
+ } \
+ else \
+ { \
+ /* No timer block, just ourselves */ \
+ WaitBlock->NextWaitBlock = WaitBlock; \
+ } \
+ \
+ /* Set wait settings */ \
+ Thread->Alertable = Alertable; \
+ Thread->WaitMode = WaitMode; \
+ Thread->WaitReason = WaitReason; \
+ \
+ /* Check if we can swap the thread's stack */ \
+ Thread->WaitListEntry.Flink = NULL; \
+ Swappable = KiCheckThreadStackSwap(Thread, WaitMode); \
+ \
+ /* Set the wait time */ \
+ Thread->WaitTime = KeTickCount.LowPart;
+
+#define KxQueueThreadWait() \
+ /* Setup the Wait Block */ \
+ Thread->WaitBlockList = WaitBlock; \
+ WaitBlock->WaitKey = STATUS_SUCCESS; \
+ WaitBlock->Object = Queue; \
+ WaitBlock->WaitType = WaitAny; \
+ WaitBlock->Thread = Thread; \
+ \
+ /* Clear wait status */ \
+ Thread->WaitStatus = STATUS_SUCCESS; \
+ \
+ /* Check if we have a timer */ \
+ if (Timeout) \
+ { \
+ /* Setup the timer */ \
+ KxSetTimerForThreadWait(Timer, *Timeout); \
+ \
+ /* Save the due time for the caller */ \
+ DueTime.QuadPart = Timer->DueTime.QuadPart; \
+ \
+ /* Pointer to timer block */ \
+ WaitBlock->NextWaitBlock = TimerBlock; \
+ TimerBlock->NextWaitBlock = WaitBlock; \
+ \
+ /* Link the timer to this Wait Block */ \
+ Timer->Header.WaitListHead.Flink = &TimerBlock->WaitListEntry; \
+ Timer->Header.WaitListHead.Blink = &TimerBlock->WaitListEntry; \
+ } \
+ else \
+ { \
+ /* No timer block, just ourselves */ \
+ WaitBlock->NextWaitBlock = WaitBlock; \
+ } \
+ \
+ /* Set wait settings */ \
+ Thread->Alertable = FALSE; \
+ Thread->WaitMode = WaitMode; \
+ Thread->WaitReason = WrQueue; \
+ \
+ /* Check if we can swap the thread's stack */ \
+ Thread->WaitListEntry.Flink = NULL; \
+ Swappable = KiCheckThreadStackSwap(Thread, WaitMode); \
+ \
+ /* Set the wait time */ \
+ Thread->WaitTime = KeTickCount.LowPart;
//
// Unwaits a Thread
@@ -772,6 +866,27 @@
/* We deliver instantly on UP */
UNREFERENCED_PARAMETER(NeedApc);
UNREFERENCED_PARAMETER(Processor);
+}
+
+FORCEINLINE
+PKSPIN_LOCK_QUEUE
+KiAcquireTimerLock(IN ULONG Hand)
+{
+ ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL);
+
+ /* Nothing to do on UP */
+ UNREFERENCED_PARAMETER(Hand);
+ return NULL;
+}
+
+FORCEINLINE
+VOID
+KiReleaseTimerLock(IN PKSPIN_LOCK_QUEUE LockQueue)
+{
+ ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL);
+
+ /* Nothing to do on UP */
+ UNREFERENCED_PARAMETER(LockQueue);
}
#else
@@ -1350,3 +1465,19 @@
/* Return the current mode */
return KeGetCurrentThread()->PreviousMode;
}
+
+VOID
+FORCEINLINE
+KiInsertWaitTimer(IN PKTIMER Timer)
+{
+ /* Set default data */
+ Timer->Header.Inserted = TRUE;
+ if (!Timer->Period) Timer->Header.SignalState = FALSE;
+
+ /* Now insert it into the Timer List */
+ InsertAscendingList(&KiTimerListHead,
+ Timer,
+ KTIMER,
+ TimerListEntry,
+ DueTime.QuadPart);
+}
Modified: trunk/reactos/ntoskrnl/ke/i386/ctxswitch.S
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/i386/ctxswitch…
==============================================================================
--- trunk/reactos/ntoskrnl/ke/i386/ctxswitch.S (original)
+++ trunk/reactos/ntoskrnl/ke/i386/ctxswitch.S Tue Jan 23 21:39:47 2007
@@ -677,18 +677,9 @@
#endif
jz CheckSchedule
- /* Raise to DISPATCH_LEVEL */
- mov ecx, DISPATCH_LEVEL
- call @KfRaiseIrql@4
- mov edi, eax
-
/* Handle the above */
lea ecx, [ebx+KPCR_PRCB_DATA]
call @KiRetireDpcList@4
-
- /* Lower IRQL */
- mov ecx, edi
- call @KfLowerIrql@4
CheckSchedule:
#ifndef NEW_SCHEDULER
Modified: trunk/reactos/ntoskrnl/ke/queue.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/queue.c?rev=25…
==============================================================================
--- trunk/reactos/ntoskrnl/ke/queue.c (original)
+++ trunk/reactos/ntoskrnl/ke/queue.c Tue Jan 23 21:39:47 2007
@@ -244,13 +244,13 @@
PLIST_ENTRY QueueEntry;
NTSTATUS Status;
PKTHREAD Thread = KeGetCurrentThread();
- KIRQL OldIrql;
PKQUEUE PreviousQueue;
- PKWAIT_BLOCK WaitBlock;
- PKTIMER Timer;
+ PKWAIT_BLOCK WaitBlock = &Thread->WaitBlock[0];
+ PKWAIT_BLOCK TimerBlock = &Thread->WaitBlock[TIMER_WAIT_BLOCK];
+ PKTIMER Timer = &Thread->Timer;
BOOLEAN Swappable;
PLARGE_INTEGER OriginalDueTime = Timeout;
- LARGE_INTEGER DueTime, NewDueTime;
+ LARGE_INTEGER DueTime, NewDueTime, InterruptTime;
ASSERT_QUEUE(Queue);
ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
@@ -259,12 +259,14 @@
{
/* It is, so next time don't do expect this */
Thread->WaitNext = FALSE;
+ KxQueueThreadWait();
}
else
{
- /* Lock the Dispatcher Database */
- OldIrql = KiAcquireDispatcherLock();
- Thread->WaitIrql = OldIrql;
+ /* Raise IRQL to synch, prepare the wait, then lock the database */
+ Thread->WaitIrql = KeRaiseIrqlToSynchLevel();
+ KxQueueThreadWait();
+ KiAcquireDispatcherLockAtDpcLevel();
}
/*
@@ -314,7 +316,13 @@
/* Check if the entry is valid. If not, bugcheck */
if (!(QueueEntry->Flink) || !(QueueEntry->Blink))
{
- KEBUGCHECK(INVALID_WORK_QUEUE_ITEM);
+ /* Invalid item */
+ KeBugCheckEx(INVALID_WORK_QUEUE_ITEM,
+ (ULONG_PTR)QueueEntry,
+ (ULONG_PTR)Queue,
+ (ULONG_PTR)NULL,
+ (ULONG_PTR)((PWORK_QUEUE_ITEM)QueueEntry)->
+ WorkerRoutine);
}
/* Remove the Entry */
@@ -326,16 +334,14 @@
}
else
{
- /* Use the Thread's Wait Block, it's big enough */
- Thread->WaitBlockList = &Thread->WaitBlock[0];
-
/* Check if a kernel APC is pending and we're below APC_LEVEL */
if ((Thread->ApcState.KernelApcPending) &&
!(Thread->SpecialApcDisable) && (Thread->WaitIrql <
APC_LEVEL))
{
/* Increment the count and unlock the dispatcher */
Queue->CurrentCount++;
- KiReleaseDispatcherLock(Thread->WaitIrql);
+ KiReleaseDispatcherLockFromDpcLevel();
+ KiExitDispatcher(Thread->WaitIrql);
}
else
{
@@ -349,94 +355,57 @@
break;
}
- /* Build the Wait Block */
- WaitBlock = &Thread->WaitBlock[0];
- WaitBlock->Object = (PVOID)Queue;
- WaitBlock->WaitKey = STATUS_SUCCESS;
- WaitBlock->WaitType = WaitAny;
- WaitBlock->Thread = Thread;
- Thread->WaitStatus = STATUS_WAIT_0;
-
- /* Check if we can swap the thread's stack */
- Thread->WaitListEntry.Flink = NULL;
- Swappable = KiCheckThreadStackSwap(Thread, WaitMode);
-
- /* We need to wait for the object... check for a timeout */
+ /* Enable the Timeout Timer if there was any specified */
if (Timeout)
{
- /* Check if it's zero */
- if (!Timeout->QuadPart)
+ /* Check if the timer expired */
+ InterruptTime.QuadPart = KeQueryInterruptTime();
+ if (InterruptTime.QuadPart >= Timer->DueTime.QuadPart)
{
- /* Don't wait. Return and increase pending threads */
+ /* It did, so we don't need to wait */
QueueEntry = (PLIST_ENTRY)STATUS_TIMEOUT;
Queue->CurrentCount++;
break;
}
- /*
- * Set up the Timer. We'll use the internal function so
- * that we can hold on to the dispatcher lock.
- */
- Timer = &Thread->Timer;
- WaitBlock->NextWaitBlock = &Thread->WaitBlock[1];
- WaitBlock = &Thread->WaitBlock[1];
-
- /* Set up the Timer Wait Block */
- WaitBlock->Object = (PVOID)Timer;
- WaitBlock->Thread = Thread;
- WaitBlock->WaitKey = STATUS_TIMEOUT;
- WaitBlock->WaitType = WaitAny;
-
- /* Link the timer to this Wait Block */
- Timer->Header.WaitListHead.Flink =
- &WaitBlock->WaitListEntry;
- Timer->Header.WaitListHead.Blink =
- &WaitBlock->WaitListEntry;
- WaitBlock->WaitListEntry.Flink =
- &Timer->Header.WaitListHead;
- WaitBlock->WaitListEntry.Blink =
- &Timer->Header.WaitListHead;
-
- /* Create Timer */
- if (!KiInsertTimer(Timer, *Timeout))
- {
- /* FIXME */
- DPRINT1("If you see this message contact Alex
ASAP\n");
- KEBUGCHECK(0);
- }
-
- /* Set timer due time */
- DueTime.QuadPart = Timer->DueTime.QuadPart;
+ /* It didn't, so activate it */
+ Timer->Header.Inserted = TRUE;
}
- /* Close the loop */
- WaitBlock->NextWaitBlock = &Thread->WaitBlock[0];
-
- /* Insert the wait block into the Queues's wait list */
- WaitBlock = &Thread->WaitBlock[0];
+ /* Insert the wait block in the list */
InsertTailList(&Queue->Header.WaitListHead,
&WaitBlock->WaitListEntry);
/* Setup the wait information */
- Thread->WaitMode = WaitMode;
- Thread->WaitReason = WrQueue;
- Thread->Alertable = FALSE;
- Thread->WaitTime = ((PLARGE_INTEGER)&KeTickCount)->LowPart;
Thread->State = Waiting;
- /* Find a new thread to run */
+ /* Add the thread to the wait list */
KiAddThreadToWaitList(Thread, Swappable);
+
+ /* Activate thread swap */
+ ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL);
+ KiSetThreadSwapBusy(Thread);
+
+ /* Check if we have a timer */
+ if (Timeout)
+ {
+ /* Insert it */
+ KiInsertWaitTimer(Timer);
+ }
+ else
+ {
+ /* Otherwise, unlock the dispatcher */
+ KiReleaseDispatcherLockFromDpcLevel();
+ }
+
+ /* Do the actual swap */
Status = KiSwapThread(Thread, KeGetCurrentPrcb());
/* Reset the wait reason */
Thread->WaitReason = 0;
/* Check if we were executing an APC */
- if (Status != STATUS_KERNEL_APC)
- {
- /* Done Waiting */
- return (PLIST_ENTRY)Status;
- }
+ if (Status != STATUS_KERNEL_APC) return (PLIST_ENTRY)Status;
/* Check if we had a timeout */
if (Timeout)
@@ -448,17 +417,17 @@
}
}
- /* Reacquire the lock */
- OldIrql = KiAcquireDispatcherLock();
-
- /* Save the new IRQL and decrease number of waiting threads */
- Thread->WaitIrql = OldIrql;
+ /* Start another wait */
+ Thread->WaitIrql = KeRaiseIrqlToSynchLevel();
+ KxQueueThreadWait();
+ KiAcquireDispatcherLockAtDpcLevel();
Queue->CurrentCount--;
}
}
/* Unlock Database and return */
- KiReleaseDispatcherLock(Thread->WaitIrql);
+ KiReleaseDispatcherLockFromDpcLevel();
+ KiExitDispatcher(Thread->WaitIrql);
return QueueEntry;
}
Modified: trunk/reactos/ntoskrnl/ke/wait.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/wait.c?rev=256…
==============================================================================
--- trunk/reactos/ntoskrnl/ke/wait.c (original)
+++ trunk/reactos/ntoskrnl/ke/wait.c Tue Jan 23 21:39:47 2007
@@ -15,6 +15,7 @@
/* PRIVATE FUNCTIONS *********************************************************/
+#if 0
VOID
FASTCALL
KiWaitSatisfyAll(PKWAIT_BLOCK FirstBlock)
@@ -36,6 +37,7 @@
WaitBlock = WaitBlock->NextWaitBlock;
} while (WaitBlock != FirstBlock);
}
+#endif
VOID
FASTCALL
@@ -234,89 +236,122 @@
IN BOOLEAN Alertable,
IN PLARGE_INTEGER Interval OPTIONAL)
{
- PKTIMER ThreadTimer;
+ PKTIMER Timer;
+ PKWAIT_BLOCK TimerBlock;
PKTHREAD Thread = KeGetCurrentThread();
NTSTATUS WaitStatus;
BOOLEAN Swappable;
- PLARGE_INTEGER OriginalDueTime = Interval;
- LARGE_INTEGER DueTime, NewDueTime;
+ PLARGE_INTEGER OriginalDueTime;
+ LARGE_INTEGER DueTime, NewDueTime, InterruptTime;
+
+ /* If this is a user-mode wait of 0 seconds, yield execution */
+ if (!(Interval->QuadPart) && (WaitMode != KernelMode))
+ {
+ /* Make sure the wait isn't alertable or interrupting an APC */
+ if (!(Alertable) && !(Thread->ApcState.UserApcPending))
+ {
+ /* Yield execution */
+ NtYieldExecution();
+ }
+ }
+
+ /* Setup the original time and timer/wait blocks */
+ OriginalDueTime = Interval;
+ Timer = &Thread->Timer;
+ TimerBlock = &Thread->WaitBlock[TIMER_WAIT_BLOCK];
/* Check if the lock is already held */
- if (Thread->WaitNext)
- {
- /* Lock is held, disable Wait Next */
- Thread->WaitNext = FALSE;
- Swappable = KxDelayThreadWait(Thread, Alertable, WaitMode);
- }
- else
- {
- /* Lock not held, acquire it */
+ if (!Thread->WaitNext) goto WaitStart;
+
+ /* Otherwise, we already have the lock, so initialize the wait */
+ Thread->WaitNext = FALSE;
+ KxDelayThreadWait();
+
+ /* Start wait loop */
+ for (;;)
+ {
+ /* Disable pre-emption */
+ Thread->Preempted = FALSE;
+
+ /* Check if a kernel APC is pending and we're below APC_LEVEL */
+ if ((Thread->ApcState.KernelApcPending) &&
!(Thread->SpecialApcDisable) &&
+ (Thread->WaitIrql < APC_LEVEL))
+ {
+ /* Unlock the dispatcher */
+ KiReleaseDispatcherLock(Thread->WaitIrql);
+ }
+ else
+ {
+ /* Check if we have to bail out due to an alerted state */
+ WaitStatus = KiCheckAlertability(Thread, Alertable, WaitMode);
+ if (WaitStatus != STATUS_WAIT_0) break;
+
+ /* Check if the timer expired */
+ InterruptTime.QuadPart = KeQueryInterruptTime();
+ if (InterruptTime.QuadPart >= Timer->DueTime.QuadPart)
+ {
+ /* It did, so we don't need to wait */
+ goto NoWait;
+ }
+
+ /* It didn't, so activate it */
+ Timer->Header.Inserted = TRUE;
+
+ /* 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);
+
+ /* Insert the timer and swap the thread */
+ ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL);
+ KiSetThreadSwapBusy(Thread);
+ KiInsertWaitTimer(Timer);
+ WaitStatus = KiSwapThread(Thread, KeGetCurrentPrcb());
+
+ /* Check if were swapped ok */
+ 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);
+ }
+
WaitStart:
- Thread->WaitIrql = KiAcquireDispatcherLock();
- Swappable = KxDelayThreadWait(Thread, Alertable, WaitMode);
- }
-
- /* Check if a kernel APC is pending and we're below APC_LEVEL */
- if ((Thread->ApcState.KernelApcPending) && !(Thread->SpecialApcDisable)
&&
- (Thread->WaitIrql < APC_LEVEL))
- {
- /* Unlock the dispatcher */
+ /* Setup a new wait */
+ Thread->WaitIrql = KeRaiseIrqlToSynchLevel();
+ KxDelayThreadWait();
+ KiAcquireDispatcherLockAtDpcLevel();
+ }
+
+ /* We're done! */
+ KiReleaseDispatcherLock(Thread->WaitIrql);
+ return WaitStatus;
+
+NoWait:
+ /* There was nothing to wait for. Did we have a wait interval? */
+ if (!Interval->QuadPart)
+ {
+ /* Unlock the dispatcher and do a yield */
KiReleaseDispatcherLock(Thread->WaitIrql);
- goto WaitStart;
- }
-
- /* Check if we have to bail out due to an alerted state */
- WaitStatus = KiCheckAlertability(Thread, Alertable, WaitMode);
- if (WaitStatus != STATUS_WAIT_0)
- {
- /* Unlock the dispatcher and return */
- KiReleaseDispatcherLock(Thread->WaitIrql);
- return WaitStatus;
- }
-
- /* Set Timer */
- ThreadTimer = &Thread->Timer;
-
- /* Insert the Timer into the Timer Lists and enable it */
- if (!KiInsertTimer(ThreadTimer, *Interval))
- {
- /* FIXME: We should find a new ready thread */
- KiReleaseDispatcherLock(Thread->WaitIrql);
- return STATUS_WAIT_0;
- }
-
- /* Save due time */
- DueTime.QuadPart = ThreadTimer->DueTime.QuadPart;
-
- /* 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 or if we timed out */
- if (WaitStatus == STATUS_KERNEL_APC)
- {
- /* Recalculate due times */
- Interval = KiRecalculateDueTime(OriginalDueTime,
- &DueTime,
- &NewDueTime);
- goto WaitStart;
- }
-
- /* This is a good thing */
- if (WaitStatus == STATUS_TIMEOUT) WaitStatus = STATUS_SUCCESS;
-
- /* Return Status */
- return WaitStatus;
+ return NtYieldExecution();
+ }
+
+ /* Unlock the dispatcher and adjust the quantum for a no-wait */
+ KiReleaseDispatcherLockFromDpcLevel();
+ KiAdjustQuantumThread(Thread);
+ return STATUS_SUCCESS;
}
/*
@@ -330,157 +365,145 @@
IN BOOLEAN Alertable,
IN PLARGE_INTEGER Timeout OPTIONAL)
{
- PKMUTANT CurrentObject;
- PKWAIT_BLOCK WaitBlock;
- PKTIMER ThreadTimer;
PKTHREAD Thread = KeGetCurrentThread();
+ PKMUTANT CurrentObject = (PKMUTANT)Object;
+ PKWAIT_BLOCK WaitBlock = &Thread->WaitBlock[0];
+ PKWAIT_BLOCK TimerBlock = &Thread->WaitBlock[TIMER_WAIT_BLOCK];
+ PKTIMER Timer = &Thread->Timer;
NTSTATUS WaitStatus;
BOOLEAN Swappable;
- LARGE_INTEGER DueTime, NewDueTime;
+ LARGE_INTEGER DueTime, NewDueTime, InterruptTime;
PLARGE_INTEGER OriginalDueTime = Timeout;
- /* Get wait block */
- WaitBlock = &Thread->WaitBlock[0];
-
/* Check if the lock is already held */
- if (Thread->WaitNext)
- {
- /* Lock is held, disable Wait Next */
- Thread->WaitNext = FALSE;
- Swappable = KxSingleThreadWait(Thread,
- WaitBlock,
- Object,
- Timeout,
- Alertable,
- WaitReason,
- WaitMode);
- }
- else
- {
-StartWait:
- /* Lock not held, acquire it */
- Thread->WaitIrql = KiAcquireDispatcherLock();
- Swappable = KxSingleThreadWait(Thread,
- WaitBlock,
- Object,
- Timeout,
- WaitReason,
- WaitMode,
- Alertable);
- }
-
- /* Check if a kernel APC is pending and we're below APC_LEVEL */
- if ((Thread->ApcState.KernelApcPending) && !(Thread->SpecialApcDisable)
&&
- (Thread->WaitIrql < APC_LEVEL))
- {
- /* Unlock the dispatcher and wait again */
- KiReleaseDispatcherLock(Thread->WaitIrql);
- goto StartWait;
- }
-
- /* Get the Current Object */
- CurrentObject = (PKMUTANT)Object;
- ASSERT(CurrentObject->Header.Type != QueueObject);
-
- /* Check if it's a mutant */
- if (CurrentObject->Header.Type == MutantObject)
- {
- /* Check its signal state or if we own it */
- if ((CurrentObject->Header.SignalState > 0) ||
- (Thread == 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, Thread);
- WaitStatus = Thread->WaitStatus;
+ if (!Thread->WaitNext) goto WaitStart;
+
+ /* Otherwise, we already have the lock, so initialize the wait */
+ Thread->WaitNext = FALSE;
+ KxSingleThreadWait();
+
+ /* Start wait loop */
+ for (;;)
+ {
+ /* Disable pre-emption */
+ Thread->Preempted = FALSE;
+
+ /* Check if a kernel APC is pending and we're below APC_LEVEL */
+ if ((Thread->ApcState.KernelApcPending) &&
!(Thread->SpecialApcDisable) &&
+ (Thread->WaitIrql < APC_LEVEL))
+ {
+ /* Unlock the dispatcher */
+ KiReleaseDispatcherLock(Thread->WaitIrql);
+ }
+ else
+ {
+ /* Sanity check */
+ ASSERT(CurrentObject->Header.Type != QueueObject);
+
+ /* Check if it's a mutant */
+ if (CurrentObject->Header.Type == MutantObject)
+ {
+ /* Check its signal state or if we own it */
+ if ((CurrentObject->Header.SignalState > 0) ||
+ (Thread == 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, Thread);
+ WaitStatus = Thread->WaitStatus;
+ goto DontWait;
+ }
+ else
+ {
+ /* Raise an exception */
+ KiReleaseDispatcherLock(Thread->WaitIrql);
+ ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED);
+ }
+ }
+ }
+ else if (CurrentObject->Header.SignalState > 0)
+ {
+ /* Another satisfied object */
+ KiSatisfyNonMutantWait(CurrentObject, Thread);
+ WaitStatus = STATUS_WAIT_0;
goto DontWait;
}
+
+ /* Make sure we can satisfy the Alertable request */
+ WaitStatus = KiCheckAlertability(Thread, Alertable, WaitMode);
+ if (WaitStatus != STATUS_WAIT_0) break;
+
+ /* Enable the Timeout Timer if there was any specified */
+ if (Timeout)
+ {
+ /* Check if the timer expired */
+ InterruptTime.QuadPart = KeQueryInterruptTime();
+ if (InterruptTime.QuadPart >= Timer->DueTime.QuadPart)
+ {
+ /* It did, so we don't need to wait */
+ WaitStatus = STATUS_TIMEOUT;
+ goto DontWait;
+ }
+
+ /* It didn't, so activate it */
+ Timer->Header.Inserted = TRUE;
+ }
+
+ /* 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);
+
+ /* Activate thread swap */
+ ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL);
+ KiSetThreadSwapBusy(Thread);
+
+ /* Check if we have a timer */
+ if (Timeout)
+ {
+ /* Insert it */
+ KiInsertWaitTimer(Timer);
+ }
else
{
- /* Raise an exception */
- KiReleaseDispatcherLock(Thread->WaitIrql);
- ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED);
- }
- }
- }
- else if (CurrentObject->Header.SignalState > 0)
- {
- /* Another satisfied object */
- KiSatisfyNonMutantWait(CurrentObject, Thread);
- WaitStatus = STATUS_WAIT_0;
- goto DontWait;
- }
-
- /* Make sure we can satisfy the Alertable request */
- WaitStatus = KiCheckAlertability(Thread, Alertable, WaitMode);
- if (WaitStatus != STATUS_WAIT_0)
- {
- /* Unlock the dispatcher and return */
- KiReleaseDispatcherLock(Thread->WaitIrql);
- return WaitStatus;
- }
-
- /* Enable the Timeout Timer if there was any specified */
- if (Timeout)
- {
- /* Fail if the timeout interval is actually 0 */
- if (!Timeout->QuadPart)
- {
- /* Return a timeout */
- WaitStatus = STATUS_TIMEOUT;
- goto DontWait;
- }
-
- /* Insert the Timer into the Timer Lists and enable it */
- ThreadTimer = &Thread->Timer;
- if (!KiInsertTimer(ThreadTimer, *Timeout))
- {
- /* Return a timeout if we couldn't insert the timer */
- WaitStatus = STATUS_TIMEOUT;
- goto DontWait;
- }
-
- /* Set the current due time */
- DueTime.QuadPart = ThreadTimer->DueTime.QuadPart;
- }
-
- /* 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;
+ /* Otherwise, unlock the dispatcher */
+ KiReleaseDispatcherLockFromDpcLevel();
+ }
+
+ /* Do the actual swap */
+ WaitStatus = KiSwapThread(Thread, KeGetCurrentPrcb());
+
+ /* 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);
+ }
+ }
+WaitStart:
+ /* Setup a new wait */
+ Thread->WaitIrql = KeRaiseIrqlToSynchLevel();
+ KxSingleThreadWait();
+ KiAcquireDispatcherLockAtDpcLevel();
}
/* Wait complete */
+ KiReleaseDispatcherLock(Thread->WaitIrql);
return WaitStatus;
DontWait:
@@ -508,15 +531,14 @@
{
PKMUTANT CurrentObject;
PKWAIT_BLOCK WaitBlock;
- PKWAIT_BLOCK TimerWaitBlock;
- PKTIMER ThreadTimer;
PKTHREAD Thread = KeGetCurrentThread();
- ULONG AllObjectsSignaled;
- ULONG WaitIndex;
+ PKWAIT_BLOCK TimerBlock = &Thread->WaitBlock[TIMER_WAIT_BLOCK];
+ PKTIMER Timer = &Thread->Timer;
NTSTATUS WaitStatus = STATUS_SUCCESS;
BOOLEAN Swappable;
PLARGE_INTEGER OriginalDueTime = Timeout;
- LARGE_INTEGER DueTime, NewDueTime;
+ LARGE_INTEGER DueTime, NewDueTime, InterruptTime;
+ ULONG Index;
/* Make sure the Wait Count is valid */
if (!WaitBlockArray)
@@ -545,219 +567,220 @@
ASSERT(Count != 0);
/* Check if the lock is already held */
- if (Thread->WaitNext)
- {
- /* Lock is held, disable Wait Next */
- Thread->WaitNext = FALSE;
- }
- else
- {
- /* Lock not held, acquire it */
-StartWait:
- Thread->WaitIrql = KiAcquireDispatcherLock();
- }
-
- /* Prepare for the wait */
- Swappable = KxMultiThreadWait(Thread,
- WaitBlockArray,
- Alertable,
- WaitReason,
- WaitMode);
-
- /* Check if a kernel APC is pending and we're below APC_LEVEL */
- if ((Thread->ApcState.KernelApcPending) && !(Thread->SpecialApcDisable)
&&
- (Thread->WaitIrql < APC_LEVEL))
- {
- /* Unlock the dispatcher */
- KiReleaseDispatcherLock(Thread->WaitIrql);
- goto StartWait;
- }
-
- /* Append wait block to the KTHREAD wait block list */
- WaitBlock = WaitBlockArray;
-
- /* 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];
- ASSERT(CurrentObject->Header.Type != QueueObject);
-
- /* 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) ||
- (Thread == CurrentObject->OwnerThread))
+ if (!Thread->WaitNext) goto WaitStart;
+
+ /* Otherwise, we already have the lock, so initialize the wait */
+ Thread->WaitNext = FALSE;
+ KxMultiThreadWait();
+
+ /* Start wait loop */
+ for (;;)
+ {
+ /* Disable pre-emption */
+ Thread->Preempted = FALSE;
+
+ /* Check if a kernel APC is pending and we're below APC_LEVEL */
+ if ((Thread->ApcState.KernelApcPending) &&
!(Thread->SpecialApcDisable) &&
+ (Thread->WaitIrql < APC_LEVEL))
+ {
+ /* Unlock the dispatcher */
+ KiReleaseDispatcherLock(Thread->WaitIrql);
+ }
+ else
+ {
+ /* Check what kind of wait this is */
+ Index = 0;
+ if (WaitType == WaitAny)
+ {
+ /* Loop blocks */
+ do
{
- /* This is a Wait Any, so unwait this and exit */
- if (CurrentObject->Header.SignalState !=
- (LONG)MINLONG)
+ /* Get the Current Object */
+ CurrentObject = (PKMUTANT)Object[Index];
+ ASSERT(CurrentObject->Header.Type != QueueObject);
+
+ /* Check if the Object is a mutant */
+ if (CurrentObject->Header.Type == MutantObject)
{
- /* Normal signal state, unwait it and return */
- KiSatisfyMutantWait(CurrentObject, Thread);
- WaitStatus = Thread->WaitStatus | WaitIndex;
+ /* Check if it's signaled */
+ if ((CurrentObject->Header.SignalState > 0) ||
+ (Thread == 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, Thread);
+ WaitStatus = Thread->WaitStatus | Index;
+ goto DontWait;
+ }
+ else
+ {
+ /* Raise an exception (see wasm.ru) */
+ KiReleaseDispatcherLock(Thread->WaitIrql);
+ ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED);
+ }
+ }
+ }
+ else if (CurrentObject->Header.SignalState > 0)
+ {
+ /* Another signaled object, unwait and return */
+ KiSatisfyNonMutantWait(CurrentObject, Thread);
+ WaitStatus = Index;
goto DontWait;
}
- else
+
+ /* Go to the next block */
+ Index++;
+ } while (Index < Count);
+ }
+ else
+ {
+ /* Loop blocks */
+ do
+ {
+ /* Get the Current Object */
+ CurrentObject = (PKMUTANT)Object[Index];
+ ASSERT(CurrentObject->Header.Type != QueueObject);
+
+ /* Check if we're dealing with a mutant again */
+ if (CurrentObject->Header.Type == MutantObject)
{
- /* Raise an exception (see wasm.ru) */
- KiReleaseDispatcherLock(Thread->WaitIrql);
- ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED);
+ /* Check if it has an invalid count */
+ if ((Thread == CurrentObject->OwnerThread) &&
+ (CurrentObject->Header.SignalState == MINLONG))
+ {
+ /* Raise an exception */
+ KiReleaseDispatcherLock(Thread->WaitIrql);
+ ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED);
+ }
+ else if ((CurrentObject->Header.SignalState <= 0)
&&
+ (Thread != CurrentObject->OwnerThread))
+ {
+ /* We don't own it, can't satisfy the wait */
+ break;
+ }
}
+ else if (CurrentObject->Header.SignalState <= 0)
+ {
+ /* Not signaled, can't satisfy */
+ break;
+ }
+
+ /* Go to the next block */
+ Index++;
+ } while (Index < Count);
+
+ /* Check if we've went through all the objects */
+ if (Index == Count)
+ {
+ /* Loop wait blocks */
+ WaitBlock = WaitBlockArray;
+ do
+ {
+ /* Get the object and satisfy it */
+ CurrentObject = (PKMUTANT)WaitBlock->Object;
+ KiSatisfyObjectWait(CurrentObject, Thread);
+
+ /* Go to the next block */
+ WaitBlock = WaitBlock->NextWaitBlock;
+ } while(WaitBlock != WaitBlockArray);
+
+ /* Set the wait status and get out */
+ WaitStatus = Thread->WaitStatus;
+ goto DontWait;
}
}
- else if (CurrentObject->Header.SignalState > 0)
- {
- /* Another signaled object, unwait and return */
- KiSatisfyNonMutantWait(CurrentObject, Thread);
- 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 ((Thread == CurrentObject->OwnerThread) &&
- (CurrentObject->Header.SignalState == MINLONG))
+
+ /* Make sure we can satisfy the Alertable request */
+ WaitStatus = KiCheckAlertability(Thread, Alertable, WaitMode);
+ if (WaitStatus != STATUS_WAIT_0) break;
+
+ /* Enable the Timeout Timer if there was any specified */
+ if (Timeout)
+ {
+ /* Check if the timer expired */
+ InterruptTime.QuadPart = KeQueryInterruptTime();
+ if (InterruptTime.QuadPart >= Timer->DueTime.QuadPart)
{
- /* Raise an exception */
- KiReleaseDispatcherLock(Thread->WaitIrql);
- ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED);
+ /* It did, so we don't need to wait */
+ WaitStatus = STATUS_TIMEOUT;
+ goto DontWait;
}
- else if ((CurrentObject->Header.SignalState <= 0) &&
- (Thread != 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 = &WaitBlockArray[WaitIndex];
- WaitBlock->Object = CurrentObject;
- WaitBlock->Thread = Thread;
- WaitBlock->WaitKey = (USHORT)WaitIndex;
- WaitBlock->WaitType = (UCHAR)WaitType;
- WaitBlock->NextWaitBlock = &WaitBlockArray[WaitIndex + 1];
- }
-
- /* Check if this is a Wait All and all the objects are signaled */
- if ((WaitType == WaitAll) && (AllObjectsSignaled))
- {
- /* Return to the Root Wait Block */
- WaitBlock->NextWaitBlock = &WaitBlockArray[0];
-
- /* Satisfy their Waits and return to the caller */
- KiWaitSatisfyAll(WaitBlock);
- WaitStatus = Thread->WaitStatus;
- goto DontWait;
- }
-
- /* Make sure we can satisfy the Alertable request */
- WaitStatus = KiCheckAlertability(Thread, Alertable, WaitMode);
- if (WaitStatus != STATUS_WAIT_0)
- {
- /* Unlock the dispatcher and return */
- KiReleaseDispatcherLock(Thread->WaitIrql);
- return WaitStatus;
- }
-
- /* 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;
- }
-
- /* Link timer wait block */
- TimerWaitBlock = &Thread->WaitBlock[TIMER_WAIT_BLOCK];
- WaitBlock->NextWaitBlock = TimerWaitBlock;
-
- /* Use this the timer block for linking below */
- WaitBlock = TimerWaitBlock;
-
- /* Insert the Timer into the Timer Lists and enable it */
- ThreadTimer = &Thread->Timer;
- if (!KiInsertTimer(ThreadTimer, *Timeout))
- {
- /* Return a timeout if we couldn't insert the timer */
- WaitStatus = STATUS_TIMEOUT;
- goto DontWait;
- }
-
- /* Set the current due time */
- DueTime.QuadPart = ThreadTimer->DueTime.QuadPart;
- }
-
- /* Link to the Root Wait Block */
- WaitBlock->NextWaitBlock = &WaitBlockArray[0];
-
- /* Insert into Object's Wait List*/
- WaitBlock = &WaitBlockArray[0];
- 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 (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;
+
+ /* It didn't, so activate it */
+ Timer->Header.Inserted = TRUE;
+
+ /* Link the wait blocks */
+ WaitBlock->NextWaitBlock = TimerBlock;
+ }
+
+ /* Insert into Object's Wait List*/
+ WaitBlock = WaitBlockArray;
+ 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 (Thread->Queue) KiActivateWaiterQueue(Thread->Queue);
+
+ /* Setup the wait information */
+ Thread->State = Waiting;
+
+ /* Add the thread to the wait list */
+ KiAddThreadToWaitList(Thread, Swappable);
+
+ /* Activate thread swap */
+ ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL);
+ KiSetThreadSwapBusy(Thread);
+
+ /* Check if we have a timer */
+ if (Timeout)
+ {
+ /* Insert it */
+ KiInsertWaitTimer(Timer);
+ }
+ else
+ {
+ /* Otherwise, unlock the dispatcher */
+ KiReleaseDispatcherLockFromDpcLevel();
+ }
+
+ /* Swap the thread */
+ WaitStatus = KiSwapThread(Thread, KeGetCurrentPrcb());
+
+ /* 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);
+ }
+ }
+
+WaitStart:
+ /* Setup a new wait */
+ Thread->WaitIrql = KeRaiseIrqlToSynchLevel();
+ KxMultiThreadWait();
+ KiAcquireDispatcherLockAtDpcLevel();
}
/* We are done */
+ KiReleaseDispatcherLock(Thread->WaitIrql);
return WaitStatus;
DontWait: