- Implement KiRecalculateDueTime to handle cases where a timeout wait has been interu...
[reactos.git] / reactos / ntoskrnl / ke / wait.c
index 312b2c6..92749c2 100644 (file)
@@ -127,6 +127,7 @@ KiAbortWaitThread(IN PKTHREAD Thread,
 {
     PKWAIT_BLOCK WaitBlock;
     PKTIMER Timer;
+    LONG NewPriority;
 
     /* Update wait status */
     Thread->WaitStatus |= WaitStatus;
@@ -142,8 +143,8 @@ KiAbortWaitThread(IN PKTHREAD Thread,
         WaitBlock = WaitBlock->NextWaitBlock;
     } while (WaitBlock != Thread->WaitBlockList);
 
-    /* FIXME: Remove the thread from the wait list! */
-    //RemoveEntryList(&Thread->WaitListEntry);
+    /* Remove the thread from the wait list! */
+    if (Thread->WaitListEntry.Flink) RemoveEntryList(&Thread->WaitListEntry);
 
     /* Check if there's a Thread Timer */
     Timer = &Thread->Timer;
@@ -158,8 +159,66 @@ KiAbortWaitThread(IN PKTHREAD Thread,
     /* Increment the Queue's active threads */
     if (Thread->Queue) Thread->Queue->CurrentCount++;
 
+    /* Check if this is a non-RT thread */
+    if (Thread->Priority < LOW_REALTIME_PRIORITY)
+    {
+        /* Check if boosting is enabled and we can boost */
+        if (!(Thread->DisableBoost) && !(Thread->PriorityDecrement))
+        {
+            /* We can boost, so calculate the new priority */
+            NewPriority = Thread->BasePriority + Increment;
+            if (NewPriority > Thread->Priority)
+            {
+                /* Make sure the new priority wouldn't push the thread to RT */
+                if (NewPriority >= LOW_REALTIME_PRIORITY)
+                {
+                    /* Set it just before the RT zone */
+                    Thread->Priority = LOW_REALTIME_PRIORITY - 1;
+                }
+                else
+                {
+                    /* Otherwise, set our calculated priority */
+                    Thread->Priority = NewPriority;
+                }
+            }
+        }
+
+        /* Check if this is a high-priority thread */
+        if (Thread->BasePriority >= 14)
+        {
+            /* It is, simply reset the quantum */
+            Thread->Quantum = Thread->QuantumReset;
+        }
+        else
+        {
+            /* Otherwise, decrease quantum */
+            Thread->Quantum--;
+            if (Thread->Quantum <= 0)
+            {
+                /* We've went below 0, reset it */
+                Thread->Quantum = Thread->QuantumReset;
+
+                /* Apply per-quantum priority decrement */
+                Thread->Priority -= (Thread->PriorityDecrement + 1);
+                if (Thread->Priority < Thread->BasePriority)
+                {
+                    /* We've went too low, reset it */
+                    Thread->Priority = Thread->BasePriority;
+                }
+
+                /* Delete per-quantum decrement */
+                Thread->PriorityDecrement = 0;
+            }
+        }
+    }
+    else
+    {
+        /* For real time threads, just reset the quantum */
+        Thread->Quantum = Thread->QuantumReset;
+    }
+
     /* Reschedule the Thread */
-    KiUnblockThread(Thread, NULL, Increment);
+    KiReadyThread(Thread);
 }
 
 VOID
@@ -215,6 +274,9 @@ KeDelayExecutionThread(IN KPROCESSOR_MODE WaitMode,
     PKTIMER ThreadTimer;
     PKTHREAD CurrentThread = KeGetCurrentThread();
     NTSTATUS WaitStatus = STATUS_SUCCESS;
+    BOOLEAN Swappable;
+    PLARGE_INTEGER OriginalDueTime = Interval;
+    LARGE_INTEGER DueTime, NewDueTime;
 
     /* Check if the lock is already held */
     if (CurrentThread->WaitNext)
@@ -247,6 +309,10 @@ KeDelayExecutionThread(IN KPROCESSOR_MODE WaitMode,
             /* Check if we can do an alertable wait, if requested */
             KiCheckAlertability();
 
+            /* Check if we can swap the thread's stack */
+            CurrentThread->WaitListEntry.Flink = NULL;
+            KiCheckThreadStackSwap(WaitMode, CurrentThread, Swappable);
+
             /* Set status */
             CurrentThread->WaitStatus = STATUS_WAIT_0;
 
@@ -271,6 +337,9 @@ KeDelayExecutionThread(IN KPROCESSOR_MODE WaitMode,
                 break;
             }
 
+            /* Save due time */
+            DueTime.QuadPart = ThreadTimer->DueTime.QuadPart;
+
             /* Handle Kernel Queues */
             if (CurrentThread->Queue) KiWakeQueue(CurrentThread->Queue);
 
@@ -282,6 +351,7 @@ KeDelayExecutionThread(IN KPROCESSOR_MODE WaitMode,
             CurrentThread->State = Waiting;
 
             /* Find a new thread to run */
+            KiAddThreadToWaitList(CurrentThread, Swappable);
             WaitStatus = KiSwapThread();
             ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
 
@@ -295,7 +365,10 @@ KeDelayExecutionThread(IN KPROCESSOR_MODE WaitMode,
                 return WaitStatus;
             }
 
-            /* FIXME: Fixup interval */
+            /* Recalculate due times */
+            Interval = KiRecalculateDueTime(OriginalDueTime,
+                                            &DueTime,
+                                            &NewDueTime);
         }
 
         /* Acquire again the lock */
@@ -312,11 +385,11 @@ KeDelayExecutionThread(IN KPROCESSOR_MODE WaitMode,
  */
 NTSTATUS
 NTAPI
-KeWaitForSingleObject(PVOID Object,
-                      KWAIT_REASON WaitReason,
-                      KPROCESSOR_MODE WaitMode,
-                      BOOLEAN Alertable,
-                      PLARGE_INTEGER Timeout)
+KeWaitForSingleObject(IN PVOID Object,
+                      IN KWAIT_REASON WaitReason,
+                      IN KPROCESSOR_MODE WaitMode,
+                      IN BOOLEAN Alertable,
+                      IN PLARGE_INTEGER Timeout OPTIONAL)
 {
     PKMUTANT CurrentObject;
     PKWAIT_BLOCK WaitBlock;
@@ -324,6 +397,9 @@ KeWaitForSingleObject(PVOID Object,
     PKTIMER ThreadTimer;
     PKTHREAD CurrentThread = KeGetCurrentThread();
     NTSTATUS WaitStatus = STATUS_SUCCESS;
+    BOOLEAN Swappable;
+    LARGE_INTEGER DueTime, NewDueTime;
+    PLARGE_INTEGER OriginalDueTime = Timeout;
 
     /* Check if the lock is already held */
     if (CurrentThread->WaitNext)
@@ -338,6 +414,7 @@ KeWaitForSingleObject(PVOID Object,
     }
 
     /* Start the actual Loop */
+    WaitBlock = &CurrentThread->WaitBlock[0];
     do
     {
         /* Check if a kernel APC is pending and we're below APC_LEVEL */
@@ -353,10 +430,6 @@ KeWaitForSingleObject(PVOID Object,
             /* Set default status */
             CurrentThread->WaitStatus = STATUS_WAIT_0;
 
-            /* Append wait block to the KTHREAD wait block list */
-            WaitBlock = &CurrentThread->WaitBlock[0];
-            CurrentThread->WaitBlockList = WaitBlock;
-
             /* Get the Current Object */
             CurrentObject = (PKMUTANT)Object;
 
@@ -392,16 +465,21 @@ KeWaitForSingleObject(PVOID Object,
                 goto DontWait;
             }
 
+            /* Append wait block to the KTHREAD wait block list */
+            CurrentThread->WaitBlockList = WaitBlock;
+
             /* Set up the Wait Block */
             WaitBlock->Object = CurrentObject;
-            WaitBlock->Thread = CurrentThread;
             WaitBlock->WaitKey = (USHORT)(STATUS_SUCCESS);
             WaitBlock->WaitType = WaitAny;
-            WaitBlock->NextWaitBlock = WaitBlock;
 
             /* Make sure we can satisfy the Alertable request */
             KiCheckAlertability();
 
+            /* Check if we can swap the thread's stack */
+            CurrentThread->WaitListEntry.Flink = NULL;
+            KiCheckThreadStackSwap(WaitMode, CurrentThread, Swappable);
+
             /* Enable the Timeout Timer if there was any specified */
             if (Timeout)
             {
@@ -436,6 +514,14 @@ KeWaitForSingleObject(PVOID Object,
                     WaitStatus = STATUS_TIMEOUT;
                     goto DontWait;
                 }
+
+                /* Set the current due time */
+                DueTime.QuadPart = ThreadTimer->DueTime.QuadPart;
+            }
+            else
+            {
+                /* No timer block, so just set our wait block as next */
+                WaitBlock->NextWaitBlock = WaitBlock;
             }
 
             /* Link the Object to this Wait Block */
@@ -453,6 +539,7 @@ KeWaitForSingleObject(PVOID Object,
             CurrentThread->State = Waiting;
 
             /* Find a new thread to run */
+            KiAddThreadToWaitList(CurrentThread, Swappable);
             WaitStatus = KiSwapThread();
             ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
 
@@ -462,7 +549,10 @@ KeWaitForSingleObject(PVOID Object,
             /* Check if we had a timeout */
             if (Timeout)
             {
-                 /* FIXME: Fixup interval */
+                /* Recalculate due times */
+                Timeout = KiRecalculateDueTime(OriginalDueTime,
+                                               &DueTime,
+                                               &NewDueTime);
             }
         }
 
@@ -505,6 +595,9 @@ KeWaitForMultipleObjects(IN ULONG Count,
     ULONG AllObjectsSignaled;
     ULONG WaitIndex;
     NTSTATUS WaitStatus = STATUS_SUCCESS;
+    BOOLEAN Swappable;
+    PLARGE_INTEGER OriginalDueTime = Timeout;
+    LARGE_INTEGER DueTime, NewDueTime;
 
     /* Set the Current Thread */
     CurrentThread = KeGetCurrentThread();
@@ -668,6 +761,10 @@ KeWaitForMultipleObjects(IN ULONG Count,
             /* Make sure we can satisfy the Alertable request */
             KiCheckAlertability();
 
+            /* Check if we can swap the thread's stack */
+            CurrentThread->WaitListEntry.Flink = NULL;
+            KiCheckThreadStackSwap(WaitMode, CurrentThread, Swappable);
+
             /* Enable the Timeout Timer if there was any specified */
             if (Timeout)
             {
@@ -699,6 +796,9 @@ KeWaitForMultipleObjects(IN ULONG Count,
                     WaitStatus = STATUS_TIMEOUT;
                     goto DontWait;
                 }
+
+                /* Set the current due time */
+                DueTime.QuadPart = ThreadTimer->DueTime.QuadPart;
             }
 
             /* Insert into Object's Wait List*/
@@ -727,6 +827,7 @@ KeWaitForMultipleObjects(IN ULONG Count,
             CurrentThread->State = Waiting;
 
             /* Find a new thread to run */
+            KiAddThreadToWaitList(CurrentThread, Swappable);
             WaitStatus = KiSwapThread();
             ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
 
@@ -736,7 +837,10 @@ KeWaitForMultipleObjects(IN ULONG Count,
             /* Check if we had a timeout */
             if (Timeout)
             {
-                /* FIXME: Fixup interval */
+                /* Recalculate due times */
+                Timeout = KiRecalculateDueTime(OriginalDueTime,
+                                               &DueTime,
+                                               &NewDueTime);
             }
 
             /* Acquire again the lock */