- Implement Kernel, Memory Manager and Process Manager APIs for the following concepts (not yet used):

- Process Quantum.
  - Fixed and Variable Quantum Tables.
  - Long and Short Quantum Variability.
  - Priority Separation and Separation Masks.
  - Foreground Quantum Table.
  - Process Priority, Priority Modes and Priority Classes.
  - Virtual Memory Priority
  - Job Scheduling Classes
- Implement PsSetProcessPriorityByClass.

svn path=/trunk/; revision=23214
This commit is contained in:
Alex Ionescu 2006-07-21 19:28:38 +00:00
parent 3ea8db48b1
commit 2f2139d851
12 changed files with 507 additions and 10 deletions

View file

@ -929,6 +929,9 @@ typedef struct _KPROCESS
#endif
} KPROCESS, *PKPROCESS;
#define ASSERT_PROCESS(object) \
ASSERT((((object)->Header.Type & KOBJECT_TYPE_MASK) == ProcessObject))
//
// System Service Table Descriptor
//

View file

@ -108,6 +108,12 @@ extern NTSYSAPI POBJECT_TYPE PsProcessType;
#define PROCESS_PRIORITY_NORMAL 8
#define PROCESS_PRIORITY_NORMAL_FOREGROUND 9
//
// Process Priority Separation Values (OR)
//
#define PSP_VARIABLE_QUANTUMS 4
#define PSP_LONG_QUANTUMS 16
//
// Number of TLS expansion slots
//
@ -304,6 +310,13 @@ typedef enum _THREADINFOCLASS
#else
typedef enum _PSPROCESSPRIORITYMODE
{
PsProcessPriorityForeground,
PsProcessPriorityBackground,
PsProcessPrioritySpinning
} PSPROCESSPRIORITYMODE;
typedef enum _JOBOBJECTINFOCLASS
{
JobObjectBasicAccountingInformation = 1,

View file

@ -49,3 +49,4 @@
// - Add code for interval recalulation when wait interrupted by an APC
//
///////////////////////////////////////////////////////////////////////////////

View file

@ -397,6 +397,21 @@ KeInitializeProcess(
LARGE_INTEGER DirectoryTableBase
);
VOID
NTAPI
KeSetQuantumProcess(
IN PKPROCESS Process,
IN UCHAR Quantum
);
KPRIORITY
NTAPI
KeSetPriorityAndQuantumProcess(
IN PKPROCESS Process,
IN KPRIORITY Priority,
IN UCHAR Quantum OPTIONAL
);
ULONG
STDCALL
KeForceResumeThread(IN PKTHREAD Thread);

View file

@ -654,6 +654,13 @@ ULONG
NTAPI
MmGetSessionLocaleId(VOID);
NTSTATUS
NTAPI
MmSetMemoryPriorityProcess(
IN PEPROCESS Process,
IN UCHAR MemoryPriority
);
/* i386/pfault.c *************************************************************/
NTSTATUS

View file

@ -19,6 +19,8 @@ struct _EJOB;
#define PSP_MAX_LOAD_IMAGE_NOTIFY 8
#define PSP_MAX_CREATE_PROCESS_NOTIFY 8
#define PSP_JOB_SCHEDULING_CLASSES 10
VOID
NTAPI
PspShutdownProcessManager(VOID);
@ -226,7 +228,8 @@ extern PKWIN32_PROCESS_CALLOUT PspW32ProcessCallout;
extern PKWIN32_THREAD_CALLOUT PspW32ThreadCallout;
extern PVOID PspSystemDllEntryPoint;
extern PVOID PspSystemDllBase;
extern BOOLEAN PspUseJobSchedulingClasses;
extern CHAR PspJobSchedulingClasses[PSP_JOB_SCHEDULING_CLASSES];
#include "ps_x.h"
#endif /* __INCLUDE_INTERNAL_PS_H */

View file

@ -7,6 +7,18 @@
* Thomas Weidenmueller (w3seek@reactos.org)
*/
//
// Extract Quantum Settings from the Priority Separation Mask
//
#define PspPrioritySeparationFromMask(Mask) \
((Mask) & 3)
#define PspQuantumTypeFromMask(Mask) \
((Mask) & 12)
#define PspQuantumLengthFromMask(Mask) \
((Mask) & 48)
VOID
FORCEINLINE
PspRunCreateThreadNotifyRoutines(IN PETHREAD CurrentThread,

View file

@ -221,6 +221,204 @@ KiSwapProcess(PKPROCESS NewProcess,
Ke386SetPageTableDirectory(NewProcess->DirectoryTableBase.u.LowPart);
}
VOID
NTAPI
KeSetQuantumProcess(IN PKPROCESS Process,
IN UCHAR Quantum)
{
KIRQL OldIrql;
PLIST_ENTRY NextEntry, ListHead;
PKTHREAD Thread;
ASSERT_PROCESS(Process);
ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
/* Lock Dispatcher */
OldIrql = KeAcquireDispatcherDatabaseLock();
/* Set new quantum */
Process->QuantumReset = Quantum;
/* Loop all child threads */
ListHead = &Process->ThreadListHead;
NextEntry = ListHead->Flink;
while (ListHead != NextEntry)
{
/* Get the thread */
Thread = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry);
/* Set quantum */
Thread->QuantumReset = Quantum;
/* Go to the next one */
NextEntry = NextEntry->Flink;
}
/* Release Dispatcher Database */
KeReleaseDispatcherDatabaseLock(OldIrql);
}
KPRIORITY
NTAPI
KeSetPriorityAndQuantumProcess(IN PKPROCESS Process,
IN KPRIORITY Priority,
IN UCHAR Quantum OPTIONAL)
{
KPRIORITY Delta;
PLIST_ENTRY NextEntry, ListHead;
KPRIORITY NewPriority, OldPriority;
KIRQL OldIrql;
PKTHREAD Thread;
BOOLEAN Released;
ASSERT_PROCESS(Process);
ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
/* Check if the process already has this priority */
if (Process->BasePriority == Priority)
{
/* Don't change anything */
return Process->BasePriority;
}
/* If the caller gave priority 0, normalize to 1 */
if (!Priority) Priority = 1;
/* Lock Dispatcher */
OldIrql = KeAcquireDispatcherDatabaseLock();
/* Check if we are modifying the quantum too */
if (Quantum) Process->QuantumReset = Quantum;
/* Save the current base priority and update it */
OldPriority = Process->BasePriority;
Process->BasePriority = Priority;
/* Calculate the priority delta */
Delta = Priority - OldPriority;
/* Set the list head and list entry */
ListHead = &Process->ThreadListHead;
NextEntry = ListHead->Flink;
/* Check if this is a real-time priority */
if (Priority >= LOW_REALTIME_PRIORITY)
{
/* Loop the thread list */
while (NextEntry != ListHead)
{
/* Get the thread */
Thread = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry);
/* Update the quantum if we had one */
if (Quantum) Thread->QuantumReset = Quantum;
/* Calculate the new priority */
NewPriority = Thread->BasePriority + Delta;
if (NewPriority < LOW_REALTIME_PRIORITY)
{
/* We're in real-time range, don't let it go below */
NewPriority = LOW_REALTIME_PRIORITY;
}
else if (NewPriority > HIGH_PRIORITY)
{
/* We're going beyond the maximum priority, normalize */
NewPriority = HIGH_PRIORITY;
}
/*
* If priority saturation occured or the old priority was still in
* the real-time range, don't do anything.
*/
if (!(Thread->Saturation) || (OldPriority < LOW_REALTIME_PRIORITY))
{
/* Check if we had priority saturation */
if (Thread->Saturation > 0)
{
/* Boost priority to maximum */
NewPriority = HIGH_PRIORITY;
}
else if (Thread->Saturation < 0)
{
/* If we had negative saturation, set minimum priority */
NewPriority = LOW_REALTIME_PRIORITY;
}
/* Update priority and quantum */
Thread->BasePriority = NewPriority;
Thread->Quantum = Thread->QuantumReset;
/* Disable decrements and update priority */
Thread->PriorityDecrement = 0;
KiSetPriorityThread(Thread, NewPriority, &Released);
}
/* Go to the next thread */
NextEntry = NextEntry->Flink;
}
}
else
{
/* Loop the thread list */
while (NextEntry != ListHead)
{
/* Get the thread */
Thread = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry);
/* Update the quantum if we had one */
if (Quantum) Thread->QuantumReset = Quantum;
/* Calculate the new priority */
NewPriority = Thread->BasePriority + Delta;
if (NewPriority >= LOW_REALTIME_PRIORITY)
{
/* We're not real-time range, don't let it enter RT range */
NewPriority = LOW_REALTIME_PRIORITY - 1;
}
else if (NewPriority <= LOW_PRIORITY)
{
/* We're going below the minimum priority, normalize */
NewPriority = 1;
}
/*
* If priority saturation occured or the old priority was still in
* the real-time range, don't do anything.
*/
if (!(Thread->Saturation) ||
(OldPriority >= LOW_REALTIME_PRIORITY))
{
/* Check if we had priority saturation */
if (Thread->Saturation > 0)
{
/* Boost priority to maximum */
NewPriority = LOW_REALTIME_PRIORITY - 1;
}
else if (Thread->Saturation < 0)
{
/* If we had negative saturation, set minimum priority */
NewPriority = 1;
}
/* Update priority and quantum */
Thread->BasePriority = NewPriority;
Thread->Quantum = Thread->QuantumReset;
/* Disable decrements and update priority */
Thread->PriorityDecrement = 0;
KiSetPriorityThread(Thread, NewPriority, &Released);
}
/* Go to the next thread */
NextEntry = NextEntry->Flink;
}
}
/* Release Dispatcher Database */
if (!Released) KeReleaseDispatcherDatabaseLock(OldIrql);
/* Return previous priority */
return OldPriority;
}
/*
* @implemented
*/

