From c696d665327138ddab1492440a71207d835c00c7 Mon Sep 17 00:00:00 2001 From: Alex Ionescu Date: Wed, 17 Jan 2007 01:56:15 +0000 Subject: [PATCH] - Simplify KiSelectReadyThread. - Disable KiSetAffinityThread to do nothing else but change affinity instead of doing re-scheduling (temporary change). - Cleanup KiQuantumEnd to prepare for new scheduler. - Fix up a large bug in KeInsertQueueDpc which was making every DPC become a Threaded DPC due to a bad assignment-instead-of-compare. - Copy KiSelectNextThread for new scheduler branch, without SMT support. - Fix a bug in KiAdjustQuantumThread under new scheduler. - Re-implement KiSetPriorityThread under new scheduler, leave hacks for current scheduler support. - Remove old testing assert from KiExitDispatcher. svn path=/trunk/; revision=25491 --- reactos/ntoskrnl/include/internal/ke.h | 7 +- reactos/ntoskrnl/include/internal/ke_x.h | 10 +- reactos/ntoskrnl/ke/dpc.c | 24 +- reactos/ntoskrnl/ke/thrdobj.c | 18 +- reactos/ntoskrnl/ke/thrdschd.c | 342 +++++++++++++++-------- reactos/ntoskrnl/ke/wait.c | 4 - 6 files changed, 258 insertions(+), 147 deletions(-) diff --git a/reactos/ntoskrnl/include/internal/ke.h b/reactos/ntoskrnl/include/internal/ke.h index 447c26aeec7..d8f38c0b848 100644 --- a/reactos/ntoskrnl/include/internal/ke.h +++ b/reactos/ntoskrnl/include/internal/ke.h @@ -223,15 +223,14 @@ NTAPI KiDeferredReadyThread(IN PKTHREAD Thread); KAFFINITY -NTAPI +FASTCALL KiSetAffinityThread( IN PKTHREAD Thread, - IN KAFFINITY Affinity, - IN PBOOLEAN Released // hack + IN KAFFINITY Affinity ); PKTHREAD -NTAPI +FASTCALL KiSelectNextThread( IN PKPRCB Prcb ); diff --git a/reactos/ntoskrnl/include/internal/ke_x.h b/reactos/ntoskrnl/include/internal/ke_x.h index d2d2415ba51..69ecd58b80b 100644 --- a/reactos/ntoskrnl/include/internal/ke_x.h +++ b/reactos/ntoskrnl/include/internal/ke_x.h @@ -1259,12 +1259,12 @@ KiSelectReadyThread(IN KPRIORITY Priority, { LONG PriorityMask, PrioritySet, HighPriority; PLIST_ENTRY ListEntry; - PKTHREAD Thread; + PKTHREAD Thread = NULL; /* Save the current mask and get the priority set for the CPU */ PriorityMask = Priority; PrioritySet = Prcb->ReadySummary >> (UCHAR)Priority; - if (!PrioritySet) return NULL; + if (!PrioritySet) goto Quickie; /* Get the highest priority possible */ BitScanReverse((PULONG)&HighPriority, PrioritySet); @@ -1275,7 +1275,7 @@ KiSelectReadyThread(IN KPRIORITY Priority, ASSERT(IsListEmpty(&Prcb->DispatcherReadyListHead[HighPriority]) == FALSE); /* Get the first thread on the list */ - ListEntry = &Prcb->DispatcherReadyListHead[HighPriority]; + ListEntry = Prcb->DispatcherReadyListHead[HighPriority].Flink; Thread = CONTAINING_RECORD(ListEntry, KTHREAD, WaitListEntry); /* Make sure this thread is here for a reason */ @@ -1284,14 +1284,14 @@ KiSelectReadyThread(IN KPRIORITY Priority, ASSERT(Thread->NextProcessor == Prcb->Number); /* Remove it from the list */ - RemoveEntryList(&Thread->WaitListEntry); - if (IsListEmpty(&Thread->WaitListEntry)) + if (RemoveEntryList(&Thread->WaitListEntry)) { /* The list is empty now, reset the ready summary */ Prcb->ReadySummary ^= PRIORITY_MASK(HighPriority); } /* Sanity check and return the thread */ +Quickie: ASSERT((Thread == NULL) || (Thread->BasePriority == 0) || (Thread->Priority != 0)); diff --git a/reactos/ntoskrnl/ke/dpc.c b/reactos/ntoskrnl/ke/dpc.c index 51a40308f3d..2640ca0f6b6 100644 --- a/reactos/ntoskrnl/ke/dpc.c +++ b/reactos/ntoskrnl/ke/dpc.c @@ -70,7 +70,22 @@ KiQuantumEnd(VOID) /* Check if a new thread is scheduled */ if (!Prcb->NextThread) { - /* FIXME: TODO. Add code from new scheduler */ +#ifdef NEW_SCHEDULER + /* Get a new ready thread */ + NextThread = KiSelectReadyThread(Thread->Priority, Prcb); + if (NextThread) + { + /* Found one, set it on standby */ + NextThread->Standby; + Prcb->NextThread = NewThread; + } +#else + /* Just leave now */ + KiReleasePrcbLock(Prcb); + KeLowerIrql(DISPATCH_LEVEL); + KiDispatchThread(Ready); + return; +#endif } else { @@ -94,14 +109,9 @@ KiQuantumEnd(VOID) /* Just leave now */ KiReleasePrcbLock(Prcb); KeLowerIrql(DISPATCH_LEVEL); - KiDispatchThread(Ready); // FIXME: ROS return; } - /* This shouldn't happen on ROS yet */ - DPRINT1("The impossible happened - Tell Alex\n"); - ASSERT(FALSE); - /* Get the next thread now */ NextThread = Prcb->NextThread; @@ -296,7 +306,7 @@ KeInsertQueueDpc(IN PKDPC Dpc, } /* Check if this is a threaded DPC and threaded DPCs are enabled */ - if ((Dpc->Type = ThreadedDpcObject) && (Prcb->ThreadDpcEnable)) + if ((Dpc->Type == ThreadedDpcObject) && (Prcb->ThreadDpcEnable)) { /* Then use the threaded data */ DpcData = &Prcb->DpcData[DPC_THREADED]; diff --git a/reactos/ntoskrnl/ke/thrdobj.c b/reactos/ntoskrnl/ke/thrdobj.c index aa48d29c1c6..5033dc6ec5b 100644 --- a/reactos/ntoskrnl/ke/thrdobj.c +++ b/reactos/ntoskrnl/ke/thrdobj.c @@ -1252,7 +1252,6 @@ KeSetAffinityThread(IN PKTHREAD Thread, { KIRQL OldIrql; KAFFINITY OldAffinity; - BOOLEAN Released; ASSERT_THREAD(Thread); ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); @@ -1260,21 +1259,10 @@ KeSetAffinityThread(IN PKTHREAD Thread, OldIrql = KiAcquireDispatcherLock(); /* Call the internal function */ - OldAffinity = KiSetAffinityThread(Thread, Affinity, &Released); + OldAffinity = KiSetAffinityThread(Thread, Affinity); - /* Check if lock was released */ - if (!Released) - { - /* Release the dispatcher database */ - KiReleaseDispatcherLock(OldIrql); - } - else - { - /* Lower IRQL only */ - KeLowerIrql(OldIrql); - } - - /* Return old affinity */ + /* Release the dispatcher database and return old affinity */ + KiReleaseDispatcherLock(OldIrql); return OldAffinity; } diff --git a/reactos/ntoskrnl/ke/thrdschd.c b/reactos/ntoskrnl/ke/thrdschd.c index b8e97baf4ed..ffe3f5bba99 100644 --- a/reactos/ntoskrnl/ke/thrdschd.c +++ b/reactos/ntoskrnl/ke/thrdschd.c @@ -21,17 +21,6 @@ ULONG KiIdleSMTSummary; /* FUNCTIONS *****************************************************************/ -static -VOID -KiRequestReschedule(CCHAR Processor) -{ - PKPCR Pcr; - - Pcr = (PKPCR)(KPCR_BASE + Processor * PAGE_SIZE); - Pcr->Prcb->QuantumEnd = TRUE; - KiIpiSendRequest(1 << Processor, IPI_DPC); -} - static VOID KiInsertIntoThreadList(KPRIORITY Priority, @@ -166,6 +155,40 @@ KiDispatchThreadNoLock(ULONG NewThreadStatus) return FALSE; } +VOID +NTAPI +KiDeferredReadyThread(IN PKTHREAD Thread) +{ + /* FIXME: Not yet implemented */ + KEBUGCHECK(0); +} + +PKTHREAD +FASTCALL +KiSelectNextThread(IN PKPRCB Prcb) +{ + PKTHREAD Thread; + + /* Select a ready thread */ + Thread = KiSelectReadyThread(0, Prcb); + if (!Thread) + { + /* Didn't find any, get the current idle thread */ + Thread = Prcb->IdleThread; + + /* Enable idle scheduling */ + InterlockedOr(&KiIdleSummary, Prcb->SetMember); + Prcb->IdleSchedule = TRUE; + + /* FIXME: SMT support */ + } + + /* Sanity checks and return the thread */ + ASSERT(Thread != NULL); + ASSERT((Thread->BasePriority == 0) || (Thread->Priority != 0)); + return Thread; +} + NTSTATUS FASTCALL KiSwapThread(IN PKTHREAD CurrentThread, @@ -174,8 +197,12 @@ KiSwapThread(IN PKTHREAD CurrentThread, BOOLEAN ApcState; ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL); +#ifdef NEW_SCHEDULER + +#else /* Find a new thread to run */ ApcState = KiDispatchThreadNoLock(Waiting); +#endif /* Check if we need to deliver APCs */ if (ApcState) @@ -238,7 +265,7 @@ KiReadyThread(IN PKTHREAD Thread) else { /* Insert the thread on the deferred ready list */ -#if 0 +#ifdef NEW_SCHEDULER KiInsertDeferredReadyList(Thread); #else /* Insert the thread into the thread list */ @@ -249,7 +276,7 @@ KiReadyThread(IN PKTHREAD Thread) } VOID -STDCALL +NTAPI KiAdjustQuantumThread(IN PKTHREAD Thread) { PKPRCB Prcb = KeGetCurrentPrcb(); @@ -275,10 +302,14 @@ KiAdjustQuantumThread(IN PKTHREAD Thread) /* Check if there's no next thread scheduled */ if (!Prcb->NextThread) { - /* Select a new thread and set it on standby */ - NextThread = KiSelectNextThread(Prcb); - NextThread->State = Standby; - Prcb->NextThread = NextThread; + /* Select a ready thread and check if we found one */ + NextThread = KiSelectReadyThread(Thread->Priority, Prcb); + if (NextThread) + { + /* Set it on standby and switch to it */ + NextThread->State = Standby; + Prcb->NextThread = NextThread; + } } else { @@ -303,91 +334,213 @@ KiSetPriorityThread(IN PKTHREAD Thread, IN KPRIORITY Priority, OUT PBOOLEAN Released) { - KPRIORITY OldPriority = Thread->Priority; - ULONG Mask; - ULONG i; - PKPCR Pcr; + PKPRCB Prcb; + ULONG Processor; + BOOLEAN RequestInterrupt = FALSE; + KPRIORITY OldPriority; + PKTHREAD NewThread; ASSERT((Priority >= 0) && (Priority <= HIGH_PRIORITY)); /* Check if priority changed */ - if (OldPriority != Priority) + if (Thread->Priority != Priority) { - /* Set it */ - Thread->Priority = (SCHAR)Priority; - - /* Choose action based on thread's state */ - if (Thread->State == Ready) + /* Loop priority setting in case we need to start over */ + for (;;) { - /* Remove it from the current queue */ - KiRemoveFromThreadList(Thread); - - /* Re-insert it at its current priority */ - KiInsertIntoThreadList(Priority, Thread); - - /* Check if the old priority was lower */ - if (KeGetCurrentThread()->Priority < Priority) + /* Choose action based on thread's state */ + if (Thread->State == Ready) { - /* Dispatch it immediately */ - KiDispatchThreadNoLock(Ready); - *Released = TRUE; - return; - } - } - else if (Thread->State == Running) - { - /* Check if the new priority is lower */ - if (Priority < OldPriority) - { - /* Check for threads with a higher priority */ - Mask = ~((1 << (Priority + 1)) - 1); - if (PriorityListMask & Mask) + /* Make sure we're not on the ready queue */ + if (Thread->ProcessReadyQueue) { - /* Found a thread, is it us? */ - if (Thread == KeGetCurrentThread()) + /* Get the PRCB for the thread and lock it */ + Processor = Thread->NextProcessor; + Prcb = KiProcessorBlock[Processor]; + KiAcquirePrcbLock(Prcb); + + /* Make sure the thread is still ready and on this CPU */ + if ((Thread->State == Ready) && + (Thread->NextProcessor == Prcb->Number)) { - /* Dispatch us */ + /* Sanity check */ + ASSERT((Prcb->ReadySummary & + PRIORITY_MASK(Thread->Priority))); + + /* Remove it from the current queue */ +#ifdef NEW_SCHEDULER + if (RemoveEntryList(&Thread->WaitListEntry)) + { + /* Update the ready summary */ + Prcb->ReadySummary ^= PRIORITY_MASK(Thread->Priority); + } +#else + KiRemoveFromThreadList(Thread); +#endif + + /* Update priority */ + Thread->Priority = (SCHAR)Priority; + + /* Re-insert it at its current priority */ +#ifndef NEW_SCHEDULER + KiInsertIntoThreadList(Priority, Thread); KiDispatchThreadNoLock(Ready); *Released = TRUE; - return; - } +#else + KiInsertDeferredReadyList(Thread); +#endif + + /* Release the PRCB Lock */ + KiReleasePrcbLock(Prcb); + } else { - /* Loop every CPU */ - for (i = 0; i < KeNumberProcessors; i++) - { - /* Get the PCR for this CPU */ - Pcr = (PKPCR)(KPCR_BASE + i * PAGE_SIZE); + /* Release the lock and loop again */ + KEBUGCHECK(0); + KiReleasePrcbLock(Prcb); + continue; + } + } + else + { + /* It's already on the ready queue, just update priority */ + Thread->Priority = (SCHAR)Priority; + } + } + else if (Thread->State == Standby) + { + /* Get the PRCB for the thread and lock it */ + KEBUGCHECK(0); + Processor = Thread->NextProcessor; + Prcb = KiProcessorBlock[Processor]; + KiAcquirePrcbLock(Prcb); - /* Reschedule if the new one is already on a CPU */ - if (Pcr->Prcb->CurrentThread == Thread) + /* Check if we're still the next thread to run */ + if (Thread == Prcb->NextThread) + { + /* Get the old priority and update ours */ + OldPriority = Thread->Priority; + Thread->Priority = (SCHAR)Priority; + + /* Check if there was a change */ + if (Priority < OldPriority) + { + /* Find a new thread */ + NewThread = KiSelectReadyThread(Priority + 1, Prcb); + if (NewThread) + { + /* Found a new one, set it on standby */ + NewThread->State = Standby; + Prcb->NextThread = NewThread; + + /* Dispatch our thread */ + KiInsertDeferredReadyList(Thread); + } + } + + /* Release the PRCB lock */ + KiReleasePrcbLock(Prcb); + } + else + { + /* Release the lock and try again */ + KiReleasePrcbLock(Prcb); + continue; + } + } + else if (Thread->State == Running) + { + /* Get the PRCB for the thread and lock it */ + Processor = Thread->NextProcessor; + Prcb = KiProcessorBlock[Processor]; + KiAcquirePrcbLock(Prcb); + + /* Check if we're still the current thread running */ + if (Thread == Prcb->CurrentThread) + { + /* Get the old priority and update ours */ + OldPriority = Thread->Priority; + Thread->Priority = (SCHAR)Priority; + + /* Check if there was a change and there's no new thread */ + if ((Priority < OldPriority) && !(Prcb->NextThread)) + { +#ifdef NEW_SCHEDULER + /* Find a new thread */ + NewThread = KiSelectReadyThread(Priority + 1, Prcb); + if (NewThread) + { + /* Found a new one, set it on standby */ + NewThread->State = Standby; + Prcb->NextThread = NewThread; + + /* Request an interrupt */ + RequestInterrupt = TRUE; + } +#else + /* Check for threads with a higher priority */ + if (PriorityListMask & ~((1 << (Priority + 1)) - 1)) + { + /* Found a thread, is it us? */ + if (Thread == KeGetCurrentThread()) { - KiReleaseDispatcherLockFromDpcLevel(); - KiRequestReschedule(i); + /* Dispatch us */ + KiDispatchThreadNoLock(Ready); *Released = TRUE; return; } } +#endif + } + + /* Release the lock and check if we need an interrupt */ + KiReleasePrcbLock(Prcb); + if (RequestInterrupt) + { + /* Check if we're running on another CPU */ + if (KeGetCurrentProcessorNumber() != Processor) + { + /* We are, send an IPI */ + KiIpiSendRequest(AFFINITY_MASK(Processor), IPI_DPC); + } } } + else + { + /* Thread changed, release lock and restart */ + KiReleasePrcbLock(Prcb); + continue; + } } + else if (Thread->State == DeferredReady) + { + /* FIXME: TODO */ + DPRINT1("Deferred state not yet supported\n"); + KEBUGCHECK(0); + } + else + { + /* Any other state, just change priority */ + Thread->Priority = (SCHAR)Priority; + } + + /* If we got here, then thread state was consistent, so bail out */ + break; } } /* Return to caller */ *Released = FALSE; - return; } KAFFINITY -NTAPI +FASTCALL KiSetAffinityThread(IN PKTHREAD Thread, - IN KAFFINITY Affinity, - PBOOLEAN Released) + IN KAFFINITY Affinity) { KAFFINITY OldAffinity; - ULONG ProcessorMask; - CCHAR i; - PKPCR Pcr; + + /* Get the current affinity */ + OldAffinity = Thread->UserAffinity; /* Make sure that the affinity is valid */ if (((Affinity & Thread->ApcState.Process->Affinity) != (Affinity)) || @@ -397,52 +550,17 @@ KiSetAffinityThread(IN PKTHREAD Thread, KeBugCheck(INVALID_AFFINITY_SET); } - /* Get the old affinity */ - OldAffinity = Thread->UserAffinity; - + /* Update the new affinity */ Thread->UserAffinity = Affinity; - if (Thread->SystemAffinityActive == FALSE) { - - Thread->Affinity = Affinity; - - if (Thread->State == Running) { - - ProcessorMask = 1 << KeGetCurrentProcessorNumber(); - if (Thread == KeGetCurrentThread()) { - - if (!(Affinity & ProcessorMask)) { - - KiDispatchThreadNoLock(Ready); - *Released = TRUE; - return OldAffinity; - } - - } else { - - for (i = 0; i < KeNumberProcessors; i++) { - - Pcr = (PKPCR)(KPCR_BASE + i * PAGE_SIZE); - if (Pcr->Prcb->CurrentThread == Thread) { - - if (!(Affinity & ProcessorMask)) { - - KiReleaseDispatcherLockFromDpcLevel(); - KiRequestReschedule(i); - *Released = TRUE; - return OldAffinity; - } - - break; - } - } - - ASSERT (i < KeNumberProcessors); - } - } + /* Check if system affinity is disabled */ + if (!Thread->SystemAffinityActive) + { + /* FIXME: TODO */ + DPRINT1("Affinity support disabled!\n"); } - *Released = FALSE; + /* Return the old affinity */ return OldAffinity; } diff --git a/reactos/ntoskrnl/ke/wait.c b/reactos/ntoskrnl/ke/wait.c index c1d863cdfb5..d118261d13a 100644 --- a/reactos/ntoskrnl/ke/wait.c +++ b/reactos/ntoskrnl/ke/wait.c @@ -183,10 +183,6 @@ KiExitDispatcher(IN KIRQL OldIrql) /* Make sure there's a new thread scheduled */ if (!Prcb->NextThread) goto Quickie; - /* This shouldn't happen on ROS yet */ - DPRINT1("The impossible happened - Tell Alex\n"); - ASSERT(FALSE); - /* Lock the PRCB */ KiAcquirePrcbLock(Prcb);