Author: ion Date: Fri Jul 21 23:28:38 2006 New Revision: 23214
URL: http://svn.reactos.org/svn/reactos?rev=23214&view=rev Log: - 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.
Modified: trunk/reactos/include/ndk/ketypes.h trunk/reactos/include/ndk/pstypes.h trunk/reactos/ntoskrnl/KrnlFun.c trunk/reactos/ntoskrnl/include/internal/ke.h trunk/reactos/ntoskrnl/include/internal/mm.h trunk/reactos/ntoskrnl/include/internal/ps.h trunk/reactos/ntoskrnl/include/internal/ps_x.h trunk/reactos/ntoskrnl/ke/process.c trunk/reactos/ntoskrnl/mm/mminit.c trunk/reactos/ntoskrnl/mm/process.c trunk/reactos/ntoskrnl/ps/job.c trunk/reactos/ntoskrnl/ps/process.c
Modified: trunk/reactos/include/ndk/ketypes.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/include/ndk/ketypes.h?rev=2... ============================================================================== --- trunk/reactos/include/ndk/ketypes.h (original) +++ trunk/reactos/include/ndk/ketypes.h Fri Jul 21 23:28:38 2006 @@ -929,6 +929,9 @@ #endif } KPROCESS, *PKPROCESS;
+#define ASSERT_PROCESS(object) \ + ASSERT((((object)->Header.Type & KOBJECT_TYPE_MASK) == ProcessObject)) + // // System Service Table Descriptor //
Modified: trunk/reactos/include/ndk/pstypes.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/include/ndk/pstypes.h?rev=2... ============================================================================== --- trunk/reactos/include/ndk/pstypes.h (original) +++ trunk/reactos/include/ndk/pstypes.h Fri Jul 21 23:28:38 2006 @@ -107,6 +107,12 @@ #define PROCESS_PRIORITY_IDLE 3 #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 @@ -303,6 +309,13 @@ } THREADINFOCLASS;
#else + +typedef enum _PSPROCESSPRIORITYMODE +{ + PsProcessPriorityForeground, + PsProcessPriorityBackground, + PsProcessPrioritySpinning +} PSPROCESSPRIORITYMODE;
typedef enum _JOBOBJECTINFOCLASS {
Modified: trunk/reactos/ntoskrnl/KrnlFun.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/KrnlFun.c?rev=2321... ============================================================================== --- trunk/reactos/ntoskrnl/KrnlFun.c (original) +++ trunk/reactos/ntoskrnl/KrnlFun.c Fri Jul 21 23:28:38 2006 @@ -48,4 +48,5 @@ // Ke: // - Add code for interval recalulation when wait interrupted by an APC // -/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +
Modified: trunk/reactos/ntoskrnl/include/internal/ke.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/k... ============================================================================== --- trunk/reactos/ntoskrnl/include/internal/ke.h (original) +++ trunk/reactos/ntoskrnl/include/internal/ke.h Fri Jul 21 23:28:38 2006 @@ -397,6 +397,21 @@ 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);
Modified: trunk/reactos/ntoskrnl/include/internal/mm.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/m... ============================================================================== --- trunk/reactos/ntoskrnl/include/internal/mm.h (original) +++ trunk/reactos/ntoskrnl/include/internal/mm.h Fri Jul 21 23:28:38 2006 @@ -654,6 +654,13 @@ NTAPI MmGetSessionLocaleId(VOID);
+NTSTATUS +NTAPI +MmSetMemoryPriorityProcess( + IN PEPROCESS Process, + IN UCHAR MemoryPriority +); + /* i386/pfault.c *************************************************************/
NTSTATUS
Modified: trunk/reactos/ntoskrnl/include/internal/ps.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/p... ============================================================================== --- trunk/reactos/ntoskrnl/include/internal/ps.h (original) +++ trunk/reactos/ntoskrnl/include/internal/ps.h Fri Jul 21 23:28:38 2006 @@ -18,6 +18,8 @@ #define PSP_MAX_CREATE_THREAD_NOTIFY 8 #define PSP_MAX_LOAD_IMAGE_NOTIFY 8 #define PSP_MAX_CREATE_PROCESS_NOTIFY 8 + +#define PSP_JOB_SCHEDULING_CLASSES 10
VOID NTAPI @@ -226,7 +228,8 @@ 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 */
Modified: trunk/reactos/ntoskrnl/include/internal/ps_x.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/p... ============================================================================== --- trunk/reactos/ntoskrnl/include/internal/ps_x.h (original) +++ trunk/reactos/ntoskrnl/include/internal/ps_x.h Fri Jul 21 23:28:38 2006 @@ -6,6 +6,18 @@ * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) * 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
Modified: trunk/reactos/ntoskrnl/ke/process.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/process.c?rev=2... ============================================================================== --- trunk/reactos/ntoskrnl/ke/process.c (original) +++ trunk/reactos/ntoskrnl/ke/process.c Fri Jul 21 23:28:38 2006 @@ -221,6 +221,204 @@ 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 */
Modified: trunk/reactos/ntoskrnl/mm/mminit.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/mminit.c?rev=23... ============================================================================== --- trunk/reactos/ntoskrnl/mm/mminit.c (original) +++ trunk/reactos/ntoskrnl/mm/mminit.c Fri Jul 21 23:28:38 2006 @@ -29,7 +29,7 @@
static BOOLEAN IsThisAnNtAsSystem = FALSE; -static MM_SYSTEM_SIZE MmSystemSize = MmSmallSystem; +MM_SYSTEM_SIZE MmSystemSize = MmSmallSystem;
PHYSICAL_ADDRESS MmSharedDataPagePhysicalAddress;
Modified: trunk/reactos/ntoskrnl/mm/process.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/process.c?rev=2... ============================================================================== --- trunk/reactos/ntoskrnl/mm/process.c (original) +++ trunk/reactos/ntoskrnl/mm/process.c Fri Jul 21 23:28:38 2006 @@ -17,11 +17,35 @@ 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
Modified: trunk/reactos/ntoskrnl/ps/job.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ps/job.c?rev=23214... ============================================================================== --- trunk/reactos/ntoskrnl/ps/job.c (original) +++ trunk/reactos/ntoskrnl/ps/job.c Fri Jul 21 23:28:38 2006 @@ -18,14 +18,28 @@ #pragma alloc_text(INIT, PsInitJobManagment) #endif
- - /* GLOBALS *******************************************************************/
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 = {
Modified: trunk/reactos/ntoskrnl/ps/process.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ps/process.c?rev=2... ============================================================================== --- trunk/reactos/ntoskrnl/ps/process.c (original) +++ trunk/reactos/ntoskrnl/ps/process.c Fri Jul 21 23:28:38 2006 @@ -27,6 +27,49 @@
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 @@ -140,6 +183,164 @@ /* Reference the Process we had referenced earlier */ if (OldProcess) ObDereferenceObject(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 @@ -861,15 +1062,21 @@ }
/* - * @unimplemented - */ -NTSTATUS + * @implemented + */ +VOID NTAPI PsSetProcessPriorityByClass(IN PEPROCESS Process, - IN ULONG Type) -{ - UNIMPLEMENTED; - return STATUS_NOT_IMPLEMENTED; + IN PSPROCESSPRIORITYMODE Type) +{ + UCHAR Quantum; + ULONG Priority; + + /* Compute quantum and priority */ + Priority = PspComputeQuantumAndPriority(Process, Type, &Quantum); + + /* Set them */ + KeSetPriorityAndQuantumProcess(&Process->Pcb, Priority, Quantum); }
/*