X-Git-Url: https://git.reactos.org/?p=reactos.git;a=blobdiff_plain;f=reactos%2Fntoskrnl%2Fke%2Fwait.c;h=a4737b0b7faf173b06412b938f8624e14d870db1;hp=52eef5870589a68f288b3832c73a064fc6334761;hb=cbdf28bb6ace5e3faec494c5743371d7288f191c;hpb=5c2e4f088a9c1f6d7525163649bb92fcd1158b9c diff --git a/reactos/ntoskrnl/ke/wait.c b/reactos/ntoskrnl/ke/wait.c index 52eef587058..a4737b0b7fa 100644 --- a/reactos/ntoskrnl/ke/wait.c +++ b/reactos/ntoskrnl/ke/wait.c @@ -11,34 +11,10 @@ #include #define NDEBUG -#include +#include /* PRIVATE FUNCTIONS *********************************************************/ -#if 0 -VOID -FASTCALL -KiWaitSatisfyAll(PKWAIT_BLOCK FirstBlock) -{ - PKWAIT_BLOCK WaitBlock = FirstBlock; - PKTHREAD WaitThread = WaitBlock->Thread; - - /* Loop through all the Wait Blocks, and wake each Object */ - do - { - /* Make sure it hasn't timed out */ - if (WaitBlock->WaitKey != STATUS_TIMEOUT) - { - /* Wake the Object */ - KiSatisfyObjectWait((PKMUTANT)WaitBlock->Object, WaitThread); - } - - /* Move to the next block */ - WaitBlock = WaitBlock->NextWaitBlock; - } while (WaitBlock != FirstBlock); -} -#endif - VOID FASTCALL KiWaitTest(IN PVOID ObjectPointer, @@ -101,13 +77,7 @@ KiUnlinkThread(IN PKTHREAD Thread, /* Check if there's a Thread Timer */ Timer = &Thread->Timer; - if (Timer->Header.Inserted) - { - /* Remove the timer */ - Timer->Header.Inserted = FALSE; - RemoveEntryList(&Timer->TimerListEntry); - //KiRemoveTimer(Timer); - } + if (Timer->Header.Inserted) KxRemoveTreeTimer(Timer); /* Increment the Queue's active threads */ if (Thread->Queue) Thread->Queue->CurrentCount++; @@ -117,7 +87,7 @@ KiUnlinkThread(IN PKTHREAD Thread, VOID FASTCALL KiUnwaitThread(IN PKTHREAD Thread, - IN NTSTATUS WaitStatus, + IN LONG_PTR WaitStatus, IN KPRIORITY Increment) { /* Unlink the thread */ @@ -140,13 +110,83 @@ KiAcquireFastMutex(IN PFAST_MUTEX FastMutex) FastMutex->Contention++; /* Wait for the event */ - KeWaitForSingleObject(&FastMutex->Gate, + KeWaitForSingleObject(&FastMutex->Event, WrMutex, KernelMode, FALSE, NULL); } +VOID +FASTCALL +KiAcquireGuardedMutex(IN OUT PKGUARDED_MUTEX GuardedMutex) +{ + ULONG BitsToRemove, BitsToAdd; + LONG OldValue, NewValue; + + /* We depend on these bits being just right */ + C_ASSERT((GM_LOCK_WAITER_WOKEN * 2) == GM_LOCK_WAITER_INC); + + /* Increase the contention count */ + GuardedMutex->Contention++; + + /* Start by unlocking the Guarded Mutex */ + BitsToRemove = GM_LOCK_BIT; + BitsToAdd = GM_LOCK_WAITER_INC; + + /* Start change loop */ + for (;;) + { + /* Loop sanity checks */ + ASSERT((BitsToRemove == GM_LOCK_BIT) || + (BitsToRemove == (GM_LOCK_BIT | GM_LOCK_WAITER_WOKEN))); + ASSERT((BitsToAdd == GM_LOCK_WAITER_INC) || + (BitsToAdd == GM_LOCK_WAITER_WOKEN)); + + /* Get the Count Bits */ + OldValue = GuardedMutex->Count; + + /* Start internal bit change loop */ + for (;;) + { + /* Check if the Guarded Mutex is locked */ + if (OldValue & GM_LOCK_BIT) + { + /* Sanity check */ + ASSERT((BitsToRemove == GM_LOCK_BIT) || + ((OldValue & GM_LOCK_WAITER_WOKEN) != 0)); + + /* Unlock it by removing the Lock Bit */ + NewValue = OldValue ^ BitsToRemove; + NewValue = InterlockedCompareExchange(&GuardedMutex->Count, + NewValue, + OldValue); + if (NewValue == OldValue) return; + } + else + { + /* The Guarded Mutex isn't locked, so simply set the bits */ + NewValue = OldValue + BitsToAdd; + NewValue = InterlockedCompareExchange(&GuardedMutex->Count, + NewValue, + OldValue); + if (NewValue == OldValue) break; + } + + /* Old value changed, loop again */ + OldValue = NewValue; + } + + /* Now we have to wait for it */ + KeWaitForGate(&GuardedMutex->Gate, WrGuardedMutex, KernelMode); + ASSERT((GuardedMutex->Count & GM_LOCK_WAITER_WOKEN) != 0); + + /* Ok, the wait is done, so set the new bits */ + BitsToRemove = GM_LOCK_BIT | GM_LOCK_WAITER_WOKEN; + BitsToAdd = GM_LOCK_WAITER_WOKEN; + } +} + // // This routine exits the dispatcher after a compatible operation and // swaps the context to the next scheduled thread on the current CPU if @@ -163,7 +203,7 @@ KiExitDispatcher(IN KIRQL OldIrql) BOOLEAN PendingApc; /* Make sure we're at synchronization level */ - ASSERT_IRQL_EQUAL(SYNCH_LEVEL); + ASSERT(KeGetCurrentIrql() == SYNCH_LEVEL); /* Check if we have deferred threads */ KiCheckDeferredReadyList(Prcb); @@ -243,6 +283,7 @@ KeDelayExecutionThread(IN KPROCESSOR_MODE WaitMode, BOOLEAN Swappable; PLARGE_INTEGER OriginalDueTime; LARGE_INTEGER DueTime, NewDueTime, InterruptTime; + ULONG Hand = 0; /* If this is a user-mode wait of 0 seconds, yield execution */ if (!(Interval->QuadPart) && (WaitMode != KernelMode)) @@ -288,7 +329,7 @@ KeDelayExecutionThread(IN KPROCESSOR_MODE WaitMode, /* Check if the timer expired */ InterruptTime.QuadPart = KeQueryInterruptTime(); - if (InterruptTime.QuadPart >= Timer->DueTime.QuadPart) + if ((ULONGLONG)InterruptTime.QuadPart >= Timer->DueTime.QuadPart) { /* It did, so we don't need to wait */ goto NoWait; @@ -309,7 +350,7 @@ KeDelayExecutionThread(IN KPROCESSOR_MODE WaitMode, /* Insert the timer and swap the thread */ ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL); KiSetThreadSwapBusy(Thread); - KiInsertWaitTimer(Timer); + KxInsertTimer(Timer, Hand); WaitStatus = KiSwapThread(Thread, KeGetCurrentPrcb()); /* Check if were swapped ok */ @@ -374,6 +415,7 @@ KeWaitForSingleObject(IN PVOID Object, BOOLEAN Swappable; LARGE_INTEGER DueTime, NewDueTime, InterruptTime; PLARGE_INTEGER OriginalDueTime = Timeout; + ULONG Hand = 0; /* Check if the lock is already held */ if (!Thread->WaitNext) goto WaitStart; @@ -426,7 +468,7 @@ KeWaitForSingleObject(IN PVOID Object, else if (CurrentObject->Header.SignalState > 0) { /* Another satisfied object */ - KiSatisfyNonMutantWait(CurrentObject, Thread); + KiSatisfyNonMutantWait(CurrentObject); WaitStatus = STATUS_WAIT_0; goto DontWait; } @@ -440,7 +482,8 @@ KeWaitForSingleObject(IN PVOID Object, { /* Check if the timer expired */ InterruptTime.QuadPart = KeQueryInterruptTime(); - if (InterruptTime.QuadPart >= Timer->DueTime.QuadPart) + if ((ULONGLONG)InterruptTime.QuadPart >= + Timer->DueTime.QuadPart) { /* It did, so we don't need to wait */ WaitStatus = STATUS_TIMEOUT; @@ -472,7 +515,7 @@ KeWaitForSingleObject(IN PVOID Object, if (Timeout) { /* Insert it */ - KiInsertWaitTimer(Timer); + KxInsertTimer(Timer, Hand); } else { @@ -538,7 +581,7 @@ KeWaitForMultipleObjects(IN ULONG Count, BOOLEAN Swappable; PLARGE_INTEGER OriginalDueTime = Timeout; LARGE_INTEGER DueTime, NewDueTime, InterruptTime; - ULONG Index; + ULONG Index, Hand = 0; /* Make sure the Wait Count is valid */ if (!WaitBlockArray) @@ -547,7 +590,7 @@ KeWaitForMultipleObjects(IN ULONG Count, if (Count > THREAD_WAIT_OBJECTS) { /* Bugcheck */ - KEBUGCHECK(MAXIMUM_WAIT_OBJECTS_EXCEEDED); + KeBugCheck(MAXIMUM_WAIT_OBJECTS_EXCEEDED); } /* Use the Thread's Wait Block */ @@ -559,7 +602,7 @@ KeWaitForMultipleObjects(IN ULONG Count, if (Count > MAXIMUM_WAIT_OBJECTS) { /* Bugcheck */ - KEBUGCHECK(MAXIMUM_WAIT_OBJECTS_EXCEEDED); + KeBugCheck(MAXIMUM_WAIT_OBJECTS_EXCEEDED); } } @@ -571,6 +614,12 @@ KeWaitForMultipleObjects(IN ULONG Count, /* Otherwise, we already have the lock, so initialize the wait */ Thread->WaitNext = FALSE; + /* Note that KxMultiThreadWait is a macro, defined in ke_x.h, that */ + /* uses (and modifies some of) the following local */ + /* variables: */ + /* Thread, Index, WaitBlock, Timer, Timeout, Hand and Swappable. */ + /* If it looks like this code doesn't actually wait for any objects */ + /* at all, it's because the setup is done by that macro. */ KxMultiThreadWait(); /* Start wait loop */ @@ -626,7 +675,7 @@ KeWaitForMultipleObjects(IN ULONG Count, else if (CurrentObject->Header.SignalState > 0) { /* Another signaled object, unwait and return */ - KiSatisfyNonMutantWait(CurrentObject, Thread); + KiSatisfyNonMutantWait(CurrentObject); WaitStatus = Index; goto DontWait; } @@ -649,7 +698,7 @@ KeWaitForMultipleObjects(IN ULONG Count, { /* Check if it has an invalid count */ if ((Thread == CurrentObject->OwnerThread) && - (CurrentObject->Header.SignalState == MINLONG)) + (CurrentObject->Header.SignalState == (LONG)MINLONG)) { /* Raise an exception */ KiReleaseDispatcherLock(Thread->WaitIrql); @@ -702,7 +751,8 @@ KeWaitForMultipleObjects(IN ULONG Count, { /* Check if the timer expired */ InterruptTime.QuadPart = KeQueryInterruptTime(); - if (InterruptTime.QuadPart >= Timer->DueTime.QuadPart) + if ((ULONGLONG)InterruptTime.QuadPart >= + Timer->DueTime.QuadPart) { /* It did, so we don't need to wait */ WaitStatus = STATUS_TIMEOUT; @@ -748,7 +798,7 @@ KeWaitForMultipleObjects(IN ULONG Count, if (Timeout) { /* Insert it */ - KiInsertWaitTimer(Timer); + KxInsertTimer(Timer, Hand); } else { @@ -799,25 +849,24 @@ NtDelayExecution(IN BOOLEAN Alertable, { KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); LARGE_INTEGER SafeInterval; - NTSTATUS Status = STATUS_SUCCESS; + NTSTATUS Status; /* Check the previous mode */ - if(PreviousMode != KernelMode) + if (PreviousMode != KernelMode) { /* Enter SEH for probing */ - _SEH_TRY + _SEH2_TRY { /* Probe and capture the time out */ SafeInterval = ProbeForReadLargeInteger(DelayInterval); DelayInterval = &SafeInterval; } - _SEH_HANDLE + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { - /* Get SEH exception */ - Status = _SEH_GetExceptionCode(); + /* Return the exception code */ + _SEH2_YIELD(return _SEH2_GetExceptionCode()); } - _SEH_END; - if (!NT_SUCCESS(Status)) return Status; + _SEH2_END; } /* Call the Kernel Function */