WIP [NTOS:KE/x64] Handle NewThread == OldThread in KiIdleLoop

This commit is contained in:
Timo Kreuzer 2024-12-10 19:26:02 +02:00
parent e118c6a769
commit 5faf6ed339
3 changed files with 47 additions and 9 deletions

View file

@ -158,14 +158,22 @@ KiIdleLoop(VOID)
/* The thread is now running */
NewThread->State = Running;
/* Clear idle summary bit */
InterlockedBitTestAndResetAffinity(&KiIdleSummary, Prcb->Number);
/* Check if we're actually running a different thread */
if (NewThread != OldThread)
{
/* Clear idle summary bit */
InterlockedBitTestAndResetAffinity(&KiIdleSummary, Prcb->Number);
/* Switch away from the idle thread */
KiSwapContext(APC_LEVEL, OldThread);
/* Switch away from the idle thread */
KiSwapContext(APC_LEVEL, OldThread);
/* Set idle summary bit */
InterlockedBitTestAndSetAffinity(&KiIdleSummary, Prcb->Number);
/* Set idle summary bit */
InterlockedBitTestAndSetAffinity(&KiIdleSummary, Prcb->Number);
}
else
{
NewThread->SwapBusy = FALSE;
}
#ifdef CONFIG_SMP
/* Go back to DISPATCH_LEVEL */

View file

@ -66,6 +66,17 @@ KiDpcInterruptHandler(VOID)
/* Acquire the PRCB lock */
KiAcquirePrcbLock(Prcb);
if (Prcb->NextThread == Prcb->CurrentThread)
{
__debugbreak();
/* This can happen, when the idle thread is running and a different
processor reschedules the thread */
ASSERT(Prcb->NextThread == Prcb->IdleThread);
Prcb->NextThread = NULL;
KiReleasePrcbLock(Prcb);
goto Exit;
}
/* Capture current thread data */
OldThread = Prcb->CurrentThread;
NewThread = Prcb->NextThread;
@ -78,7 +89,7 @@ KiDpcInterruptHandler(VOID)
NewThread->State = Running;
OldThread->WaitReason = WrDispatchInt;
/* Make the old thread ready */
/* Make the old thread ready (this releases the PRCB lock) */
KxQueueReadyThread(OldThread, Prcb);
/* Swap to the new thread */

View file

@ -485,8 +485,27 @@ KiSwapThread(IN PKTHREAD CurrentThread,
/* Save the wait IRQL */
WaitIrql = CurrentThread->WaitIrql;
/* Swap contexts */
ApcState = KiSwapContext(WaitIrql, CurrentThread);
#ifdef CONFIG_SMP
/* On SMP builds it is possible that the new thread is the old thread. */
if (NextThread == CurrentThread)
{
/* Unset SwapBusy */
CurrentThread->SwapBusy = FALSE;
/* Check for pending APCs */
if ((NextThread->ApcState.KernelApcPending) &&
(NextThread->SpecialApcDisable == FALSE) &&
(WaitIrql == PASSIVE_LEVEL))
{
ApcState = TRUE;
}
}
else
#endif
{
/* Swap contexts */
ApcState = KiSwapContext(WaitIrql, CurrentThread);
}
/* Get the wait status */
WaitStatus = CurrentThread->WaitStatus;