/* * PROJECT: ReactOS Kernel * LICENSE: GPL - See COPYING in the top level directory * FILE: ntoskrnl/ke/procobj.c * PURPOSE: Kernel Process Management and System Call Tables * PROGRAMMERS: Alex Ionescu * Gregor Anich */ /* INCLUDES ******************************************************************/ #include #define NDEBUG #include /* GLOBALS *******************************************************************/ LIST_ENTRY KiProcessListHead; LIST_ENTRY KiProcessInSwapListHead, KiProcessOutSwapListHead; LIST_ENTRY KiStackInSwapListHead; KEVENT KiSwapEvent; KSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTable[SSDT_MAX_ENTRIES]; KSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTableShadow[SSDT_MAX_ENTRIES]; PVOID KeUserApcDispatcher; PVOID KeUserCallbackDispatcher; PVOID KeUserExceptionDispatcher; PVOID KeRaiseUserExceptionDispatcher; /* PRIVATE FUNCTIONS *********************************************************/ VOID NTAPI KiAttachProcess(IN PKTHREAD Thread, IN PKPROCESS Process, IN PKLOCK_QUEUE_HANDLE ApcLock, IN PRKAPC_STATE SavedApcState) { #if 0 PLIST_ENTRY ListHead, NextEntry; PKTHREAD CurrentThread; #endif ASSERT(Process != Thread->ApcState.Process); /* Increase Stack Count */ ASSERT(Process->StackCount != MAXULONG_PTR); Process->StackCount++; /* Swap the APC Environment */ KiMoveApcState(&Thread->ApcState, SavedApcState); /* Reinitialize Apc State */ InitializeListHead(&Thread->ApcState.ApcListHead[KernelMode]); InitializeListHead(&Thread->ApcState.ApcListHead[UserMode]); Thread->ApcState.Process = Process; Thread->ApcState.KernelApcInProgress = FALSE; Thread->ApcState.KernelApcPending = FALSE; Thread->ApcState.UserApcPending = FALSE; /* Update Environment Pointers if needed*/ if (SavedApcState == &Thread->SavedApcState) { Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread-> SavedApcState; Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->ApcState; Thread->ApcStateIndex = AttachedApcEnvironment; } /* Check if the process is paged in */ if (Process->State == ProcessInMemory) { /* Scan the ready list */ #if 0 ListHead = &Process->ReadyListHead; NextEntry = ListHead->Flink; while (NextEntry != ListHead) { /* Get the thread */ CurrentThread = CONTAINING_RECORD(NextEntry, KTHREAD, WaitListEntry); /* Remove it */ RemoveEntryList(NextEntry); CurrentThread->ProcessReadyQueue = FALSE; /* Mark it ready */ KiReadyThread(CurrentThread); /* Go to the next one */ NextEntry = ListHead->Flink; } #endif /* Release dispatcher lock */ KiReleaseDispatcherLockFromSynchLevel(); /* Release lock */ KiReleaseApcLockFromSynchLevel(ApcLock); /* Swap Processes */ KiSwapProcess(Process, SavedApcState->Process); /* Exit the dispatcher */ KiExitDispatcher(ApcLock->OldIrql); } else { DPRINT1("Errr. ReactOS doesn't support paging out processes yet...\n"); ASSERT(FALSE); } } VOID NTAPI KeInitializeProcess(IN OUT PKPROCESS Process, IN KPRIORITY Priority, IN KAFFINITY Affinity, IN PULONG_PTR DirectoryTableBase, IN BOOLEAN Enable) { #ifdef CONFIG_SMP ULONG i = 0; UCHAR IdealNode = 0; PKNODE Node; #endif /* Initialize the Dispatcher Header */ Process->Header.Type = ProcessObject; Process->Header.Size = sizeof(KPROCESS) / sizeof(ULONG); Process->Header.SignalState = 0; InitializeListHead(&(Process->Header.WaitListHead)); /* Initialize Scheduler Data, Alignment Faults and Set the PDE */ Process->Affinity = Affinity; Process->BasePriority = (CHAR)Priority; Process->QuantumReset = 6; Process->DirectoryTableBase[0] = DirectoryTableBase[0]; Process->DirectoryTableBase[1] = DirectoryTableBase[1]; Process->AutoAlignment = Enable; #if defined(_M_IX86) Process->IopmOffset = KiComputeIopmOffset(IO_ACCESS_MAP_NONE); #endif /* Initialize the lists */ InitializeListHead(&Process->ThreadListHead); InitializeListHead(&Process->ProfileListHead); InitializeListHead(&Process->ReadyListHead); /* Initialize the current State */ Process->State = ProcessInMemory; /* Check how many Nodes there are on the system */ #ifdef CONFIG_SMP if (KeNumberNodes > 1) { /* Set the new seed */ KeProcessNodeSeed = (KeProcessNodeSeed + 1) / KeNumberNodes; IdealNode = KeProcessNodeSeed; /* Loop every node */ do { /* Check if the affinity matches */ if (KeNodeBlock[IdealNode]->ProcessorMask != Affinity) break; /* No match, try next Ideal Node and increase node loop index */ IdealNode++; i++; /* Check if the Ideal Node is beyond the total number of nodes */ if (IdealNode >= KeNumberNodes) { /* Normalize the Ideal Node */ IdealNode -= KeNumberNodes; } } while (i < KeNumberNodes); } /* Set the ideal node and get the ideal node block */ Process->IdealNode = IdealNode; Node = KeNodeBlock[IdealNode]; ASSERT(Node->ProcessorMask & Affinity); /* Find the matching affinity set to calculate the thread seed */ Affinity &= Node->ProcessorMask; Process->ThreadSeed = KeFindNextRightSetAffinity(Node->Seed, (ULONG)Affinity); Node->Seed = Process->ThreadSeed; #endif } ULONG NTAPI KeSetProcess(IN PKPROCESS Process, IN KPRIORITY Increment, IN BOOLEAN InWait) { KIRQL OldIrql; ULONG OldState; ASSERT_PROCESS(Process); ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); /* Lock Dispatcher */ OldIrql = KiAcquireDispatcherLock(); /* Get Old State */ OldState = Process->Header.SignalState; /* Signal the Process */ Process->Header.SignalState = TRUE; /* Check if was unsignaled and has waiters */ if (!(OldState) && !(IsListEmpty(&Process->Header.WaitListHead))) { /* Unwait the threads */ KxUnwaitThread(&Process->Header, Increment); } /* Release Dispatcher Database */ KiReleaseDispatcherLock(OldIrql); /* Return the previous State */ return OldState; } VOID NTAPI KeSetQuantumProcess(IN PKPROCESS Process, IN UCHAR Quantum) { KLOCK_QUEUE_HANDLE ProcessLock; PLIST_ENTRY NextEntry, ListHead; PKTHREAD Thread; ASSERT_PROCESS(Process); ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); /* Lock the process */ KiAcquireProcessLockRaiseToSynch(Process, &ProcessLock); /* 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 lock */ KiReleaseProcessLock(&ProcessLock); } KAFFINITY NTAPI KeSetAffinityProcess(IN PKPROCESS Process, IN KAFFINITY Affinity) { KLOCK_QUEUE_HANDLE ProcessLock; PLIST_ENTRY NextEntry, ListHead; KAFFINITY OldAffinity; PKTHREAD Thread; ASSERT_PROCESS(Process); ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); ASSERT((Affinity & KeActiveProcessors) != 0); /* Lock the process */ KiAcquireProcessLockRaiseToSynch(Process, &ProcessLock); /* Acquire the dispatcher lock */ KiAcquireDispatcherLockAtSynchLevel(); /* Capture old affinity and update it */ OldAffinity = Process->Affinity; Process->Affinity = Affinity; /* Loop all child threads */ ListHead = &Process->ThreadListHead; NextEntry = ListHead->Flink; while (ListHead != NextEntry) { /* Get the thread */ Thread = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry); /* Set affinity on it */ KiSetAffinityThread(Thread, Affinity); NextEntry = NextEntry->Flink; } /* Release Dispatcher Database */ KiReleaseDispatcherLockFromSynchLevel(); /* Release the process lock */ KiReleaseProcessLockFromSynchLevel(&ProcessLock); KiExitDispatcher(ProcessLock.OldIrql); /* Return previous affinity */ return OldAffinity; } BOOLEAN NTAPI KeSetAutoAlignmentProcess(IN PKPROCESS Process, IN BOOLEAN Enable) { /* Set or reset the bit depending on what the enable flag says */ if (Enable) { return InterlockedBitTestAndSet(&Process->ProcessFlags, KPSF_AUTO_ALIGNMENT_BIT); } else { return InterlockedBitTestAndReset(&Process->ProcessFlags, KPSF_AUTO_ALIGNMENT_BIT); } } BOOLEAN NTAPI KeSetDisableBoostProcess(IN PKPROCESS Process, IN BOOLEAN Disable) { /* Set or reset the bit depending on what the disable flag says */ if (Disable) { return InterlockedBitTestAndSet(&Process->ProcessFlags, KPSF_DISABLE_BOOST_BIT); } else { return InterlockedBitTestAndReset(&Process->ProcessFlags, KPSF_DISABLE_BOOST_BIT); } } KPRIORITY NTAPI KeSetPriorityAndQuantumProcess(IN PKPROCESS Process, IN KPRIORITY Priority, IN UCHAR Quantum OPTIONAL) { KLOCK_QUEUE_HANDLE ProcessLock; KPRIORITY Delta; PLIST_ENTRY NextEntry, ListHead; KPRIORITY NewPriority, OldPriority; PKTHREAD Thread; ASSERT_PROCESS(Process); ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); /* Check if the process already has this priority */ if (Process->BasePriority == Priority) return Process->BasePriority; /* If the caller gave priority 0, normalize to 1 */ if (!Priority) Priority = LOW_PRIORITY + 1; /* Lock the process */ KiAcquireProcessLockRaiseToSynch(Process, &ProcessLock); /* 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 = (SCHAR)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; /* Acquire the thread lock */ KiAcquireThreadLock(Thread); /* 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 = (SCHAR)NewPriority; Thread->Quantum = Thread->QuantumReset; /* Disable decrements and update priority */ Thread->PriorityDecrement = 0; KiSetPriorityThread(Thread, NewPriority); } /* Release the thread lock */ KiReleaseThreadLock(Thread); /* 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; /* Lock the thread */ KiAcquireThreadLock(Thread); /* 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 = (SCHAR)NewPriority; Thread->Quantum = Thread->QuantumReset; /* Disable decrements and update priority */ Thread->PriorityDecrement = 0; KiSetPriorityThread(Thread, NewPriority); } /* Release the thread lock */ KiReleaseThreadLock(Thread); /* Go to the next thread */ NextEntry = NextEntry->Flink; } } /* Release Dispatcher Database */ KiReleaseDispatcherLockFromSynchLevel(); /* Release the process lock */ KiReleaseProcessLockFromSynchLevel(&ProcessLock); KiExitDispatcher(ProcessLock.OldIrql); /* Return previous priority */ return OldPriority; } VOID NTAPI KeQueryValuesProcess(IN PKPROCESS Process, PPROCESS_VALUES Values) { PEPROCESS EProcess; PLIST_ENTRY NextEntry; ULONG TotalKernel, TotalUser; KLOCK_QUEUE_HANDLE ProcessLock; ASSERT_PROCESS(Process); ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); /* Lock the process */ KiAcquireProcessLockRaiseToSynch(Process, &ProcessLock); /* Initialize user and kernel times */ TotalKernel = Process->KernelTime; TotalUser = Process->UserTime; /* Copy the IO_COUNTERS from the process */ EProcess = (PEPROCESS)Process; Values->IoInfo.ReadOperationCount = EProcess->ReadOperationCount.QuadPart; Values->IoInfo.WriteOperationCount = EProcess->WriteOperationCount.QuadPart; Values->IoInfo.OtherOperationCount = EProcess->OtherOperationCount.QuadPart; Values->IoInfo.ReadTransferCount = EProcess->ReadTransferCount.QuadPart; Values->IoInfo.WriteTransferCount = EProcess->WriteTransferCount.QuadPart; Values->IoInfo.OtherTransferCount = EProcess->OtherTransferCount.QuadPart; /* Loop all child threads and sum up their times */ for (NextEntry = Process->ThreadListHead.Flink; NextEntry != &Process->ThreadListHead; NextEntry = NextEntry->Flink) { PKTHREAD Thread; /* Get the thread */ Thread = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry); /* Sum up times */ TotalKernel += Thread->KernelTime; TotalUser += Thread->UserTime; } /* Release the process lock */ KiReleaseProcessLock(&ProcessLock); /* Compute total times */ Values->TotalKernelTime.QuadPart = TotalKernel * (LONGLONG)KeMaximumIncrement; Values->TotalUserTime.QuadPart = TotalUser * (LONGLONG)KeMaximumIncrement; } /* PUBLIC FUNCTIONS **********************************************************/ /* * @implemented */ VOID NTAPI KeAttachProcess(IN PKPROCESS Process) { KLOCK_QUEUE_HANDLE ApcLock; PKTHREAD Thread = KeGetCurrentThread(); ASSERT_PROCESS(Process); ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); /* Check if we're already in that process */ if (Thread->ApcState.Process == Process) return; /* Check if a DPC is executing or if we're already attached */ if ((Thread->ApcStateIndex != OriginalApcEnvironment) || (KeIsExecutingDpc())) { /* Invalid attempt */ KeBugCheckEx(INVALID_PROCESS_ATTACH_ATTEMPT, (ULONG_PTR)Process, (ULONG_PTR)Thread->ApcState.Process, Thread->ApcStateIndex, KeIsExecutingDpc()); } else { /* Acquire APC Lock */ KiAcquireApcLockRaiseToSynch(Thread, &ApcLock); /* Acquire the dispatcher lock */ KiAcquireDispatcherLockAtSynchLevel(); /* Legit attach attempt: do it! */ KiAttachProcess(Thread, Process, &ApcLock, &Thread->SavedApcState); } } /* * @implemented */ VOID NTAPI KeDetachProcess(VOID) { PKTHREAD Thread = KeGetCurrentThread(); KLOCK_QUEUE_HANDLE ApcLock; PKPROCESS Process; ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); /* Check if it's attached */ if (Thread->ApcStateIndex == OriginalApcEnvironment) return; /* Acquire APC Lock */ KiAcquireApcLockRaiseToSynch(Thread, &ApcLock); /* Check for invalid attach attempts */ if ((Thread->ApcState.KernelApcInProgress) || !(IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode])) || !(IsListEmpty(&Thread->ApcState.ApcListHead[UserMode]))) { /* Crash the system */ KeBugCheck(INVALID_PROCESS_DETACH_ATTEMPT); } /* Get the process */ Process = Thread->ApcState.Process; /* Acquire dispatcher lock */ KiAcquireDispatcherLockAtSynchLevel(); /* Decrease the stack count */ ASSERT(Process->StackCount != 0); ASSERT(Process->State == ProcessInMemory); Process->StackCount--; /* Check if we can swap the process out */ if (!Process->StackCount) { /* FIXME: Swap the process out */ } /* Release dispatcher lock */ KiReleaseDispatcherLockFromSynchLevel(); /* Restore the APC State */ KiMoveApcState(&Thread->SavedApcState, &Thread->ApcState); Thread->SavedApcState.Process = NULL; Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->ApcState; Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->SavedApcState; Thread->ApcStateIndex = OriginalApcEnvironment; /* Release lock */ KiReleaseApcLockFromSynchLevel(&ApcLock); /* Swap Processes */ KiSwapProcess(Thread->ApcState.Process, Process); /* Exit the dispatcher */ KiExitDispatcher(ApcLock.OldIrql); /* Check if we have pending APCs */ if (!(IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode]))) { /* What do you know, we do! Request them to be delivered */ Thread->ApcState.KernelApcPending = TRUE; HalRequestSoftwareInterrupt(APC_LEVEL); } } /* * @implemented */ BOOLEAN NTAPI KeIsAttachedProcess(VOID) { /* Return the APC State */ return KeGetCurrentThread()->ApcStateIndex; } /* * @implemented */ VOID NTAPI KeStackAttachProcess(IN PKPROCESS Process, OUT PRKAPC_STATE ApcState) { KLOCK_QUEUE_HANDLE ApcLock; PKTHREAD Thread = KeGetCurrentThread(); ASSERT_PROCESS(Process); ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); /* Crash system if DPC is being executed! */ if (KeIsExecutingDpc()) { /* Executing a DPC, crash! */ KeBugCheckEx(INVALID_PROCESS_ATTACH_ATTEMPT, (ULONG_PTR)Process, (ULONG_PTR)Thread->ApcState.Process, Thread->ApcStateIndex, KeIsExecutingDpc()); } /* Check if we are already in the target process */ if (Thread->ApcState.Process == Process) { /* Set magic value so we don't crash later when detaching */ ApcState->Process = (PKPROCESS)1; return; } /* Acquire APC Lock */ KiAcquireApcLockRaiseToSynch(Thread, &ApcLock); /* Acquire dispatcher lock */ KiAcquireDispatcherLockAtSynchLevel(); /* Check if the Current Thread is already attached */ if (Thread->ApcStateIndex != OriginalApcEnvironment) { /* We're already attached, so save the APC State into what we got */ KiAttachProcess(Thread, Process, &ApcLock, ApcState); } else { /* We're not attached, so save the APC State into SavedApcState */ KiAttachProcess(Thread, Process, &ApcLock, &Thread->SavedApcState); ApcState->Process = NULL; } } /* * @implemented */ VOID NTAPI KeUnstackDetachProcess(IN PRKAPC_STATE ApcState) { KLOCK_QUEUE_HANDLE ApcLock; PKTHREAD Thread = KeGetCurrentThread(); PKPROCESS Process; ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); /* Check for magic value meaning we were already in the same process */ if (ApcState->Process == (PKPROCESS)1) return; /* Loop to make sure no APCs are pending */ for (;;) { /* Acquire APC Lock */ KiAcquireApcLockRaiseToSynch(Thread, &ApcLock); /* Check if a kernel APC is pending */ if (Thread->ApcState.KernelApcPending) { /* Check if kernel APC should be delivered */ if (!(Thread->KernelApcDisable) && (ApcLock.OldIrql <= APC_LEVEL)) { /* Release the APC lock so that the APC can be delivered */ KiReleaseApcLock(&ApcLock); continue; } } /* Otherwise, break out */ break; } /* * Check if the process isn't attacked, or has a Kernel APC in progress * or has pending APC of any kind. */ if ((Thread->ApcStateIndex == OriginalApcEnvironment) || (Thread->ApcState.KernelApcInProgress) || (!IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode])) || (!IsListEmpty(&Thread->ApcState.ApcListHead[UserMode]))) { /* Bugcheck the system */ KeBugCheck(INVALID_PROCESS_DETACH_ATTEMPT); } /* Get the process */ Process = Thread->ApcState.Process; /* Acquire dispatcher lock */ KiAcquireDispatcherLockAtSynchLevel(); /* Decrease the stack count */ ASSERT(Process->StackCount != 0); ASSERT(Process->State == ProcessInMemory); Process->StackCount--; /* Check if we can swap the process out */ if (!Process->StackCount) { /* FIXME: Swap the process out */ } /* Release dispatcher lock */ KiReleaseDispatcherLockFromSynchLevel(); /* Check if there's an APC state to restore */ if (ApcState->Process) { /* Restore the APC State */ KiMoveApcState(ApcState, &Thread->ApcState); } else { /* The ApcState parameter is useless, so use the saved data and reset it */ KiMoveApcState(&Thread->SavedApcState, &Thread->ApcState); Thread->SavedApcState.Process = NULL; Thread->ApcStateIndex = OriginalApcEnvironment; Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->ApcState; Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->SavedApcState; } /* Release lock */ KiReleaseApcLockFromSynchLevel(&ApcLock); /* Swap Processes */ KiSwapProcess(Thread->ApcState.Process, Process); /* Exit the dispatcher */ KiExitDispatcher(ApcLock.OldIrql); /* Check if we have pending APCs */ if (!(IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode]))) { /* What do you know, we do! Request them to be delivered */ Thread->ApcState.KernelApcPending = TRUE; HalRequestSoftwareInterrupt(APC_LEVEL); } } /* * @implemented */ ULONG NTAPI KeQueryRuntimeProcess(IN PKPROCESS Process, OUT PULONG UserTime) { ULONG TotalUser, TotalKernel; KLOCK_QUEUE_HANDLE ProcessLock; PLIST_ENTRY NextEntry, ListHead; PKTHREAD Thread; ASSERT_PROCESS(Process); /* Initialize user and kernel times */ TotalUser = Process->UserTime; TotalKernel = Process->KernelTime; /* Lock the process */ KiAcquireProcessLockRaiseToSynch(Process, &ProcessLock); /* Loop all child threads and sum up their times */ ListHead = &Process->ThreadListHead; NextEntry = ListHead->Flink; while (ListHead != NextEntry) { /* Get the thread */ Thread = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry); /* Sum up times */ TotalKernel += Thread->KernelTime; TotalUser += Thread->UserTime; /* Go to the next one */ NextEntry = NextEntry->Flink; } /* Release lock */ KiReleaseProcessLock(&ProcessLock); /* Return the user time */ *UserTime = TotalUser; /* Return the kernel time */ return TotalKernel; } /* * @implemented */ BOOLEAN NTAPI KeAddSystemServiceTable(IN PULONG_PTR Base, IN PULONG Count OPTIONAL, IN ULONG Limit, IN PUCHAR Number, IN ULONG Index) { PAGED_CODE(); /* Check if descriptor table entry is free */ if ((Index > SSDT_MAX_ENTRIES - 1) || (KeServiceDescriptorTable[Index].Base) || (KeServiceDescriptorTableShadow[Index].Base)) { /* It's not, fail */ return FALSE; } /* Initialize the shadow service descriptor table */ KeServiceDescriptorTableShadow[Index].Base = Base; KeServiceDescriptorTableShadow[Index].Limit = Limit; KeServiceDescriptorTableShadow[Index].Number = Number; KeServiceDescriptorTableShadow[Index].Count = Count; return TRUE; } /* * @implemented */ BOOLEAN NTAPI KeRemoveSystemServiceTable(IN ULONG Index) { PAGED_CODE(); /* Make sure the Index is valid */ if (Index > (SSDT_MAX_ENTRIES - 1)) return FALSE; /* Is there a Normal Descriptor Table? */ if (!KeServiceDescriptorTable[Index].Base) { /* Not with the index, is there a shadow at least? */ if (!KeServiceDescriptorTableShadow[Index].Base) return FALSE; } /* Now clear from the Shadow Table. */ KeServiceDescriptorTableShadow[Index].Base = NULL; KeServiceDescriptorTableShadow[Index].Number = NULL; KeServiceDescriptorTableShadow[Index].Limit = 0; KeServiceDescriptorTableShadow[Index].Count = NULL; /* Check if we should clean from the Master one too */ if (Index == 1) { KeServiceDescriptorTable[Index].Base = NULL; KeServiceDescriptorTable[Index].Number = NULL; KeServiceDescriptorTable[Index].Limit = 0; KeServiceDescriptorTable[Index].Count = NULL; } /* Return success */ return TRUE; } /* EOF */