Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1072 lines
28 KiB

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
psinit.c
Abstract:
Process Structure Initialization.
Author:
Mark Lucovsky (markl) 20-Apr-1989
Revision History:
--*/
#include "psp.h"
extern ULONG PsMinimumWorkingSet;
extern ULONG PsMaximumWorkingSet;
#ifdef ALLOC_DATA_PRAGMA
#pragma const_seg("PAGECONST")
#pragma data_seg("PAGEDATA")
#endif
#define NTDLL_PATH_NAME L"\\SystemRoot\\System32\\ntdll.dll"
const UNICODE_STRING PsNtDllPathName = {
sizeof(NTDLL_PATH_NAME) - sizeof(UNICODE_NULL),
sizeof(NTDLL_PATH_NAME),
NTDLL_PATH_NAME
};
ULONG PsPrioritySeperation; // nonpaged
BOOLEAN PspUseJobSchedulingClasses = FALSE;
PACCESS_TOKEN PspBootAccessToken = NULL;
HANDLE PspInitialSystemProcessHandle = NULL;
PHANDLE_TABLE PspCidTable; // nonpaged
SYSTEM_DLL PspSystemDll = {NULL};
#ifdef ALLOC_DATA_PRAGMA
#pragma const_seg("INITCONST")
#pragma data_seg("INITDATA")
#endif
ULONG PsRawPrioritySeparation = 0;
ULONG PsEmbeddedNTMask = 0;
NTSTATUS
MmCheckSystemImage(
IN HANDLE ImageFileHandle,
IN LOGICAL PurgeSection
);
NTSTATUS
LookupEntryPoint (
IN PVOID DllBase,
IN PSZ NameOfEntryPoint,
OUT PVOID *AddressOfEntryPoint
);
const GENERIC_MAPPING PspProcessMapping = {
STANDARD_RIGHTS_READ |
PROCESS_VM_READ | PROCESS_QUERY_INFORMATION,
STANDARD_RIGHTS_WRITE |
PROCESS_CREATE_PROCESS | PROCESS_CREATE_THREAD |
PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_DUP_HANDLE |
PROCESS_TERMINATE | PROCESS_SET_QUOTA |
PROCESS_SET_INFORMATION | PROCESS_SET_PORT,
STANDARD_RIGHTS_EXECUTE |
SYNCHRONIZE,
PROCESS_ALL_ACCESS
};
const GENERIC_MAPPING PspThreadMapping = {
STANDARD_RIGHTS_READ |
THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION,
STANDARD_RIGHTS_WRITE |
THREAD_TERMINATE | THREAD_SUSPEND_RESUME | THREAD_ALERT |
THREAD_SET_INFORMATION | THREAD_SET_CONTEXT,
STANDARD_RIGHTS_EXECUTE |
SYNCHRONIZE,
THREAD_ALL_ACCESS
};
const GENERIC_MAPPING PspJobMapping = {
STANDARD_RIGHTS_READ |
JOB_OBJECT_QUERY,
STANDARD_RIGHTS_WRITE |
JOB_OBJECT_ASSIGN_PROCESS | JOB_OBJECT_SET_ATTRIBUTES | JOB_OBJECT_TERMINATE,
STANDARD_RIGHTS_EXECUTE |
SYNCHRONIZE,
THREAD_ALL_ACCESS
};
#ifdef ALLOC_DATA_PRAGMA
#pragma data_seg()
#pragma const_seg("PAGECONST")
#endif
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT,PsInitSystem)
#pragma alloc_text(INIT,PspInitPhase0)
#pragma alloc_text(INIT,PspInitPhase1)
#pragma alloc_text(INIT,PspInitializeSystemDll)
#pragma alloc_text(INIT,PspLookupSystemDllEntryPoint)
#pragma alloc_text(INIT,PspNameToOrdinal)
#pragma alloc_text(PAGE,PsLocateSystemDll)
#pragma alloc_text(PAGE,PsMapSystemDll)
#pragma alloc_text(PAGE,PsChangeQuantumTable)
#endif
//
// Process Structure Global Data
//
POBJECT_TYPE PsThreadType;
POBJECT_TYPE PsProcessType;
PEPROCESS PsInitialSystemProcess;
PVOID PsSystemDllDllBase;
ULONG PspDefaultPagedLimit;
ULONG PspDefaultNonPagedLimit;
ULONG PspDefaultPagefileLimit;
SCHAR PspForegroundQuantum[3];
EPROCESS_QUOTA_BLOCK PspDefaultQuotaBlock;
BOOLEAN PspDoingGiveBacks;
POBJECT_TYPE PsJobType;
KGUARDED_MUTEX PspJobListLock;
KSPIN_LOCK PspQuotaLock;
LIST_ENTRY PspJobList;
SINGLE_LIST_ENTRY PsReaperListHead;
WORK_QUEUE_ITEM PsReaperWorkItem;
PVOID PsSystemDllBase;
#define PSP_1MB (1024*1024)
//
// List head and mutex that links all processes that have been initialized
//
KGUARDED_MUTEX PspActiveProcessMutex;
LIST_ENTRY PsActiveProcessHead;
//extern PIMAGE_FILE_HEADER _header;
PEPROCESS PsIdleProcess;
PETHREAD PspShutdownThread;
BOOLEAN
PsInitSystem (
IN ULONG Phase,
IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
/*++
Routine Description:
This function performs process structure initialization.
It is called during phase 0 and phase 1 initialization. Its
function is to dispatch to the appropriate phase initialization
routine.
Arguments:
Phase - Supplies the initialization phase number.
LoaderBlock - Supplies a pointer to a loader parameter block.
Return Value:
TRUE - Initialization succeeded.
FALSE - Initialization failed.
--*/
{
UNREFERENCED_PARAMETER (Phase);
switch (InitializationPhase) {
case 0 :
return PspInitPhase0(LoaderBlock);
case 1 :
return PspInitPhase1(LoaderBlock);
default:
KeBugCheckEx(UNEXPECTED_INITIALIZATION_CALL, 1, InitializationPhase, 0, 0);
}
// return 0; // Not reachable, quiet compiler
}
BOOLEAN
PspInitPhase0 (
IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
/*++
Routine Description:
This routine performs phase 0 process structure initialization.
During this phase, the initial system process, phase 1 initialization
thread, and reaper threads are created. All object types and other
process structures are created and initialized.
Arguments:
None.
Return Value:
TRUE - Initialization was successful.
FALSE - Initialization Failed.
--*/
{
UNICODE_STRING NameString;
OBJECT_ATTRIBUTES ObjectAttributes;
OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
HANDLE ThreadHandle;
PETHREAD Thread;
MM_SYSTEMSIZE SystemSize;
ULONG i;
#if DBG
NTSTATUS Status;
#endif
SystemSize = MmQuerySystemSize ();
PspDefaultPagefileLimit = (ULONG)-1;
#ifdef _WIN64
if (sizeof (TEB) > 8192 || sizeof (PEB) > 4096) {
#else
if (sizeof (TEB) > 4096 || sizeof (PEB) > 4096) {
#endif
KeBugCheckEx (PROCESS_INITIALIZATION_FAILED, 99, sizeof (TEB), sizeof (PEB), 99);
}
switch (SystemSize) {
case MmMediumSystem :
PsMinimumWorkingSet += 10;
PsMaximumWorkingSet += 100;
break;
case MmLargeSystem :
PsMinimumWorkingSet += 30;
PsMaximumWorkingSet += 300;
break;
case MmSmallSystem :
default:
break;
}
//
// Initialize all the callback structures
//
for (i = 0; i < PSP_MAX_CREATE_THREAD_NOTIFY; i++) {
ExInitializeCallBack (&PspCreateThreadNotifyRoutine[i]);
}
for (i = 0; i < PSP_MAX_CREATE_PROCESS_NOTIFY; i++) {
ExInitializeCallBack (&PspCreateProcessNotifyRoutine[i]);
}
for (i = 0; i < PSP_MAX_LOAD_IMAGE_NOTIFY; i++) {
ExInitializeCallBack (&PspLoadImageNotifyRoutine[i]);
}
PsChangeQuantumTable (FALSE, PsRawPrioritySeparation);
//
// Quotas grow as needed automatically
//
if (PspDefaultNonPagedLimit == 0 && PspDefaultPagedLimit == 0) {
PspDoingGiveBacks = TRUE;
} else {
PspDoingGiveBacks = FALSE;
}
PspDefaultPagedLimit *= PSP_1MB;
PspDefaultNonPagedLimit *= PSP_1MB;
if (PspDefaultPagefileLimit != -1) {
PspDefaultPagefileLimit *= PSP_1MB;
}
//
// Initialize active process list head and mutex
//
InitializeListHead (&PsActiveProcessHead);
PspInitializeProcessListLock ();
//
// Initialize the process security fields lock
//
PsIdleProcess = PsGetCurrentProcess();
PspInitializeProcessLock (PsIdleProcess);
ExInitializeRundownProtection (&PsIdleProcess->RundownProtect);
InitializeListHead (&PsIdleProcess->ThreadListHead);
PsIdleProcess->Pcb.KernelTime = 0;
PsIdleProcess->Pcb.KernelTime = 0;
//
// Initialize the shutdown thread pointer
//
PspShutdownThread = NULL;
//
// Initialize the common fields of the Object Type Prototype record
//
RtlZeroMemory (&ObjectTypeInitializer, sizeof (ObjectTypeInitializer));
ObjectTypeInitializer.Length = sizeof (ObjectTypeInitializer);
ObjectTypeInitializer.SecurityRequired = TRUE;
ObjectTypeInitializer.PoolType = NonPagedPool;
ObjectTypeInitializer.InvalidAttributes = OBJ_PERMANENT |
OBJ_EXCLUSIVE |
OBJ_OPENIF;
//
// Create Object types for Thread and Process Objects.
//
RtlInitUnicodeString (&NameString, L"Process");
ObjectTypeInitializer.DefaultPagedPoolCharge = PSP_PROCESS_PAGED_CHARGE;
ObjectTypeInitializer.DefaultNonPagedPoolCharge = PSP_PROCESS_NONPAGED_CHARGE;
ObjectTypeInitializer.DeleteProcedure = PspProcessDelete;
ObjectTypeInitializer.ValidAccessMask = PROCESS_ALL_ACCESS;
ObjectTypeInitializer.GenericMapping = PspProcessMapping;
if (!NT_SUCCESS (ObCreateObjectType (&NameString,
&ObjectTypeInitializer,
(PSECURITY_DESCRIPTOR) NULL,
&PsProcessType))) {
return FALSE;
}
RtlInitUnicodeString (&NameString, L"Thread");
ObjectTypeInitializer.DefaultPagedPoolCharge = PSP_THREAD_PAGED_CHARGE;
ObjectTypeInitializer.DefaultNonPagedPoolCharge = PSP_THREAD_NONPAGED_CHARGE;
ObjectTypeInitializer.DeleteProcedure = PspThreadDelete;
ObjectTypeInitializer.ValidAccessMask = THREAD_ALL_ACCESS;
ObjectTypeInitializer.GenericMapping = PspThreadMapping;
if (!NT_SUCCESS (ObCreateObjectType (&NameString,
&ObjectTypeInitializer,
(PSECURITY_DESCRIPTOR) NULL,
&PsThreadType))) {
return FALSE;
}
RtlInitUnicodeString (&NameString, L"Job");
ObjectTypeInitializer.DefaultPagedPoolCharge = 0;
ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof (EJOB);
ObjectTypeInitializer.DeleteProcedure = PspJobDelete;
ObjectTypeInitializer.CloseProcedure = PspJobClose;
ObjectTypeInitializer.ValidAccessMask = JOB_OBJECT_ALL_ACCESS;
ObjectTypeInitializer.GenericMapping = PspJobMapping;
ObjectTypeInitializer.InvalidAttributes = 0;
if (!NT_SUCCESS (ObCreateObjectType (&NameString,
&ObjectTypeInitializer,
(PSECURITY_DESCRIPTOR) NULL,
&PsJobType))) {
return FALSE;
}
//
// Initialize job list head and mutex
//
PspInitializeJobStructures ();
InitializeListHead (&PspWorkingSetChangeHead.Links);
PspInitializeWorkingSetChangeLock ();
//
// Initialize CID handle table.
//
// N.B. The CID handle table is removed from the handle table list so
// it will not be enumerated for object handle queries.
//
PspCidTable = ExCreateHandleTable (NULL);
if (PspCidTable == NULL) {
return FALSE;
}
//
// Set PID and TID reuse to strict FIFO. This isn't absolutely needed but
// it makes tracking audits easier.
//
ExSetHandleTableStrictFIFO (PspCidTable);
ExRemoveHandleTable (PspCidTable);
#if defined(i386)
//
// Ldt Initialization
//
if ( !NT_SUCCESS (PspLdtInitialize ()) ) {
return FALSE;
}
//
// Vdm support Initialization
//
if (!NT_SUCCESS (PspVdmInitialize ())) {
return FALSE;
}
#endif
//
// Initialize Reaper Data Structures
//
PsReaperListHead.Next = NULL;
ExInitializeWorkItem (&PsReaperWorkItem, PspReaper, NULL);
//
// Get a pointer to the system access token.
// This token is used by the boot process, so we can take the pointer
// from there.
//
PspBootAccessToken = ExFastRefGetObject (PsIdleProcess->Token);
InitializeObjectAttributes (&ObjectAttributes,
NULL,
0,
NULL,
NULL);
if (!NT_SUCCESS (PspCreateProcess (&PspInitialSystemProcessHandle,
PROCESS_ALL_ACCESS,
&ObjectAttributes,
NULL,
0,
NULL,
NULL,
NULL,
0))) {
return FALSE;
}
if (!NT_SUCCESS (ObReferenceObjectByHandle (PspInitialSystemProcessHandle,
0L,
PsProcessType,
KernelMode,
&PsInitialSystemProcess,
NULL))) {
return FALSE;
}
strcpy((char *) &PsIdleProcess->ImageFileName[0], "Idle");
strcpy((char *) &PsInitialSystemProcess->ImageFileName[0], "System");
//
// The system process can allocate resources, and its name may be queried by
// NtQueryInfomationProcess and various audits. We must explicitly allocate memory
// for this field of the System EPROCESS, and initialize it appropriately. In this
// case, appropriate initialization means zeroing the memory.
//
PsInitialSystemProcess->SeAuditProcessCreationInfo.ImageFileName =
ExAllocatePoolWithTag (PagedPool,
sizeof(OBJECT_NAME_INFORMATION),
'aPeS');
if (PsInitialSystemProcess->SeAuditProcessCreationInfo.ImageFileName != NULL) {
RtlZeroMemory (PsInitialSystemProcess->SeAuditProcessCreationInfo.ImageFileName,
sizeof (OBJECT_NAME_INFORMATION));
} else {
return FALSE;
}
//
// Phase 1 System initialization
//
if (!NT_SUCCESS (PsCreateSystemThread (&ThreadHandle,
THREAD_ALL_ACCESS,
&ObjectAttributes,
0L,
NULL,
Phase1Initialization,
(PVOID)LoaderBlock))) {
return FALSE;
}
if (!NT_SUCCESS (ObReferenceObjectByHandle (ThreadHandle,
0L,
PsThreadType,
KernelMode,
&Thread,
NULL))) {
return FALSE;
}
ZwClose (ThreadHandle);
//
// On checked systems install an image callout routine
//
#if DBG
Status = PsSetLoadImageNotifyRoutine (PspImageNotifyTest);
if (!NT_SUCCESS (Status)) {
return FALSE;
}
#endif
return TRUE;
}
BOOLEAN
PspInitPhase1 (
IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
/*++
Routine Description:
This routine performs phase 1 process structure initialization.
During this phase, the system DLL is located and relevant entry
points are extracted.
Arguments:
None.
Return Value:
TRUE - Initialization was successful.
FALSE - Initialization Failed.
--*/
{
NTSTATUS st;
UNREFERENCED_PARAMETER (LoaderBlock);
PspInitializeJobStructuresPhase1 ();
st = PspInitializeSystemDll ();
if (!NT_SUCCESS (st)) {
return FALSE;
}
return TRUE;
}
NTSTATUS
PsLocateSystemDll (
BOOLEAN ReplaceExisting
)
/*++
Routine Description:
This function locates the system dll and creates a section for the
DLL and maps it into the system process.
Arguments:
None.
Return Value:
TRUE - Initialization was successful.
FALSE - Initialization Failed.
--*/
{
HANDLE File;
HANDLE Section;
NTSTATUS st;
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatus;
PVOID NtDllSection;
//
// First see if we need to load this DLL at all.
//
if (ExVerifySuite (EmbeddedNT) && (PsEmbeddedNTMask&PS_EMBEDDED_NO_USERMODE)) {
return STATUS_SUCCESS;
}
if (!ReplaceExisting) {
ExInitializePushLock(&PspSystemDll.DllLock);
}
//
// Initialize the system DLL
//
InitializeObjectAttributes (&ObjectAttributes,
(PUNICODE_STRING) &PsNtDllPathName,
OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE,
NULL,
NULL);
st = ZwOpenFile (&File,
SYNCHRONIZE | FILE_EXECUTE,
&ObjectAttributes,
&IoStatus,
FILE_SHARE_READ,
0);
if (!NT_SUCCESS (st)) {
#if DBG
DbgPrint("PS: PsLocateSystemDll - NtOpenFile( NTDLL.DLL ) failed. Status == %lx\n",
st);
#endif
if (ReplaceExisting) {
return st;
}
KeBugCheckEx (PROCESS1_INITIALIZATION_FAILED, st, 2, 0, 0);
}
st = MmCheckSystemImage (File, TRUE);
if (st == STATUS_IMAGE_CHECKSUM_MISMATCH ||
st == STATUS_INVALID_IMAGE_PROTECT) {
ULONG_PTR ErrorParameters;
ULONG ErrorResponse;
//
// Hard error time. A driver is corrupt.
//
ErrorParameters = (ULONG_PTR)&PsNtDllPathName;
NtRaiseHardError (st,
1,
1,
&ErrorParameters,
OptionOk,
&ErrorResponse);
return st;
}
st = ZwCreateSection (&Section,
SECTION_ALL_ACCESS,
NULL,
0,
PAGE_EXECUTE,
SEC_IMAGE,
File);
ZwClose (File);
if (!NT_SUCCESS (st)) {
#if DBG
DbgPrint("PS: PsLocateSystemDll: NtCreateSection Status == %lx\n",st);
#endif
if (ReplaceExisting) {
return st;
}
KeBugCheckEx (PROCESS1_INITIALIZATION_FAILED, st, 3, 0, 0);
// return st;
}
//
// Now that we have the section, reference it, store its address in the
// PspSystemDll and then close handle to the section.
//
st = ObReferenceObjectByHandle (Section,
SECTION_ALL_ACCESS,
MmSectionObjectType,
KernelMode,
&NtDllSection,
NULL);
ZwClose (Section);
if (!NT_SUCCESS (st)) {
if (ReplaceExisting) {
return st;
}
KeBugCheckEx(PROCESS1_INITIALIZATION_FAILED,st,4,0,0);
// return st;
}
if (ReplaceExisting) {
PVOID ExistingSection;
KeEnterCriticalRegion();
ExAcquirePushLockExclusive(&PspSystemDll.DllLock);
ExistingSection = PspSystemDll.Section;
PspSystemDll.Section = NtDllSection;
ExReleasePushLockExclusive(&PspSystemDll.DllLock);
KeLeaveCriticalRegion();
if (ExistingSection) {
ObDereferenceObject(ExistingSection);
}
} else {
PspSystemDll.Section = NtDllSection;
//
// Map the system dll into the user part of the address space
//
st = PsMapSystemDll (PsGetCurrentProcess (), &PspSystemDll.DllBase);
PsSystemDllDllBase = PspSystemDll.DllBase;
if (!NT_SUCCESS (st)) {
KeBugCheckEx (PROCESS1_INITIALIZATION_FAILED, st, 5, 0, 0);
// return st;
}
PsSystemDllBase = PspSystemDll.DllBase;
}
return STATUS_SUCCESS;
}
NTSTATUS
PsMapSystemDll (
IN PEPROCESS Process,
OUT PVOID *DllBase OPTIONAL
)
/*++
Routine Description:
This function maps the system DLL into the specified process.
Arguments:
Process - Supplies the address of the process to map the DLL into.
Return Value:
TBD
--*/
{
NTSTATUS st;
PVOID ViewBase;
LARGE_INTEGER SectionOffset;
SIZE_T ViewSize;
PVOID CapturedSection;
PAGED_CODE();
ViewBase = NULL;
SectionOffset.LowPart = 0;
SectionOffset.HighPart = 0;
ViewSize = 0;
KeEnterCriticalRegion();
ExAcquirePushLockShared(&PspSystemDll.DllLock);
CapturedSection = PspSystemDll.Section;
ObReferenceObject(CapturedSection);
ExReleasePushLockShared(&PspSystemDll.DllLock);
KeLeaveCriticalRegion();
//
// Map the system dll into the user part of the address space
//
st = MmMapViewOfSection(
CapturedSection,
Process,
&ViewBase,
0L,
0L,
&SectionOffset,
&ViewSize,
ViewShare,
0L,
PAGE_READWRITE
);
ObDereferenceObject(CapturedSection);
if (st != STATUS_SUCCESS) {
#if DBG
DbgPrint("PS: Unable to map system dll at based address.\n");
#endif
st = STATUS_CONFLICTING_ADDRESSES;
}
if (ARGUMENT_PRESENT (DllBase)) {
*DllBase = ViewBase;
}
return st;
}
NTSTATUS
PspInitializeSystemDll (
VOID
)
/*++
Routine Description:
This function initializes the system DLL and locates
various entrypoints within the DLL.
Arguments:
None.
Return Value:
TBD
--*/
{
NTSTATUS st;
PSZ dll_entrypoint;
//
// If we skipped dll load becuase we are kernel only then exit now.
//
if (PsSystemDllDllBase == NULL) {
return STATUS_SUCCESS;
}
//
// Locate the important system dll entrypoints
//
dll_entrypoint = "LdrInitializeThunk";
st = PspLookupSystemDllEntryPoint (dll_entrypoint,
(PVOID) &PspSystemDll.LoaderInitRoutine);
if (!NT_SUCCESS (st)) {
#if DBG
DbgPrint("PS: Unable to locate LdrInitializeThunk in system dll\n");
#endif
KeBugCheckEx (PROCESS1_INITIALIZATION_FAILED, st, 6, 0, 0);
}
st = PspLookupKernelUserEntryPoints ();
if ( !NT_SUCCESS (st)) {
KeBugCheckEx(PROCESS1_INITIALIZATION_FAILED,st,8,0,0);
}
KdUpdateDataBlock ();
return st;
}
NTSTATUS
PspLookupSystemDllEntryPoint (
IN PSZ NameOfEntryPoint,
OUT PVOID *AddressOfEntryPoint
)
{
return LookupEntryPoint (PspSystemDll.DllBase,
NameOfEntryPoint,
AddressOfEntryPoint);
}
const SCHAR PspFixedQuantums[6] = {3*THREAD_QUANTUM,
3*THREAD_QUANTUM,
3*THREAD_QUANTUM,
6*THREAD_QUANTUM,
6*THREAD_QUANTUM,
6*THREAD_QUANTUM};
const SCHAR PspVariableQuantums[6] = {1*THREAD_QUANTUM,
2*THREAD_QUANTUM,
3*THREAD_QUANTUM,
2*THREAD_QUANTUM,
4*THREAD_QUANTUM,
6*THREAD_QUANTUM};
//
// The table is ONLY used when fixed quantums are selected.
//
const SCHAR PspJobSchedulingClasses[PSP_NUMBER_OF_SCHEDULING_CLASSES] = {1*THREAD_QUANTUM, // long fixed 0
2*THREAD_QUANTUM, // long fixed 1...
3*THREAD_QUANTUM,
4*THREAD_QUANTUM,
5*THREAD_QUANTUM,
6*THREAD_QUANTUM, // DEFAULT
7*THREAD_QUANTUM,
8*THREAD_QUANTUM,
9*THREAD_QUANTUM,
10*THREAD_QUANTUM}; // long fixed 9
VOID
PsChangeQuantumTable (
BOOLEAN ModifyActiveProcesses,
ULONG PrioritySeparation
)
{
PEPROCESS Process;
PETHREAD CurrentThread;
PLIST_ENTRY NextProcess;
ULONG QuantumIndex;
SCHAR const* QuantumTableBase;
PEJOB Job;
//
// extract priority seperation value
//
switch (PrioritySeparation & PROCESS_PRIORITY_SEPARATION_MASK) {
case 3:
PsPrioritySeperation = PROCESS_PRIORITY_SEPARATION_MAX;
break;
default:
PsPrioritySeperation = PrioritySeparation & PROCESS_PRIORITY_SEPARATION_MASK;
break;
}
//
// determine if we are using fixed or variable quantums
//
switch (PrioritySeparation & PROCESS_QUANTUM_VARIABLE_MASK) {
case PROCESS_QUANTUM_VARIABLE_VALUE:
QuantumTableBase = PspVariableQuantums;
break;
case PROCESS_QUANTUM_FIXED_VALUE:
QuantumTableBase = PspFixedQuantums;
break;
case PROCESS_QUANTUM_VARIABLE_DEF:
default:
if (MmIsThisAnNtAsSystem ()) {
QuantumTableBase = PspFixedQuantums;
} else {
QuantumTableBase = PspVariableQuantums;
}
break;
}
//
// determine if we are using long or short
//
switch (PrioritySeparation & PROCESS_QUANTUM_LONG_MASK) {
case PROCESS_QUANTUM_LONG_VALUE:
QuantumTableBase = QuantumTableBase + 3;
break;
case PROCESS_QUANTUM_SHORT_VALUE:
break;
case PROCESS_QUANTUM_LONG_DEF:
default:
if (MmIsThisAnNtAsSystem ()) {
QuantumTableBase = QuantumTableBase + 3;
}
break;
}
//
// Job Scheduling classes are ONLY meaningful if long fixed quantums
// are selected. In practice, this means stock NTS configurations
//
if (QuantumTableBase == &PspFixedQuantums[3]) {
PspUseJobSchedulingClasses = TRUE;
} else {
PspUseJobSchedulingClasses = FALSE;
}
RtlCopyMemory (PspForegroundQuantum, QuantumTableBase, sizeof(PspForegroundQuantum));
if (ModifyActiveProcesses) {
CurrentThread = PsGetCurrentThread ();
PspLockProcessList (CurrentThread);
NextProcess = PsActiveProcessHead.Flink;
while (NextProcess != &PsActiveProcessHead) {
Process = CONTAINING_RECORD(NextProcess,
EPROCESS,
ActiveProcessLinks);
if (Process->Vm.Flags.MemoryPriority == MEMORY_PRIORITY_BACKGROUND) {
QuantumIndex = 0;
} else {
QuantumIndex = PsPrioritySeperation;
}
if (Process->PriorityClass != PROCESS_PRIORITY_CLASS_IDLE) {
//
// If the process is contained within a JOB, AND we are
// running Fixed, Long Quantums, use the quantum associated
// with the Job's scheduling class
//
Job = Process->Job;
if (Job != NULL && PspUseJobSchedulingClasses) {
Process->Pcb.ThreadQuantum = PspJobSchedulingClasses[Job->SchedulingClass];
} else {
Process->Pcb.ThreadQuantum = PspForegroundQuantum[QuantumIndex];
}
} else {
Process->Pcb.ThreadQuantum = THREAD_QUANTUM;
}
NextProcess = NextProcess->Flink;
}
PspUnlockProcessList (CurrentThread);
}
}
#ifdef ALLOC_DATA_PRAGMA
#pragma const_seg()
#endif