859 lines
21 KiB
C
859 lines
21 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1989 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
procobj.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module implements the machine independent functions to manipulate
|
|||
|
the kernel process object. Functions are provided to initilaize, attach,
|
|||
|
detach, exclude, include, and set the base priority of process objects.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
David N. Cutler (davec) 7-Mar-1989
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
Kernel mode only.
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "ki.h"
|
|||
|
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
#pragma alloc_text(PAGE, KeInitializeProcess)
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Define forward referenced function prototypes.
|
|||
|
//
|
|||
|
|
|||
|
VOID
|
|||
|
KiAttachProcess (
|
|||
|
IN PKPROCESS Process,
|
|||
|
IN KIRQL OldIrql
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
KiMoveApcState (
|
|||
|
IN PKAPC_STATE Source,
|
|||
|
OUT PKAPC_STATE Destination
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// The following assert macro is used to check that an input process is
|
|||
|
// really a kprocess and not something else, like deallocated pool.
|
|||
|
//
|
|||
|
|
|||
|
#define ASSERT_PROCESS(E) { \
|
|||
|
ASSERT((E)->Header.Type == ProcessObject); \
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
KeInitializeProcess (
|
|||
|
IN PRKPROCESS Process,
|
|||
|
IN KPRIORITY BasePriority,
|
|||
|
IN KAFFINITY Affinity,
|
|||
|
IN ULONG DirectoryTableBase[2],
|
|||
|
IN BOOLEAN Enable
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function initializes a kernel process object. The base priority,
|
|||
|
affinity, and page frame numbers for the process page table directory
|
|||
|
and hyper space are stored in the process object.
|
|||
|
|
|||
|
N.B. It is assumed that the process object is zeroed.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Process - Supplies a pointer to a dispatcher object of type process.
|
|||
|
|
|||
|
BasePriority - Supplies the base priority of the process.
|
|||
|
|
|||
|
Affinity - Supplies the set of processors on which children threads
|
|||
|
of the process can execute.
|
|||
|
|
|||
|
DirectoryTableBase - Supplies a pointer to an array whose fist element
|
|||
|
is the value that is to be loaded into the Directory Table Base
|
|||
|
register when a child thread is dispatched for execution and whose
|
|||
|
second element contains the page table entry that maps hyper space.
|
|||
|
|
|||
|
Enable - Supplies a boolean value that determines the default
|
|||
|
handling of data alignment exceptions for child threads. A value
|
|||
|
of TRUE causes all data alignment exceptions to be automatically
|
|||
|
handled by the kernel. A value of FALSE causes all data alignment
|
|||
|
exceptions to be actually raised as exceptions.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the standard dispatcher object header and set the initial
|
|||
|
// signal state of the process object.
|
|||
|
//
|
|||
|
|
|||
|
Process->Header.Type = ProcessObject;
|
|||
|
Process->Header.Size = sizeof(KPROCESS) / sizeof(LONG);
|
|||
|
InitializeListHead(&Process->Header.WaitListHead);
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the base priority, affinity, directory table base values,
|
|||
|
// autoalignment, and stack count.
|
|||
|
//
|
|||
|
// N.B. The distinguished value MAXSHORT is used to signify that no
|
|||
|
// threads have been created for the process.
|
|||
|
//
|
|||
|
|
|||
|
Process->BasePriority = (SCHAR)BasePriority;
|
|||
|
Process->Affinity = Affinity;
|
|||
|
Process->AutoAlignment = Enable;
|
|||
|
Process->DirectoryTableBase[0] = DirectoryTableBase[0];
|
|||
|
Process->DirectoryTableBase[1] = DirectoryTableBase[1];
|
|||
|
Process->StackCount = MAXSHORT;
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the stack count, profile listhead, ready queue list head,
|
|||
|
// accumulated runtime, process quantum, thread quantum, and thread list
|
|||
|
// head.
|
|||
|
//
|
|||
|
|
|||
|
InitializeListHead(&Process->ProfileListHead);
|
|||
|
InitializeListHead(&Process->ReadyListHead);
|
|||
|
InitializeListHead(&Process->ThreadListHead);
|
|||
|
Process->ThreadQuantum = THREAD_QUANTUM;
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the process state and set the thread processor selection
|
|||
|
// seed.
|
|||
|
//
|
|||
|
|
|||
|
Process->State = ProcessInMemory;
|
|||
|
Process->ThreadSeed = (UCHAR)KiQueryLowTickCount();
|
|||
|
|
|||
|
//
|
|||
|
// Initialize Ldt descriptor for this process (i386 only)
|
|||
|
//
|
|||
|
|
|||
|
#ifdef i386
|
|||
|
|
|||
|
//
|
|||
|
// Initialize IopmBase and Iopl flag for this process (i386 only)
|
|||
|
//
|
|||
|
|
|||
|
Process->IopmOffset = KiComputeIopmOffset(IO_ACCESS_MAP_NONE);
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
KeAttachProcess (
|
|||
|
IN PRKPROCESS Process
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function attaches a thread to a target process' address space.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Process - Supplies a pointer to a dispatcher object of type process.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
KIRQL OldIrql;
|
|||
|
|
|||
|
ASSERT_PROCESS(Process);
|
|||
|
ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
|
|||
|
|
|||
|
//
|
|||
|
// Raise IRQL to dispatcher level and lock dispatcher database.
|
|||
|
//
|
|||
|
|
|||
|
KiLockDispatcherDatabase(&OldIrql);
|
|||
|
|
|||
|
//
|
|||
|
// Attach target process.
|
|||
|
//
|
|||
|
|
|||
|
KiAttachProcess(Process, OldIrql);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
KeTryToAttachProcess (
|
|||
|
IN PRKPROCESS Process
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function tries to attach a thread to a target process' address
|
|||
|
space. If the target process is in memory or out of memory, then the
|
|||
|
target process is attached. Otherwise, it is not attached.
|
|||
|
|
|||
|
N.B. If the target process state is out of memory, then the caller
|
|||
|
must have all pages for the process in memory. This function is
|
|||
|
intended for use by the memory management system.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Process - Supplies a pointer to a dispatcher object of type process.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
If the target process state is not in transistion, then the target
|
|||
|
process is atached and a value of TRUE is returned. Otherwise, a
|
|||
|
value of FALSE is returned.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
KIRQL OldIrql;
|
|||
|
|
|||
|
ASSERT_PROCESS(Process);
|
|||
|
ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
|
|||
|
|
|||
|
//
|
|||
|
// Raise IRQL to dispatcher level and lock dispatcher database.
|
|||
|
//
|
|||
|
|
|||
|
KiLockDispatcherDatabase(&OldIrql);
|
|||
|
|
|||
|
//
|
|||
|
// If the target process state is not in transition, then set the
|
|||
|
// target process state to in memory, attach the process, and return
|
|||
|
// a value of TRUE. Otherwise, unlock the dispatcher database and
|
|||
|
// return a value of FALSE.
|
|||
|
//
|
|||
|
|
|||
|
if (Process->State != ProcessInTransition) {
|
|||
|
Process->State = ProcessInMemory;
|
|||
|
KiAttachProcess(Process, OldIrql);
|
|||
|
return TRUE;
|
|||
|
|
|||
|
} else {
|
|||
|
KiUnlockDispatcherDatabase(OldIrql);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
KeDetachProcess (
|
|||
|
VOID
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function detaches a thread from another process' address space.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
KIRQL OldIrql;
|
|||
|
PKPROCESS Process;
|
|||
|
PKTHREAD Thread;
|
|||
|
|
|||
|
ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
|
|||
|
|
|||
|
//
|
|||
|
// Raise IRQL to dispatcher level and lock dispatcher database.
|
|||
|
//
|
|||
|
|
|||
|
Thread = KeGetCurrentThread();
|
|||
|
KiLockDispatcherDatabase(&OldIrql);
|
|||
|
|
|||
|
//
|
|||
|
// If the current thread is attached to another address, then detach
|
|||
|
// it.
|
|||
|
//
|
|||
|
|
|||
|
if (Thread->ApcStateIndex != 0) {
|
|||
|
|
|||
|
//
|
|||
|
// Check if a kernel APC is in progress, the kernel APC queue is
|
|||
|
// not empty, or the user APC queue is not empty. If any of these
|
|||
|
// conditions are true, then call bug check.
|
|||
|
//
|
|||
|
|
|||
|
#if DBG
|
|||
|
|
|||
|
if ((Thread->ApcState.KernelApcInProgress) ||
|
|||
|
(IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode]) == FALSE) ||
|
|||
|
(IsListEmpty(&Thread->ApcState.ApcListHead[UserMode]) == FALSE)) {
|
|||
|
KeBugCheck(INVALID_PROCESS_DETACH_ATTEMPT);
|
|||
|
}
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// Unbias current process stack count and check if the process should
|
|||
|
// be swapped out of memory.
|
|||
|
//
|
|||
|
|
|||
|
Process = Thread->ApcState.Process;
|
|||
|
Process->StackCount -= 1;
|
|||
|
if (Process->StackCount == 0) {
|
|||
|
Process->State = ProcessInTransition;
|
|||
|
InsertTailList(&KiProcessOutSwapListHead, &Process->SwapListEntry);
|
|||
|
KiSwapEvent.Header.SignalState = 1;
|
|||
|
if (IsListEmpty(&KiSwapEvent.Header.WaitListHead) == FALSE) {
|
|||
|
KiWaitTest(&KiSwapEvent, BALANCE_INCREMENT);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Restore APC state and check whether the kernel APC queue contains
|
|||
|
// an entry. If the kernel APC queue contains an entry then set kernel
|
|||
|
// APC pending and request a software interrupt at APC_LEVEL.
|
|||
|
//
|
|||
|
|
|||
|
KiMoveApcState(&Thread->SavedApcState, &Thread->ApcState);
|
|||
|
Thread->SavedApcState.Process = (PKPROCESS)NULL;
|
|||
|
Thread->ApcStatePointer[0] = &Thread->ApcState;
|
|||
|
Thread->ApcStatePointer[1] = &Thread->SavedApcState;
|
|||
|
Thread->ApcStateIndex = 0;
|
|||
|
if (IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode]) == FALSE) {
|
|||
|
Thread->ApcState.KernelApcPending = TRUE;
|
|||
|
KiRequestSoftwareInterrupt(APC_LEVEL);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Swap the address space back to the parent process.
|
|||
|
//
|
|||
|
|
|||
|
KiSwapProcess(Thread->ApcState.Process, Process);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Lower IRQL to its previous value and return.
|
|||
|
//
|
|||
|
|
|||
|
KiUnlockDispatcherDatabase(OldIrql);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
LONG
|
|||
|
KeReadStateProcess (
|
|||
|
IN PRKPROCESS Process
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function reads the current signal state of a process object.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Process - Supplies a pointer to a dispatcher object of type process.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The current signal state of the process object.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
ASSERT_PROCESS(Process);
|
|||
|
|
|||
|
//
|
|||
|
// Return current signal state of process object.
|
|||
|
//
|
|||
|
|
|||
|
return Process->Header.SignalState;
|
|||
|
}
|
|||
|
|
|||
|
LONG
|
|||
|
KeSetProcess (
|
|||
|
IN PRKPROCESS Process,
|
|||
|
IN KPRIORITY Increment,
|
|||
|
IN BOOLEAN Wait
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function sets the signal state of a proces object to Signaled
|
|||
|
and attempts to satisfy as many Waits as possible. The previous
|
|||
|
signal state of the process object is returned as the function value.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Process - Supplies a pointer to a dispatcher object of type process.
|
|||
|
|
|||
|
Increment - Supplies the priority increment that is to be applied
|
|||
|
if setting the process causes a Wait to be satisfied.
|
|||
|
|
|||
|
Wait - Supplies a boolean value that signifies whether the call to
|
|||
|
KeSetProcess will be immediately followed by a call to one of the
|
|||
|
kernel Wait functions.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The previous signal state of the process object.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
KIRQL OldIrql;
|
|||
|
LONG OldState;
|
|||
|
PRKTHREAD Thread;
|
|||
|
|
|||
|
ASSERT_PROCESS(Process);
|
|||
|
ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
|
|||
|
|
|||
|
//
|
|||
|
// Raise IRQL to dispatcher level and lock dispatcher database.
|
|||
|
//
|
|||
|
|
|||
|
KiLockDispatcherDatabase(&OldIrql);
|
|||
|
|
|||
|
//
|
|||
|
// If the previous state of the process object is Not-Signaled and
|
|||
|
// the wait queue is not empty, then satisfy as many Waits as
|
|||
|
// possible.
|
|||
|
//
|
|||
|
|
|||
|
OldState = Process->Header.SignalState;
|
|||
|
Process->Header.SignalState = 1;
|
|||
|
if ((OldState == 0) && (!IsListEmpty(&Process->Header.WaitListHead))) {
|
|||
|
KiWaitTest(Process, Increment);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If the value of the Wait argument is TRUE, then return to the
|
|||
|
// caller with IRQL raised and the dispatcher database locked. Else
|
|||
|
// release the dispatcher database lock and lower IRQL to its
|
|||
|
// previous value.
|
|||
|
//
|
|||
|
|
|||
|
if (Wait) {
|
|||
|
Thread = KeGetCurrentThread();
|
|||
|
Thread->WaitNext = Wait;
|
|||
|
Thread->WaitIrql = OldIrql;
|
|||
|
|
|||
|
} else {
|
|||
|
KiUnlockDispatcherDatabase(OldIrql);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Return previous signal state of process object.
|
|||
|
//
|
|||
|
|
|||
|
return OldState;
|
|||
|
}
|
|||
|
|
|||
|
KPRIORITY
|
|||
|
KeSetPriorityProcess (
|
|||
|
IN PKPROCESS Process,
|
|||
|
IN KPRIORITY NewBase
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function set the base priority of a process to a new value
|
|||
|
and adjusts the priority and base priority of all child threads
|
|||
|
as appropriate.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Process - Supplies a pointer to a dispatcher object of type process.
|
|||
|
|
|||
|
NewBase - Supplies the new base priority of the process.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The previous base priority of the process.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
KPRIORITY Adjustment;
|
|||
|
PLIST_ENTRY NextEntry;
|
|||
|
KPRIORITY NewPriority;
|
|||
|
KIRQL OldIrql;
|
|||
|
KPRIORITY OldBase;
|
|||
|
PKTHREAD Thread;
|
|||
|
|
|||
|
ASSERT_PROCESS(Process);
|
|||
|
ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
|
|||
|
|
|||
|
//
|
|||
|
// Raise IRQL to dispatcher level and lock dispatcher database.
|
|||
|
//
|
|||
|
|
|||
|
KiLockDispatcherDatabase(&OldIrql);
|
|||
|
|
|||
|
//
|
|||
|
// Save the current process base priority, set the new process base
|
|||
|
// priority, compute the adjustment value, and adjust the priority
|
|||
|
// and base priority of all child threads as appropriate.
|
|||
|
//
|
|||
|
|
|||
|
OldBase = Process->BasePriority;
|
|||
|
Process->BasePriority = (SCHAR)NewBase;
|
|||
|
Adjustment = NewBase - OldBase;
|
|||
|
NextEntry = Process->ThreadListHead.Flink;
|
|||
|
if (NewBase >= LOW_REALTIME_PRIORITY) {
|
|||
|
while (NextEntry != &Process->ThreadListHead) {
|
|||
|
Thread = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry);
|
|||
|
|
|||
|
//
|
|||
|
// Compute the new base priority of the thread.
|
|||
|
//
|
|||
|
|
|||
|
NewPriority = Thread->BasePriority + Adjustment;
|
|||
|
|
|||
|
//
|
|||
|
// If the new base priority is outside the realtime class,
|
|||
|
// then limit the change to the realtime class.
|
|||
|
//
|
|||
|
|
|||
|
if (NewPriority < LOW_REALTIME_PRIORITY) {
|
|||
|
NewPriority = LOW_REALTIME_PRIORITY;
|
|||
|
|
|||
|
} else if (NewPriority > HIGH_PRIORITY) {
|
|||
|
NewPriority = HIGH_PRIORITY;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Set the base priority and the current priority of the
|
|||
|
// thread to the computed value and reset the thread quantum.
|
|||
|
//
|
|||
|
// N.B. If priority saturation occured the last time the thread
|
|||
|
// base priority was set and the new process base priority
|
|||
|
// is not crossing from variable to realtime, then the thread
|
|||
|
// priority is not changed.
|
|||
|
//
|
|||
|
|
|||
|
if ((Thread->Saturation == FALSE) || (OldBase < LOW_REALTIME_PRIORITY)) {
|
|||
|
Thread->BasePriority = (SCHAR)NewPriority;
|
|||
|
Thread->Quantum = Process->ThreadQuantum;
|
|||
|
Thread->DecrementCount = 0;
|
|||
|
Thread->PriorityDecrement = 0;
|
|||
|
Thread->Saturation = FALSE;
|
|||
|
KiSetPriorityThread(Thread, NewPriority);
|
|||
|
}
|
|||
|
|
|||
|
NextEntry = NextEntry->Flink;
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
while (NextEntry != &Process->ThreadListHead) {
|
|||
|
Thread = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry);
|
|||
|
|
|||
|
//
|
|||
|
// Compute the new base priority of the thread.
|
|||
|
//
|
|||
|
|
|||
|
NewPriority = Thread->BasePriority + Adjustment;
|
|||
|
|
|||
|
//
|
|||
|
// If the new base priority is outside the variable class,
|
|||
|
// then limit the change to the variable class.
|
|||
|
//
|
|||
|
|
|||
|
if (NewPriority >= LOW_REALTIME_PRIORITY) {
|
|||
|
NewPriority = LOW_REALTIME_PRIORITY - 1;
|
|||
|
|
|||
|
} else if (NewPriority <= LOW_PRIORITY) {
|
|||
|
NewPriority = 1;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Set the base priority and the current priority of the
|
|||
|
// thread to the computed value and reset the thread quantum.
|
|||
|
//
|
|||
|
// N.B. If priority saturation occured the last time the thread
|
|||
|
// base priority was set and the new process base priority
|
|||
|
// is not crossing from realtime to variable, then the thread
|
|||
|
// priority is not changed.
|
|||
|
//
|
|||
|
|
|||
|
if ((Thread->Saturation == FALSE) || (OldBase >= LOW_REALTIME_PRIORITY)) {
|
|||
|
Thread->BasePriority = (SCHAR)NewPriority;
|
|||
|
Thread->Quantum = Process->ThreadQuantum;
|
|||
|
Thread->DecrementCount = 0;
|
|||
|
Thread->PriorityDecrement = 0;
|
|||
|
Thread->Saturation = FALSE;
|
|||
|
KiSetPriorityThread(Thread, NewPriority);
|
|||
|
}
|
|||
|
|
|||
|
NextEntry = NextEntry->Flink;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Unlock dispatcher database and lower IRQL to its previous
|
|||
|
// value.
|
|||
|
//
|
|||
|
|
|||
|
KiUnlockDispatcherDatabase(OldIrql);
|
|||
|
|
|||
|
//
|
|||
|
// Return previous process base priority
|
|||
|
//
|
|||
|
|
|||
|
return OldBase;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
KiAttachProcess (
|
|||
|
IN PKPROCESS Process,
|
|||
|
IN KIRQL OldIrql
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function attaches a thread to a target process' address space.
|
|||
|
|
|||
|
N.B. The dispatcher database lock must be held when this routine is
|
|||
|
called.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Process - Supplies a pointer to a dispatcher object of type process.
|
|||
|
|
|||
|
Thread - Supplies a pointer to a dispatcher object of type thread.
|
|||
|
|
|||
|
OldIrql - Supplies the previous IRQL.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
PRKTHREAD Thread;
|
|||
|
KAFFINITY Processor;
|
|||
|
|
|||
|
//
|
|||
|
// Get the address of the current thread object.
|
|||
|
//
|
|||
|
|
|||
|
Thread = KeGetCurrentThread();
|
|||
|
|
|||
|
//
|
|||
|
// Check whether there is already a process address space attached or
|
|||
|
// the thread is executing a DPC. If either condition is true, then call
|
|||
|
// bug check.
|
|||
|
//
|
|||
|
|
|||
|
if (Process != Thread->ApcState.Process) {
|
|||
|
if ((Thread->ApcStateIndex != 0) ||
|
|||
|
(KeIsExecutingDpc() != FALSE)) {
|
|||
|
KeBugCheckEx(
|
|||
|
INVALID_PROCESS_ATTACH_ATTEMPT,
|
|||
|
(ULONG)Process,
|
|||
|
(ULONG)Thread->ApcState.Process,
|
|||
|
(ULONG)Thread->ApcStateIndex,
|
|||
|
(ULONG)KeIsExecutingDpc()
|
|||
|
);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If the target process is the same as the current process, then
|
|||
|
// there is no need to attach the address space. Otherwise, attach
|
|||
|
// the current thread to the target thread address space.
|
|||
|
//
|
|||
|
|
|||
|
if (Process == Thread->ApcState.Process) {
|
|||
|
KiUnlockDispatcherDatabase(OldIrql);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Bias the stack count of the target process to signify that a
|
|||
|
// thread exists in that process with a stack that is resident.
|
|||
|
//
|
|||
|
|
|||
|
Process->StackCount += 1;
|
|||
|
|
|||
|
//
|
|||
|
// Save current APC state and initialize A new APC state.
|
|||
|
//
|
|||
|
|
|||
|
KiMoveApcState(&Thread->ApcState, &Thread->SavedApcState);
|
|||
|
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;
|
|||
|
Thread->ApcStatePointer[0] = &Thread->SavedApcState;
|
|||
|
Thread->ApcStatePointer[1] = &Thread->ApcState;
|
|||
|
Thread->ApcStateIndex = 1;
|
|||
|
|
|||
|
//
|
|||
|
// If the target process is in memory, then immediately enter the
|
|||
|
// new address space by loading a new Directory Table Base. Otherwise,
|
|||
|
// insert the current thread in the target process ready list, inswap
|
|||
|
// the target process if necessary, select a new thread to run on the
|
|||
|
// the current processor and context switch to the new thread.
|
|||
|
//
|
|||
|
|
|||
|
if (Process->State == ProcessInMemory) {
|
|||
|
KiSwapProcess(Process, Thread->SavedApcState.Process);
|
|||
|
KiUnlockDispatcherDatabase(OldIrql);
|
|||
|
|
|||
|
} else {
|
|||
|
Thread->State = Ready;
|
|||
|
Thread->ProcessReadyQueue = TRUE;
|
|||
|
InsertTailList(&Process->ReadyListHead, &Thread->WaitListEntry);
|
|||
|
if (Process->State == ProcessOutOfMemory) {
|
|||
|
Process->State = ProcessInTransition;
|
|||
|
InsertTailList(&KiProcessInSwapListHead, &Process->SwapListEntry);
|
|||
|
KiSwapEvent.Header.SignalState = 1;
|
|||
|
if (IsListEmpty(&KiSwapEvent.Header.WaitListHead) == FALSE) {
|
|||
|
KiWaitTest(&KiSwapEvent, BALANCE_INCREMENT);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Clear the active processor bit in the previous process and
|
|||
|
// set active processor bit in the process being attached to.
|
|||
|
//
|
|||
|
|
|||
|
#if !defined(NT_UP)
|
|||
|
|
|||
|
Processor = KeGetCurrentPrcb()->SetMember;
|
|||
|
Thread->SavedApcState.Process->ActiveProcessors &= ~Processor;
|
|||
|
Process->ActiveProcessors |= Processor;
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
Thread->WaitIrql = OldIrql;
|
|||
|
|
|||
|
KiSwapThread();
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
KiMoveApcState (
|
|||
|
IN PKAPC_STATE Source,
|
|||
|
OUT PKAPC_STATE Destination
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function moves the APC state from the source structure to the
|
|||
|
destination structure and reinitializes list headers as appropriate.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Source - Supplies a pointer to the source APC state structure.
|
|||
|
|
|||
|
Destination - Supplies a pointer to the destination APC state structure.
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
PLIST_ENTRY First;
|
|||
|
PLIST_ENTRY Last;
|
|||
|
|
|||
|
//
|
|||
|
// Copy the APC state from the source to the destination.
|
|||
|
//
|
|||
|
|
|||
|
#if defined(_M_PPC) && (_MSC_VER >= 1000)
|
|||
|
KIRQL OldIrql;
|
|||
|
KeRaiseIrql(HIGH_LEVEL, &OldIrql);
|
|||
|
#endif
|
|||
|
|
|||
|
*Destination = *Source;
|
|||
|
|
|||
|
#if defined(_M_PPC) && (_MSC_VER >= 1000)
|
|||
|
KeLowerIrql(OldIrql);
|
|||
|
#endif
|
|||
|
|
|||
|
if (IsListEmpty(&Source->ApcListHead[KernelMode]) != FALSE) {
|
|||
|
InitializeListHead(&Destination->ApcListHead[KernelMode]);
|
|||
|
|
|||
|
} else {
|
|||
|
First = Source->ApcListHead[KernelMode].Flink;
|
|||
|
Last = Source->ApcListHead[KernelMode].Blink;
|
|||
|
Destination->ApcListHead[KernelMode].Flink = First;
|
|||
|
Destination->ApcListHead[KernelMode].Blink = Last;
|
|||
|
First->Blink = &Destination->ApcListHead[KernelMode];
|
|||
|
Last->Flink = &Destination->ApcListHead[KernelMode];
|
|||
|
}
|
|||
|
|
|||
|
if (IsListEmpty(&Source->ApcListHead[UserMode]) != FALSE) {
|
|||
|
InitializeListHead(&Destination->ApcListHead[UserMode]);
|
|||
|
|
|||
|
} else {
|
|||
|
First = Source->ApcListHead[UserMode].Flink;
|
|||
|
Last = Source->ApcListHead[UserMode].Blink;
|
|||
|
Destination->ApcListHead[UserMode].Flink = First;
|
|||
|
Destination->ApcListHead[UserMode].Blink = Last;
|
|||
|
First->Blink = &Destination->ApcListHead[UserMode];
|
|||
|
Last->Flink = &Destination->ApcListHead[UserMode];
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
}
|