View file

@ -29,7 +29,7 @@ extern unsigned int _bss_end__;
static BOOLEAN IsThisAnNtAsSystem = FALSE;
static MM_SYSTEM_SIZE MmSystemSize = MmSmallSystem;
MM_SYSTEM_SIZE MmSystemSize = MmSmallSystem;
PHYSICAL_ADDRESS MmSharedDataPagePhysicalAddress;

View file

@ -17,12 +17,36 @@ extern ULONG NtMajorVersion;
extern ULONG NtMinorVersion;
extern ULONG NtOSCSDVersion;
extern ULONG NtGlobalFlag;
extern MM_SYSTEM_SIZE MmSystemSize;
#define MM_HIGHEST_VAD_ADDRESS \
(PVOID)((ULONG_PTR)MM_HIGHEST_USER_ADDRESS - (16 * PAGE_SIZE))
/* FUNCTIONS *****************************************************************/
NTSTATUS
NTAPI
MmSetMemoryPriorityProcess(IN PEPROCESS Process,
IN UCHAR MemoryPriority)
{
UCHAR OldPriority;
/* Check if we have less then 16MB of Physical Memory */
if ((MmSystemSize == MmSmallSystem) &&
(MmStats.NrTotalPages < ((15 * 1024 * 1024) / PAGE_SIZE)))
{
/* Always use background priority */
MemoryPriority = 0;
}
/* Save the old priority and update it */
OldPriority = Process->Vm.Flags.MemoryPriority;
Process->Vm.Flags.MemoryPriority = MemoryPriority;
/* Return the old priority */
return OldPriority;
}
LCID
NTAPI
MmGetSessionLocaleId(VOID)

