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

svn path=/trunk/; revision=17234
This commit is contained in:
Alex Ionescu 2005-08-09 08:02:05 +00:00
parent 2b0d98ed0e
commit 6fd4c50fd3
3 changed files with 259 additions and 119 deletions

View file

@ -15,6 +15,9 @@
#define NDEBUG
#include "../include/debug.h"
/* FIXME: NDK */
#define HIGH_PRIORITY 31
/* FUNCTIONS *****************************************************************/
_SEH_FILTER(BaseThreadExceptionFilter)
{
@ -536,51 +539,76 @@ SetThreadAffinityMask(HANDLE hThread,
/*
* @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));
if (!NT_SUCCESS(Status))
/* Check if values forcing saturation should be used */
if (Prio == THREAD_PRIORITY_TIME_CRITICAL)
{
SetLastErrorByStatus(Status);
return(FALSE);
Prio = (HIGH_PRIORITY + 1) / 2;
}
else if (Prio == THREAD_PRIORITY_IDLE)
{
Prio = -((HIGH_PRIORITY + 1) / 2);
}
return(TRUE);
}
/* Set the Base Priority */
Status = NtSetInformationThread(hThread,
ThreadBasePriority,
&Prio,
sizeof(ULONG));
if (!NT_SUCCESS(Status))
{
/* Failure */
SetLastErrorByStatus(Status);
return FALSE;
}
/* 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

View file

@ -465,7 +465,8 @@ KiQuantumEnd(VOID)
if (OldPriority != NewPriority) {
/* Set new Priority */
CurrentThread->Priority = NewPriority;
BOOLEAN Dummy; /* <- This is a hack anyways... */
KiSetPriorityThread(CurrentThread, NewPriority, &Dummy);
} else {

View file

@ -348,8 +348,9 @@ KiAdjustQuantumThread(IN PKTHREAD Thread)
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,37 +1055,191 @@ KeQueryBasePriorityThread(IN PKTHREAD Thread)
return BasePriorityIncrement;
}
/*
* @implemented
*/
LONG STDCALL
KeSetBasePriorityThread (PKTHREAD Thread,
LONG Increment)
VOID
STDCALL
KiSetPriorityThread(PKTHREAD Thread,
KPRIORITY Priority,
PBOOLEAN Released)
{
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
*/
LONG
STDCALL
KeSetBasePriorityThread (PKTHREAD Thread,
LONG Increment)
{
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;
KIRQL OldIrql;
PKPROCESS Process;
KPRIORITY Priority;
KPRIORITY CurrentBasePriority;
KPRIORITY BasePriority;
BOOLEAN Released = FALSE;
LONG CurrentIncrement;
/* Lock the Dispatcher Database */
OldIrql = KeAcquireDispatcherDatabaseLock();
/* Get the process and calculate current BP and BPI */
Process = Thread->ApcStatePointer[0]->Process;
CurrentBasePriority = Thread->BasePriority;
CurrentIncrement = CurrentBasePriority - Process->BasePriority;
/* 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;
}
/* 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;
/* Check if it's too high */
if (BasePriority > HIGH_PRIORITY) BasePriority = HIGH_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;
/* Check if it's too low */
if (BasePriority <= LOW_PRIORITY)
BasePriority = 1;
/* 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;
/* Make sure it won't enter RTP ranges */
if (Priority >= LOW_REALTIME_PRIORITY)
Priority = LOW_REALTIME_PRIORITY - 1;
}
}
/* Finally set the new base priority */
Thread->BasePriority = BasePriority;
/* Reset the decrements */
Thread->DecrementCount = 0;
Thread->PriorityDecrement = 0;
/* If the priority will change, reset quantum and change it for real */
if (Priority != Thread->Priority)
{
Thread->Quantum = Thread->QuantumReset;
KiSetPriorityThread(Thread, Priority, &Released);
}
/* Release Lock if needed */
if (!Released)
{
KeReleaseDispatcherDatabaseLock(OldIrql);
}
else
{
KeLowerIrql(OldIrql);
}
/* Return the Old Increment */
return CurrentIncrement;
}
/*
@ -1096,79 +1251,35 @@ KeSetPriorityThread(PKTHREAD Thread,
KPRIORITY Priority)
{
KPRIORITY OldPriority;
BOOLEAN Released = FALSE;
KIRQL OldIrql;
PKTHREAD CurrentThread;
ULONG Mask;
int i;
PKPCR Pcr;
if (Priority < LOW_PRIORITY || Priority >= MAXIMUM_PRIORITY) {
KEBUGCHECK(0);
}
/* Lock the Dispatcher Database */
OldIrql = KeAcquireDispatcherDatabaseLock();
/* Save the old Priority */
OldPriority = Thread->Priority;
if (OldPriority != Priority) {
/* Reset the Quantum and Decrements */
Thread->Quantum = Thread->QuantumReset;
Thread->DecrementCount = 0;
Thread->PriorityDecrement = 0;
CurrentThread = KeGetCurrentThread();
/* Set the new Priority */
KiSetPriorityThread(Thread, Priority, &Released);
if (Thread->State == Ready) {
KiRemoveFromThreadList(Thread);
Thread->BasePriority = Thread->Priority = (CHAR)Priority;
KiInsertIntoThreadList(Priority, Thread);
if (CurrentThread->Priority < Priority) {
KiDispatchThreadNoLock(Ready);
KeLowerIrql(OldIrql);
return (OldPriority);
}
} else if (Thread->State == Running) {
Thread->BasePriority = Thread->Priority = (CHAR)Priority;
if (Priority < OldPriority) {
/* Check for threads with a higher priority */
Mask = ~((1 << (Priority + 1)) - 1);
if (PriorityListMask & Mask) {
if (Thread == CurrentThread) {
KiDispatchThreadNoLock(Ready);
KeLowerIrql(OldIrql);
return (OldPriority);
} else {
for (i = 0; i < KeNumberProcessors; i++) {
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;
}
/*