- 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
This commit is contained in:
Alex Ionescu 2007-01-17 01:56:15 +00:00
parent c15d054bad
commit c696d66532
6 changed files with 258 additions and 147 deletions

View file

@ -223,15 +223,14 @@ NTAPI
KiDeferredReadyThread(IN PKTHREAD Thread); KiDeferredReadyThread(IN PKTHREAD Thread);
KAFFINITY KAFFINITY
NTAPI FASTCALL
KiSetAffinityThread( KiSetAffinityThread(
IN PKTHREAD Thread, IN PKTHREAD Thread,
IN KAFFINITY Affinity, IN KAFFINITY Affinity
IN PBOOLEAN Released // hack
); );
PKTHREAD PKTHREAD
NTAPI FASTCALL
KiSelectNextThread( KiSelectNextThread(
IN PKPRCB Prcb IN PKPRCB Prcb
); );

View file

@ -1259,12 +1259,12 @@ KiSelectReadyThread(IN KPRIORITY Priority,
{ {
LONG PriorityMask, PrioritySet, HighPriority; LONG PriorityMask, PrioritySet, HighPriority;
PLIST_ENTRY ListEntry; PLIST_ENTRY ListEntry;
PKTHREAD Thread; PKTHREAD Thread = NULL;
/* Save the current mask and get the priority set for the CPU */ /* Save the current mask and get the priority set for the CPU */
PriorityMask = Priority; PriorityMask = Priority;
PrioritySet = Prcb->ReadySummary >> (UCHAR)Priority; PrioritySet = Prcb->ReadySummary >> (UCHAR)Priority;
if (!PrioritySet) return NULL; if (!PrioritySet) goto Quickie;
/* Get the highest priority possible */ /* Get the highest priority possible */
BitScanReverse((PULONG)&HighPriority, PrioritySet); BitScanReverse((PULONG)&HighPriority, PrioritySet);
@ -1275,7 +1275,7 @@ KiSelectReadyThread(IN KPRIORITY Priority,
ASSERT(IsListEmpty(&Prcb->DispatcherReadyListHead[HighPriority]) == FALSE); ASSERT(IsListEmpty(&Prcb->DispatcherReadyListHead[HighPriority]) == FALSE);
/* Get the first thread on the list */ /* Get the first thread on the list */
ListEntry = &Prcb->DispatcherReadyListHead[HighPriority]; ListEntry = Prcb->DispatcherReadyListHead[HighPriority].Flink;
Thread = CONTAINING_RECORD(ListEntry, KTHREAD, WaitListEntry); Thread = CONTAINING_RECORD(ListEntry, KTHREAD, WaitListEntry);
/* Make sure this thread is here for a reason */ /* Make sure this thread is here for a reason */
@ -1284,14 +1284,14 @@ KiSelectReadyThread(IN KPRIORITY Priority,
ASSERT(Thread->NextProcessor == Prcb->Number); ASSERT(Thread->NextProcessor == Prcb->Number);
/* Remove it from the list */ /* Remove it from the list */
RemoveEntryList(&Thread->WaitListEntry); if (RemoveEntryList(&Thread->WaitListEntry))
if (IsListEmpty(&Thread->WaitListEntry))
{ {
/* The list is empty now, reset the ready summary */ /* The list is empty now, reset the ready summary */
Prcb->ReadySummary ^= PRIORITY_MASK(HighPriority); Prcb->ReadySummary ^= PRIORITY_MASK(HighPriority);
} }
/* Sanity check and return the thread */ /* Sanity check and return the thread */
Quickie:
ASSERT((Thread == NULL) || ASSERT((Thread == NULL) ||
(Thread->BasePriority == 0) || (Thread->BasePriority == 0) ||
(Thread->Priority != 0)); (Thread->Priority != 0));

View file

@ -70,7 +70,22 @@ KiQuantumEnd(VOID)
/* Check if a new thread is scheduled */ /* Check if a new thread is scheduled */
if (!Prcb->NextThread) 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 else
{ {
@ -94,14 +109,9 @@ KiQuantumEnd(VOID)
/* Just leave now */ /* Just leave now */
KiReleasePrcbLock(Prcb); KiReleasePrcbLock(Prcb);
KeLowerIrql(DISPATCH_LEVEL); KeLowerIrql(DISPATCH_LEVEL);
KiDispatchThread(Ready); // FIXME: ROS
return; return;
} }
/* This shouldn't happen on ROS yet */
DPRINT1("The impossible happened - Tell Alex\n");
ASSERT(FALSE);
/* Get the next thread now */ /* Get the next thread now */
NextThread = Prcb->NextThread; NextThread = Prcb->NextThread;
@ -296,7 +306,7 @@ KeInsertQueueDpc(IN PKDPC Dpc,
} }
/* Check if this is a threaded DPC and threaded DPCs are enabled */ /* 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 */ /* Then use the threaded data */
DpcData = &Prcb->DpcData[DPC_THREADED]; DpcData = &Prcb->DpcData[DPC_THREADED];

View file

@ -1252,7 +1252,6 @@ KeSetAffinityThread(IN PKTHREAD Thread,
{ {
KIRQL OldIrql; KIRQL OldIrql;
KAFFINITY OldAffinity; KAFFINITY OldAffinity;
BOOLEAN Released;
ASSERT_THREAD(Thread); ASSERT_THREAD(Thread);
ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
@ -1260,21 +1259,10 @@ KeSetAffinityThread(IN PKTHREAD Thread,
OldIrql = KiAcquireDispatcherLock(); OldIrql = KiAcquireDispatcherLock();
/* Call the internal function */ /* Call the internal function */
OldAffinity = KiSetAffinityThread(Thread, Affinity, &Released); OldAffinity = KiSetAffinityThread(Thread, Affinity);
/* Check if lock was released */ /* Release the dispatcher database and return old affinity */
if (!Released) KiReleaseDispatcherLock(OldIrql);
{
/* Release the dispatcher database */
KiReleaseDispatcherLock(OldIrql);
}
else
{
/* Lower IRQL only */
KeLowerIrql(OldIrql);
}
/* Return old affinity */
return OldAffinity; return OldAffinity;
} }

View file

@ -21,17 +21,6 @@ ULONG KiIdleSMTSummary;
/* FUNCTIONS *****************************************************************/ /* 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 static
VOID VOID
KiInsertIntoThreadList(KPRIORITY Priority, KiInsertIntoThreadList(KPRIORITY Priority,
@ -166,6 +155,40 @@ KiDispatchThreadNoLock(ULONG NewThreadStatus)
return FALSE; 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 NTSTATUS
FASTCALL FASTCALL
KiSwapThread(IN PKTHREAD CurrentThread, KiSwapThread(IN PKTHREAD CurrentThread,
@ -174,8 +197,12 @@ KiSwapThread(IN PKTHREAD CurrentThread,
BOOLEAN ApcState; BOOLEAN ApcState;
ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL); ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL);
#ifdef NEW_SCHEDULER
#else
/* Find a new thread to run */ /* Find a new thread to run */
ApcState = KiDispatchThreadNoLock(Waiting); ApcState = KiDispatchThreadNoLock(Waiting);
#endif
/* Check if we need to deliver APCs */ /* Check if we need to deliver APCs */
if (ApcState) if (ApcState)
@ -238,7 +265,7 @@ KiReadyThread(IN PKTHREAD Thread)
else else
{ {
/* Insert the thread on the deferred ready list */ /* Insert the thread on the deferred ready list */
#if 0 #ifdef NEW_SCHEDULER
KiInsertDeferredReadyList(Thread); KiInsertDeferredReadyList(Thread);
#else #else
/* Insert the thread into the thread list */ /* Insert the thread into the thread list */
@ -249,7 +276,7 @@ KiReadyThread(IN PKTHREAD Thread)
} }
VOID VOID
STDCALL NTAPI
KiAdjustQuantumThread(IN PKTHREAD Thread) KiAdjustQuantumThread(IN PKTHREAD Thread)
{ {
PKPRCB Prcb = KeGetCurrentPrcb(); PKPRCB Prcb = KeGetCurrentPrcb();
@ -275,10 +302,14 @@ KiAdjustQuantumThread(IN PKTHREAD Thread)
/* Check if there's no next thread scheduled */ /* Check if there's no next thread scheduled */
if (!Prcb->NextThread) if (!Prcb->NextThread)
{ {
/* Select a new thread and set it on standby */ /* Select a ready thread and check if we found one */
NextThread = KiSelectNextThread(Prcb); NextThread = KiSelectReadyThread(Thread->Priority, Prcb);
NextThread->State = Standby; if (NextThread)
Prcb->NextThread = NextThread; {
/* Set it on standby and switch to it */
NextThread->State = Standby;
Prcb->NextThread = NextThread;
}
} }
else else
{ {
@ -303,91 +334,213 @@ KiSetPriorityThread(IN PKTHREAD Thread,
IN KPRIORITY Priority, IN KPRIORITY Priority,
OUT PBOOLEAN Released) OUT PBOOLEAN Released)
{ {
KPRIORITY OldPriority = Thread->Priority; PKPRCB Prcb;
ULONG Mask; ULONG Processor;
ULONG i; BOOLEAN RequestInterrupt = FALSE;
PKPCR Pcr; KPRIORITY OldPriority;
PKTHREAD NewThread;
ASSERT((Priority >= 0) && (Priority <= HIGH_PRIORITY)); ASSERT((Priority >= 0) && (Priority <= HIGH_PRIORITY));
/* Check if priority changed */ /* Check if priority changed */
if (OldPriority != Priority) if (Thread->Priority != Priority)
{ {
/* Set it */ /* Loop priority setting in case we need to start over */
Thread->Priority = (SCHAR)Priority; for (;;)
/* Choose action based on thread's state */
if (Thread->State == Ready)
{ {
/* Remove it from the current queue */ /* Choose action based on thread's state */
KiRemoveFromThreadList(Thread); if (Thread->State == Ready)
/* Re-insert it at its current priority */
KiInsertIntoThreadList(Priority, Thread);
/* Check if the old priority was lower */
if (KeGetCurrentThread()->Priority < Priority)
{ {
/* Dispatch it immediately */ /* Make sure we're not on the ready queue */
KiDispatchThreadNoLock(Ready); if (Thread->ProcessReadyQueue)
*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)
{ {
/* Found a thread, is it us? */ /* Get the PRCB for the thread and lock it */
if (Thread == KeGetCurrentThread()) 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); KiDispatchThreadNoLock(Ready);
*Released = TRUE; *Released = TRUE;
return; #else
} KiInsertDeferredReadyList(Thread);
#endif
/* Release the PRCB Lock */
KiReleasePrcbLock(Prcb);
}
else else
{ {
/* Loop every CPU */ /* Release the lock and loop again */
for (i = 0; i < KeNumberProcessors; i++) KEBUGCHECK(0);
{ KiReleasePrcbLock(Prcb);
/* Get the PCR for this CPU */ continue;
Pcr = (PKPCR)(KPCR_BASE + i * PAGE_SIZE); }
}
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 */ /* Check if we're still the next thread to run */
if (Pcr->Prcb->CurrentThread == Thread) 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(); /* Dispatch us */
KiRequestReschedule(i); KiDispatchThreadNoLock(Ready);
*Released = TRUE; *Released = TRUE;
return; 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 */ /* Return to caller */
*Released = FALSE; *Released = FALSE;
return;
} }
KAFFINITY KAFFINITY
NTAPI FASTCALL
KiSetAffinityThread(IN PKTHREAD Thread, KiSetAffinityThread(IN PKTHREAD Thread,
IN KAFFINITY Affinity, IN KAFFINITY Affinity)
PBOOLEAN Released)
{ {
KAFFINITY OldAffinity; KAFFINITY OldAffinity;
ULONG ProcessorMask;
CCHAR i; /* Get the current affinity */
PKPCR Pcr; OldAffinity = Thread->UserAffinity;
/* Make sure that the affinity is valid */ /* Make sure that the affinity is valid */
if (((Affinity & Thread->ApcState.Process->Affinity) != (Affinity)) || if (((Affinity & Thread->ApcState.Process->Affinity) != (Affinity)) ||
@ -397,52 +550,17 @@ KiSetAffinityThread(IN PKTHREAD Thread,
KeBugCheck(INVALID_AFFINITY_SET); KeBugCheck(INVALID_AFFINITY_SET);
} }
/* Get the old affinity */ /* Update the new affinity */
OldAffinity = Thread->UserAffinity;
Thread->UserAffinity = Affinity; Thread->UserAffinity = Affinity;
if (Thread->SystemAffinityActive == FALSE) { /* Check if system affinity is disabled */
if (!Thread->SystemAffinityActive)
Thread->Affinity = Affinity; {
/* FIXME: TODO */
if (Thread->State == Running) { DPRINT1("Affinity support disabled!\n");
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);
}
}
} }
*Released = FALSE; /* Return the old affinity */
return OldAffinity; return OldAffinity;
} }

View file

@ -183,10 +183,6 @@ KiExitDispatcher(IN KIRQL OldIrql)
/* Make sure there's a new thread scheduled */ /* Make sure there's a new thread scheduled */
if (!Prcb->NextThread) goto Quickie; if (!Prcb->NextThread) goto Quickie;
/* This shouldn't happen on ROS yet */
DPRINT1("The impossible happened - Tell Alex\n");
ASSERT(FALSE);
/* Lock the PRCB */ /* Lock the PRCB */
KiAcquirePrcbLock(Prcb); KiAcquirePrcbLock(Prcb);