View file

@ -18,8 +18,6 @@
#pragma alloc_text(INIT, PsInitJobManagment)
#endif
/* GLOBALS *******************************************************************/
POBJECT_TYPE PsJobType = NULL;
@ -27,6 +25,22 @@ POBJECT_TYPE PsJobType = NULL;
LIST_ENTRY PsJobListHead;
static FAST_MUTEX PsJobListLock;
BOOLEAN PspUseJobSchedulingClasses;
CHAR PspJobSchedulingClasses[PSP_JOB_SCHEDULING_CLASSES] =
{
1 * 6,
2 * 6,
3 * 6,
4 * 6,
5 * 6,
6 * 6,
7 * 6,
8 * 6,
9 * 6,
10 * 6
};
static GENERIC_MAPPING PiJobMapping =
{
STANDARD_RIGHTS_READ | JOB_OBJECT_QUERY,

View file

@ -27,6 +27,49 @@ KGUARDED_MUTEX PspActiveProcessMutex;
LARGE_INTEGER ShortPsLockDelay;
ULONG PsPrioritySeparation;
CHAR PspForegroundQuantum[3];
/* Fixed quantum table */
CHAR PspFixedQuantums[6] =
{
/* Short quantums */
3 * 6, /* Level 1 */
3 * 6, /* Level 2 */
3 * 6, /* Level 3 */
/* Long quantums */
6 * 6, /* Level 1 */
6 * 6, /* Level 2 */
6 * 6 /* Level 3 */
};
/* Variable quantum table */
CHAR PspVariableQuantums[6] =
{
/* Short quantums */
1 * 6, /* Level 1 */
2 * 6, /* Level 2 */
3 * 6, /* Level 3 */
/* Long quantums */
2 * 6, /* Level 1 */
4 * 6, /* Level 2 */
6 * 6 /* Level 3 */
};
/* Priority table */
KPRIORITY PspPriorityTable[PROCESS_PRIORITY_CLASS_ABOVE_NORMAL + 1] =
{
8,
4,
8,
13,
24,
6,
10
};
/* PRIVATE FUNCTIONS *********************************************************/
NTSTATUS
@ -142,6 +185,164 @@ PsGetNextProcess(IN PEPROCESS OldProcess)
return FoundProcess;
}
KPRIORITY
NTAPI
PspComputeQuantumAndPriority(IN PEPROCESS Process,
IN PSPROCESSPRIORITYMODE Mode,
OUT PCHAR Quantum)
{
ULONG i;
UCHAR LocalQuantum, MemoryPriority;
PAGED_CODE();
/* Check if this is a foreground process */
if (Mode == PsProcessPriorityForeground)
{
/* Set the memory priority and use priority separation */
MemoryPriority = 2;
i = PsPrioritySeparation;
}
else
{
/* Set the background memory priority and no separation */
MemoryPriority = 0;
i = 0;
}
/* Make sure that the process mode isn't spinning */
if (Mode != PsProcessPrioritySpinning)
{
/* Set the priority */
MmSetMemoryPriorityProcess(Process, MemoryPriority);
}
/* Make sure that the process isn't idle */
if (Process->PriorityClass != PROCESS_PRIORITY_CLASS_IDLE)
{
/* Does the process have a job? */
if ((Process->Job) && (PspUseJobSchedulingClasses))
{
/* Use job quantum */
LocalQuantum = PspJobSchedulingClasses[Process->Job->
SchedulingClass];
}
else
{
/* Use calculated quantum */
LocalQuantum = PspForegroundQuantum[i];
}
}
else
{
/* Process is idle, use default quantum */
LocalQuantum = 6;
}
/* Return quantum to caller */
*Quantum = LocalQuantum;
/* Return priority */
return PspPriorityTable[Process->PriorityClass];
}
VOID
NTAPI
PsChangeQuantumTable(IN BOOLEAN Immediate,
IN ULONG PrioritySeparation)
{
PEPROCESS Process = NULL;
ULONG i;
UCHAR Quantum;
PCHAR QuantumTable;
PAGED_CODE();
/* Write the current priority separation */
PsPrioritySeparation = PspPrioritySeparationFromMask(PrioritySeparation);
/* Normalize it if it was too high */
if (PsPrioritySeparation == 3) PsPrioritySeparation = 2;
/* Get the quantum table to use */
if (PspQuantumTypeFromMask(PrioritySeparation) == PSP_VARIABLE_QUANTUMS)
{
/* Use a variable table */
QuantumTable = PspVariableQuantums;
}
else
{
/* Use fixed table */
QuantumTable = PspFixedQuantums;
}
/* Now check if we should use long or short */
if (PspQuantumLengthFromMask(PrioritySeparation) == PSP_LONG_QUANTUMS)
{
/* Use long quantums */
QuantumTable += 3;
}
/* Check if we're using long fixed quantums */
if (QuantumTable == &PspFixedQuantums[3])
{
/* Use Job scheduling classes */
PspUseJobSchedulingClasses = TRUE;
}
else
{
/* Otherwise, we don't */
PspUseJobSchedulingClasses = FALSE;
}
/* Copy the selected table into the Foreground Quantum table */
RtlCopyMemory(PspForegroundQuantum,
QuantumTable,
sizeof(PspForegroundQuantum));
/* Check if we should apply these changes real-time */
if (Immediate)
{
/* We are...loop every process */
Process == PsGetNextProcess(Process);
while (Process)
{
/*
* Use the priority separation, unless the process has
* low memory priority
*/
i = (Process->Vm.Flags.MemoryPriority == 1) ?
0: PsPrioritySeparation;
/* Make sure that the process isn't idle */
if (Process->PriorityClass != PROCESS_PRIORITY_CLASS_IDLE)
{
/* Does the process have a job? */
if ((Process->Job) && (PspUseJobSchedulingClasses))
{
/* Use job quantum */
Quantum = PspJobSchedulingClasses[Process->Job->
SchedulingClass];
}
else
{
/* Use calculated quantum */
Quantum = PspForegroundQuantum[i];
}
}
else
{
/* Process is idle, use default quantum */
Quantum = 6;
}
/* Now set the quantum */
KeSetQuantumProcess(&Process->Pcb, Quantum);
/* Get the next process */
Process == PsGetNextProcess(Process);
}
}
}
NTSTATUS
NTAPI
PspCreateProcess(OUT PHANDLE ProcessHandle,
@ -861,15 +1062,21 @@ PsSetProcessWindowStation(PEPROCESS Process,
}
/*
* @unimplemented
* @implemented
*/
NTSTATUS
VOID
NTAPI
PsSetProcessPriorityByClass(IN PEPROCESS Process,
IN ULONG Type)
IN PSPROCESSPRIORITYMODE Type)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
UCHAR Quantum;
ULONG Priority;
/* Compute quantum and priority */
Priority = PspComputeQuantumAndPriority(Process, Type, &Quantum);
/* Set them */
KeSetPriorityAndQuantumProcess(&Process->Pcb, Priority, Quantum);
}
/*