- Simplify KiSelectReadyThread.
[reactos.git] / reactos / ntoskrnl / ke / dpc.c
index 9500adb..2640ca0 100644 (file)
@@ -22,20 +22,25 @@ ULONG KiMaximumDpcQueueDepth = 4;
 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))
@@ -44,68 +49,94 @@ KiQuantumEnd(VOID)
         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
@@ -161,7 +192,7 @@ KiRetireDpcList(IN PKPRCB Prcb)
                 KefReleaseSpinLockFromDpcLevel(&DpcData->DpcLock);
 
                 /* Re-enable interrupts */
-                Ke386EnableInterrupts();
+                _enable();
 
                 /* Call the DPC */
                 DeferredRoutine(Dpc,
@@ -171,7 +202,7 @@ KiRetireDpcList(IN PKPRCB Prcb)
                 ASSERT_IRQL(DISPATCH_LEVEL);
 
                 /* Disable interrupts and keep looping */
-                Ke386DisableInterrupts();
+                _disable();
             }
             else
             {
@@ -275,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];
@@ -315,7 +346,7 @@ KeInsertQueueDpc(IN PKDPC Dpc,
         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);
@@ -324,7 +355,7 @@ KeInsertQueueDpc(IN PKDPC Dpc,
         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)
@@ -337,7 +368,7 @@ KeInsertQueueDpc(IN PKDPC Dpc,
                     if (((Dpc->Importance == HighImportance) ||
                         (DpcData->DpcQueueDepth >=
                          Prcb->MaximumDpcQueueDepth)) &&
-                        (!(AFFINITY_MASK(Cpu) & IdleProcessorMask) ||
+                        (!(AFFINITY_MASK(Cpu) & KiIdleSummary) ||
                          (Prcb->Sleeping)))
                     {
                         /* Set interrupt requested */
@@ -402,7 +433,7 @@ KeRemoveQueueDpc(IN PKDPC Dpc)
     ASSERT_DPC(Dpc);
 
     /* Disable interrupts */
-    Ke386DisableInterrupts();
+    _disable();
 
     /* Get DPC data and type */
     DpcType = Dpc->Type;
@@ -426,7 +457,7 @@ KeRemoveQueueDpc(IN PKDPC Dpc)
     }
 
     /* Re-enable interrupts */
-    Ke386EnableInterrupts();
+    _enable();
 
     /* Return if the DPC was in the queue or not */
     return DpcData ? TRUE : FALSE;