Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971/* * 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 <ntoskrnl.h>#define NDEBUG#include <debug.h>
/* 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 *********************************************************/
VOIDNTAPIKiAttachProcess(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); }}
VOIDNTAPIKeInitializeProcess(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}
ULONGNTAPIKeSetProcess(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;}
VOIDNTAPIKeSetQuantumProcess(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);}
KAFFINITYNTAPIKeSetAffinityProcess(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;}
BOOLEANNTAPIKeSetAutoAlignmentProcess(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); }}
BOOLEANNTAPIKeSetDisableBoostProcess(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); }}
KPRIORITYNTAPIKeSetPriorityAndQuantumProcess(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);
/* Acquire the dispatcher lock */ KiAcquireDispatcherLockAtSynchLevel();
/* 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;}
VOIDNTAPIKeQueryValuesProcess(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 */VOIDNTAPIKeAttachProcess(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 */VOIDNTAPIKeDetachProcess(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 */BOOLEANNTAPIKeIsAttachedProcess(VOID){ /* Return the APC State */ return KeGetCurrentThread()->ApcStateIndex;}
/* * @implemented */VOIDNTAPIKeStackAttachProcess(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 */VOIDNTAPIKeUnstackDetachProcess(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 */ULONGNTAPIKeQueryRuntimeProcess(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 */BOOLEANNTAPIKeAddSystemServiceTable(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 */BOOLEANNTAPIKeRemoveSystemServiceTable(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 */