ULONG KiMinimumDpcRate = 3;
ULONG KiAdjustDpcThreshold = 20;
ULONG KiIdealDpcRate = 20;
+BOOLEAN KeThreadDpcEnable;
KMUTEX KiGenericCallDpcMutex;
/* PRIVATE FUNCTIONS *********************************************************/
+//
+// This routine executes at the end of a thread's quantum.
+// If the thread's quantum has expired, then a new thread is attempted
+// to be scheduled.
+//
+// If no candidate thread has been found, the routine will return, otherwise
+// it will swap contexts to the next scheduled thread.
+//
VOID
NTAPI
KiQuantumEnd(VOID)
{
PKPRCB Prcb = KeGetCurrentPrcb();
- PKTHREAD CurrentThread = KeGetCurrentThread();
- KIRQL OldIrql;
- PKPROCESS Process;
- KPRIORITY OldPriority;
- KPRIORITY NewPriority;
+ PKTHREAD NextThread, Thread = Prcb->CurrentThread;
/* Check if a DPC Event was requested to be signaled */
if (InterlockedExchange(&Prcb->DpcSetEventRequest, 0))
KeSetEvent(&Prcb->DpcEvent, 0, 0);
}
- /* Lock dispatcher */
- OldIrql = KeRaiseIrqlToSynchLevel();
- ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL);
-
- /* Get the Thread's Process */
- Process = CurrentThread->ApcState.Process;
+ /* Raise to synchronization level and lock the PRCB and thread */
+ KeRaiseIrqlToSynchLevel();
+ KiAcquireThreadLock(Thread);
+ KiAcquirePrcbLock(Prcb);
/* Check if Quantum expired */
- if (CurrentThread->Quantum <= 0)
+ if (Thread->Quantum <= 0)
{
- /* Reset the new Quantum */
- CurrentThread->Quantum = CurrentThread->QuantumReset;
-
- /* Calculate new priority */
- OldPriority = CurrentThread->Priority;
- if (OldPriority < LOW_REALTIME_PRIORITY)
+ /* Make sure that we're not real-time or without a quantum */
+ if ((Thread->Priority < LOW_REALTIME_PRIORITY) &&
+ !(Thread->ApcState.Process->DisableQuantum))
{
- /* Set the New Priority and add the Priority Decrement */
- NewPriority = OldPriority - CurrentThread->PriorityDecrement - 1;
-
- /* Don't go out of bounds */
- if (NewPriority < CurrentThread->BasePriority)
- {
- NewPriority = CurrentThread->BasePriority;
- }
+ /* Reset the new Quantum */
+ Thread->Quantum = Thread->QuantumReset;
- /* Reset the priority decrement */
- CurrentThread->PriorityDecrement = 0;
+ /* Calculate new priority */
+ Thread->Priority = KiComputeNewPriority(Thread, 1);
- /* Set a new priority if needed */
- if (OldPriority != NewPriority)
+ /* Check if a new thread is scheduled */
+ if (!Prcb->NextThread)
{
- /* Set new Priority */
- BOOLEAN Dummy; /* <- This is a hack anyways... */
- KiSetPriorityThread(CurrentThread, NewPriority, &Dummy);
+#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
{
- /* Queue new thread if none is already */
- if (!Prcb->NextThread)
- {
- /* FIXME: Schedule a New Thread, when ROS will have NT Scheduler */
- }
- else
- {
- /* Make the current thread non-premeptive if a new thread is queued */
- CurrentThread->Preempted = FALSE;
- }
+ /* Otherwise, make sure that this thread doesn't get preempted */
+ Thread->Preempted = FALSE;
}
}
else
{
- /* Set the Quantum back to Maximum */
- //if (CurrentThread->DisableQuantum) {
- // CurrentThread->Quantum = MAX_QUANTUM;
- //}
+ /* Otherwise, set maximum quantum */
+ Thread->Quantum = MAX_QUANTUM;
}
}
- /* Dispatch the Thread */
+ /* Release the thread lock */
+ KiReleaseThreadLock(Thread);
+
+ /* Check if there's no thread scheduled */
+ if (!Prcb->NextThread)
+ {
+ /* Just leave now */
+ KiReleasePrcbLock(Prcb);
+ KeLowerIrql(DISPATCH_LEVEL);
+ return;
+ }
+
+ /* Get the next thread now */
+ NextThread = Prcb->NextThread;
+
+ /* Set current thread's swap busy to true */
+ KiSetThreadSwapBusy(Thread);
+
+ /* Switch threads in PRCB */
+ Prcb->NextThread = NULL;
+ Prcb->CurrentThread = NextThread;
+
+ /* Set thread to running and the switch reason to Quantum End */
+ NextThread->State = Running;
+ Thread->WaitReason = WrQuantumEnd;
+
+ /* Queue it on the ready lists */
+ KxQueueReadyThread(Thread, Prcb);
+
+ /* Set wait IRQL to APC_LEVEL */
+ Thread->WaitIrql = APC_LEVEL;
+
+ /* Swap threads */
+ KiSwapContext(Thread, NextThread);
+
+ /* Lower IRQL back to DISPATCH_LEVEL */
KeLowerIrql(DISPATCH_LEVEL);
- KiDispatchThread(Ready);
}
VOID
KefReleaseSpinLockFromDpcLevel(&DpcData->DpcLock);
/* Re-enable interrupts */
- Ke386EnableInterrupts();
+ _enable();
/* Call the DPC */
DeferredRoutine(Dpc,
ASSERT_IRQL(DISPATCH_LEVEL);
/* Disable interrupts and keep looping */
- Ke386DisableInterrupts();
+ _disable();
}
else
{
}
/* 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];
if (&Prcb->DpcData[DPC_THREADED].DpcListHead == &DpcData->DpcListHead)
{
/* Make sure a threaded DPC isn't already active */
- if (!(Prcb->DpcThreadActive) && (!Prcb->DpcThreadRequested))
+ if (!(Prcb->DpcThreadActive) && !(Prcb->DpcThreadRequested))
{
/* FIXME: Setup Threaded DPC */
ASSERT(FALSE);
else
{
/* Make sure a DPC isn't executing already */
- if ((!Prcb->DpcRoutineActive) && (!Prcb->DpcInterruptRequested))
+ if (!(Prcb->DpcRoutineActive) && !(Prcb->DpcInterruptRequested))
{
/* Check if this is the same CPU */
if (Prcb != CurrentPrcb)
if (((Dpc->Importance == HighImportance) ||
(DpcData->DpcQueueDepth >=
Prcb->MaximumDpcQueueDepth)) &&
- (!(AFFINITY_MASK(Cpu) & IdleProcessorMask) ||
+ (!(AFFINITY_MASK(Cpu) & KiIdleSummary) ||
(Prcb->Sleeping)))
{
/* Set interrupt requested */
ASSERT_DPC(Dpc);
/* Disable interrupts */
- Ke386DisableInterrupts();
+ _disable();
/* Get DPC data and type */
DpcType = Dpc->Type;
}
/* Re-enable interrupts */
- Ke386EnableInterrupts();
+ _enable();
/* Return if the DPC was in the queue or not */
return DpcData ? TRUE : FALSE;