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=25605... ============================================================================== --- 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/k... ============================================================================== --- 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=256... ============================================================================== --- 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=2560... ============================================================================== --- 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: