Fix priority formulas, account for saturation, do proper km_um conversions for out of bounds or saturation priorirites, create an internal priority change function to be called if the lock is already held (however it's not efficient yet since ros dispatches instead of schedules, and so the lock is sometimes released, but i did write a small hack to account for that)... this fixes more wine tests
Modified: trunk/reactos/lib/kernel32/thread/thread.c
Modified: trunk/reactos/ntoskrnl/ke/dpc.c
Modified: trunk/reactos/ntoskrnl/ke/kthread.c

Modified: trunk/reactos/lib/kernel32/thread/thread.c
--- trunk/reactos/lib/kernel32/thread/thread.c	2005-08-09 07:42:00 UTC (rev 17233)
+++ trunk/reactos/lib/kernel32/thread/thread.c	2005-08-09 08:02:05 UTC (rev 17234)
@@ -15,6 +15,9 @@
 #define NDEBUG
 #include "../include/debug.h"
 
+/* FIXME: NDK */
+#define HIGH_PRIORITY 31
+
 /* FUNCTIONS *****************************************************************/
 _SEH_FILTER(BaseThreadExceptionFilter)
 {
@@ -536,52 +539,77 @@
 /*
  * @implemented
  */
-BOOL STDCALL
+BOOL
+STDCALL
 SetThreadPriority(HANDLE hThread,
-		  int nPriority)
+                  int nPriority)
 {
-  ULONG Prio = nPriority;
-  NTSTATUS Status;
+    ULONG Prio = nPriority;
+    NTSTATUS Status;
 
-  Status = NtSetInformationThread(hThread,
-				  ThreadBasePriority,
-				  &Prio,
-				  sizeof(ULONG));
+    /* Check if values forcing saturation should be used */
+    if (Prio == THREAD_PRIORITY_TIME_CRITICAL)
+    {
+        Prio = (HIGH_PRIORITY + 1) / 2;
+    }
+    else if (Prio == THREAD_PRIORITY_IDLE)
+    {
+        Prio = -((HIGH_PRIORITY + 1) / 2);
+    }
 
-  if (!NT_SUCCESS(Status))
+    /* Set the Base Priority */
+    Status = NtSetInformationThread(hThread,
+                                    ThreadBasePriority,
+                                    &Prio,
+                                    sizeof(ULONG));
+    if (!NT_SUCCESS(Status))
     {
-      SetLastErrorByStatus(Status);
-      return(FALSE);
+        /* Failure */
+        SetLastErrorByStatus(Status);
+        return FALSE;
     }
 
-  return(TRUE);
+    /* Return */
+    return TRUE;
 }
 
-
 /*
  * @implemented
  */
-int STDCALL
+int
+STDCALL
 GetThreadPriority(HANDLE hThread)
 {
-  THREAD_BASIC_INFORMATION ThreadBasic;
-  NTSTATUS Status;
+    THREAD_BASIC_INFORMATION ThreadBasic;
+    NTSTATUS Status;
 
-  Status = NtQueryInformationThread(hThread,
-				    ThreadBasicInformation,
-				    &ThreadBasic,
-				    sizeof(THREAD_BASIC_INFORMATION),
-				    NULL);
-  if (!NT_SUCCESS(Status))
+    /* Query the Base Priority Increment */
+    Status = NtQueryInformationThread(hThread,
+                                      ThreadBasicInformation,
+                                      &ThreadBasic,
+                                      sizeof(THREAD_BASIC_INFORMATION),
+                                      NULL);
+    if (!NT_SUCCESS(Status))
     {
-      SetLastErrorByStatus(Status);
-      return(THREAD_PRIORITY_ERROR_RETURN);
+        /* Failure */
+        SetLastErrorByStatus(Status);
+        return THREAD_PRIORITY_ERROR_RETURN;
     }
 
-  return(ThreadBasic.BasePriority);
+    /* Do some conversions for out of boundary values */
+    if (ThreadBasic.BasePriority > THREAD_BASE_PRIORITY_MAX)
+    {
+        ThreadBasic.BasePriority = THREAD_PRIORITY_TIME_CRITICAL;
+    }
+    else if (ThreadBasic.BasePriority < THREAD_BASE_PRIORITY_MIN)
+    {
+        ThreadBasic.BasePriority = THREAD_PRIORITY_IDLE;
+    }
+
+    /* Return the final result */
+    return ThreadBasic.BasePriority;
 }
 
-
 /*
  * @implemented
  */

Modified: trunk/reactos/ntoskrnl/ke/dpc.c
--- trunk/reactos/ntoskrnl/ke/dpc.c	2005-08-09 07:42:00 UTC (rev 17233)
+++ trunk/reactos/ntoskrnl/ke/dpc.c	2005-08-09 08:02:05 UTC (rev 17234)
@@ -465,7 +465,8 @@
             if (OldPriority != NewPriority) {
 
                 /* Set new Priority */
-                CurrentThread->Priority = NewPriority;
+                BOOLEAN Dummy; /* <- This is a hack anyways... */
+                KiSetPriorityThread(CurrentThread, NewPriority, &Dummy);
 
             } else {
 

Modified: trunk/reactos/ntoskrnl/ke/kthread.c
--- trunk/reactos/ntoskrnl/ke/kthread.c	2005-08-09 07:42:00 UTC (rev 17233)
+++ trunk/reactos/ntoskrnl/ke/kthread.c	2005-08-09 08:02:05 UTC (rev 17234)
@@ -348,8 +348,9 @@
             if (Priority != Thread->Priority)
             {
                 /* 
-                 * HACK HACK This isn't nice, but it's the only way with our 
-                 * current codebase
+                 * FIXME: This should be a call to KiSetPriorityThread but
+                 * due to the current ""scheduler"" in ROS, it can't be done
+                 * cleanly since it actualyl dispatches threads instead.
                  */
                 Thread->Priority = Priority;
             }
@@ -1054,121 +1055,231 @@
     return BasePriorityIncrement;
 }
 
-/*
- * @implemented
- */
-LONG STDCALL
-KeSetBasePriorityThread (PKTHREAD	Thread,
-			 LONG		Increment)
-/*
- * Sets thread's base priority relative to the process' base priority
- * Should only be passed in THREAD_PRIORITY_ constants in pstypes.h
- */
+VOID
+STDCALL
+KiSetPriorityThread(PKTHREAD Thread,
+                    KPRIORITY Priority,
+                    PBOOLEAN Released)
 {
-   KPRIORITY Priority;
-   if (Increment < -2)
-     {
-       Increment = -2;
-     }
-   else if (Increment > 2)
-     {
-       Increment = 2;
-     }
-   Priority = ((PETHREAD)Thread)->ThreadsProcess->Pcb.BasePriority + Increment;
-   if (Priority < LOW_PRIORITY)
-   {
-     Priority = LOW_PRIORITY;
-   }
-   else if (Priority >= MAXIMUM_PRIORITY)
-     {
-       Thread->BasePriority = HIGH_PRIORITY;
-     }
-   KeSetPriorityThread(Thread, Priority);
-   return 1;
+    KPRIORITY OldPriority = Thread->Priority;
+    ULONG Mask;
+    int i;
+    PKPCR Pcr;
+    DPRINT("Changing prio to : %lx\n", Priority);
+
+    /* Check if priority changed */
+    if (OldPriority != Priority)
+    {
+        /* Set it */
+        Thread->Priority = Priority;
+
+        /* Choose action based on thread's state */
+        if (Thread->State == Ready)
+        {
+            /* 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)
+            {
+                /* 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)
+                {
+                    /* Found a thread, is it us? */
+                    if (Thread == KeGetCurrentThread())
+                    {
+                        /* Dispatch us */
+                        KiDispatchThreadNoLock(Ready);
+                        *Released = TRUE;
+                        return;
+                    } 
+                    else
+                    {
+                        /* Loop every CPU */
+                        for (i = 0; i < KeNumberProcessors; i++)
+                        {
+                            /* Get the PCR for this CPU */
+                            Pcr = (PKPCR)(KPCR_BASE + i * PAGE_SIZE);
+
+                            /* Reschedule if the new one is already on a CPU */
+                            if (Pcr->Prcb->CurrentThread == Thread)
+                            {
+                                KeReleaseDispatcherDatabaseLockFromDpcLevel();
+                                KiRequestReschedule(i);
+                                *Released = TRUE;
+                                return;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /* Return to caller */
+    return;
 }
 
 /*
+ * Sets thread's base priority relative to the process' base priority
+ * Should only be passed in THREAD_PRIORITY_ constants in pstypes.h
+ *
  * @implemented
  */
-KPRIORITY
+LONG
 STDCALL
-KeSetPriorityThread(PKTHREAD Thread,
-                    KPRIORITY Priority)
+KeSetBasePriorityThread (PKTHREAD Thread,
+                         LONG Increment)
 {
-    KPRIORITY OldPriority;
     KIRQL OldIrql;
-    PKTHREAD CurrentThread;
-    ULONG Mask;
-    int i;
-    PKPCR Pcr;
+    PKPROCESS Process;
+    KPRIORITY Priority;
+    KPRIORITY CurrentBasePriority;
+    KPRIORITY BasePriority;
+    BOOLEAN Released = FALSE;
+    LONG CurrentIncrement;
+       
+    /* Lock the Dispatcher Database */
+    OldIrql = KeAcquireDispatcherDatabaseLock();
 
-    if (Priority < LOW_PRIORITY || Priority >= MAXIMUM_PRIORITY) {
+    /* Get the process and calculate current BP and BPI */
+    Process = Thread->ApcStatePointer[0]->Process;
+    CurrentBasePriority = Thread->BasePriority;
+    CurrentIncrement = CurrentBasePriority - Process->BasePriority;
 
-        KEBUGCHECK(0);
+    /* Change to use the SI if Saturation was used */
+    if (Thread->Saturation) CurrentIncrement = (HIGH_PRIORITY + 1) / 2 *
+                                               Thread->Saturation;
+
+    /* Now check if saturation is being used for the new value */
+    if (abs(Increment) >= ((HIGH_PRIORITY + 1) / 2))
+    {
+        /* Check if we need positive or negative saturation */
+        Thread->Saturation = (Increment > 0) ? 1 : -1;
     }
 
-    OldIrql = KeAcquireDispatcherDatabaseLock();
+    /* Normalize the Base Priority */
+    BasePriority = Process->BasePriority + Increment;
+    if (Process->BasePriority >= LOW_REALTIME_PRIORITY)
+    {
+        /* Check if it's too low */
+        if (BasePriority < LOW_REALTIME_PRIORITY)
+            BasePriority = LOW_REALTIME_PRIORITY;
 
-    OldPriority = Thread->Priority;
+        /* Check if it's too high */
+        if (BasePriority > HIGH_PRIORITY) BasePriority = HIGH_PRIORITY;
 
-    if (OldPriority != Priority) {
+        /* We are at RTP, so use the raw BP */
+        Priority = BasePriority;
+    }
+    else
+    {
+        /* Check if it's entering RTP */
+        if (BasePriority >= LOW_REALTIME_PRIORITY)
+            BasePriority = LOW_REALTIME_PRIORITY - 1;
 
-        CurrentThread = KeGetCurrentThread();
+        /* Check if it's too low */
+        if (BasePriority <= LOW_PRIORITY)
+            BasePriority = 1;
 
-        if (Thread->State == Ready) {
+        /* If Saturation is used, then use the raw BP */
+        if (Thread->Saturation)
+        {
+            Priority = BasePriority;
+        }
+        else
+        {
+            /* Calculate the new priority */
+            Priority = Thread->Priority + (BasePriority - CurrentBasePriority)-
+                       Thread->PriorityDecrement;
 
-            KiRemoveFromThreadList(Thread);
-            Thread->BasePriority = Thread->Priority = (CHAR)Priority;
-            KiInsertIntoThreadList(Priority, Thread);
+            /* Make sure it won't enter RTP ranges */
+            if (Priority >= LOW_REALTIME_PRIORITY)
+                Priority = LOW_REALTIME_PRIORITY - 1;
+        }
+    }
 
-            if (CurrentThread->Priority < Priority) {
+    /* Finally set the new base priority */
+    Thread->BasePriority = BasePriority;
 
-                KiDispatchThreadNoLock(Ready);
-                KeLowerIrql(OldIrql);
-                return (OldPriority);
-            }
+    /* Reset the decrements */
+    Thread->DecrementCount = 0;
+    Thread->PriorityDecrement = 0;
 
-        } else if (Thread->State == Running)  {
+    /* If the priority will change, reset quantum and change it for real */
+    if (Priority != Thread->Priority)
+    {
+        Thread->Quantum = Thread->QuantumReset;
+        KiSetPriorityThread(Thread, Priority, &Released);
+    }
 
-            Thread->BasePriority = Thread->Priority = (CHAR)Priority;
+    /* Release Lock if needed */
+    if (!Released)
+    {
+        KeReleaseDispatcherDatabaseLock(OldIrql);
+    }
+    else
+    {
+        KeLowerIrql(OldIrql);
+    }
 
-            if (Priority < OldPriority) {
+    /* Return the Old Increment */
+    return CurrentIncrement;
+}
 
-                /* Check for threads with a higher priority */
-                Mask = ~((1 << (Priority + 1)) - 1);
-                if (PriorityListMask & Mask) {
+/*
+ * @implemented
+ */
+KPRIORITY
+STDCALL
+KeSetPriorityThread(PKTHREAD Thread,
+                    KPRIORITY Priority)
+{
+    KPRIORITY OldPriority;
+    BOOLEAN Released = FALSE;
+    KIRQL OldIrql;
 
-                    if (Thread == CurrentThread) {
+    /* Lock the Dispatcher Database */
+    OldIrql = KeAcquireDispatcherDatabaseLock();
 
-                        KiDispatchThreadNoLock(Ready);
-                        KeLowerIrql(OldIrql);
-                        return (OldPriority);
+    /* Save the old Priority */
+    OldPriority = Thread->Priority;
 
-                    } else {
+    /* Reset the Quantum and Decrements */
+    Thread->Quantum = Thread->QuantumReset;
+    Thread->DecrementCount = 0;
+    Thread->PriorityDecrement = 0;
 
-                        for (i = 0; i < KeNumberProcessors; i++) {
+    /* Set the new Priority */
+    KiSetPriorityThread(Thread, Priority, &Released);
 
-                            Pcr = (PKPCR)(KPCR_BASE + i * PAGE_SIZE);
-
-                            if (Pcr->Prcb->CurrentThread == Thread) {
-
-                                KeReleaseDispatcherDatabaseLockFromDpcLevel();
-                                KiRequestReschedule(i);
-                                KeLowerIrql(OldIrql);
-                                return (OldPriority);
-                            }
-                        }
-                    }
-                }
-            }
-        }  else  {
-
-            Thread->BasePriority = Thread->Priority = (CHAR)Priority;
-        }
+    /* Release Lock if needed */
+    if (!Released)
+    {
+        KeReleaseDispatcherDatabaseLock(OldIrql);
     }
+    else
+    {
+        KeLowerIrql(OldIrql);
+    }
 
-    KeReleaseDispatcherDatabaseLock(OldIrql);
-    return(OldPriority);
+    /* Return Old Priority */
+    return OldPriority;
 }
 
 /*