Remove ps/create.c, it did not fit with the current model of abstraction. Major cleanup of ps/process.c, created ps/notify.c and ps/quota.c. Implemented NtOpenProcess, PsRemoveLoadImageNotifyRoutine, PsGetCurrentProcessSessionId

svn path=/trunk/; revision=14662
This commit is contained in:
Alex Ionescu 2005-04-18 02:12:30 +00:00
parent 781c6b374f
commit f4d2ac0b1e
12 changed files with 1712 additions and 1726 deletions

View file

@ -222,7 +222,6 @@ OBJECTS_OB = \
# Process Manager (Ps)
OBJECTS_PS = \
ps/cid.o \
ps/create.o \
ps/debug.o \
ps/idle.o \
ps/job.o \
@ -230,6 +229,8 @@ OBJECTS_PS = \
ps/locale.o \
ps/process.o \
ps/psmgr.o \
ps/notify.o \
ps/quota.o \
ps/query.o \
ps/security.o \
ps/suspend.o \

View file

@ -97,6 +97,10 @@ STDCALL
KiUnblockThread(PKTHREAD Thread,
PNTSTATUS WaitStatus,
KPRIORITY Increment);
NTSTATUS
STDCALL
KeSuspendThread(PKTHREAD Thread);
/* gmutex.c ********************************************************************/

View file

@ -533,6 +533,12 @@ PspExitThread(NTSTATUS ExitStatus);
extern LIST_ENTRY PspReaperListHead;
extern WORK_QUEUE_ITEM PspReaperWorkItem;
extern BOOLEAN PspReaping;
extern PEPROCESS PsInitialSystemProcess;
extern PEPROCESS PsIdleProcess;
extern POBJECT_TYPE PsProcessType;
extern LIST_ENTRY PsActiveProcessHead;
extern FAST_MUTEX PspActiveProcessMutex;
extern LARGE_INTEGER ShortPsLockDelay, PsLockTimeout;
VOID
STDCALL
@ -544,7 +550,7 @@ VOID PsFreezeOtherThread(PETHREAD Thread);
VOID PsFreezeProcessThreads(PEPROCESS Process);
VOID PsUnfreezeProcessThreads(PEPROCESS Process);
ULONG PsEnumThreadsByProcess(PEPROCESS Process);
PEPROCESS PsGetNextProcess(PEPROCESS OldProcess);
PEPROCESS STDCALL PsGetNextProcess(PEPROCESS OldProcess);
VOID
PsApplicationProcessorInit(VOID);
VOID
@ -679,6 +685,9 @@ VOID PsUnlockProcess(PEPROCESS Process);
#define EPROCESS_TO_KPROCESS(pEProcess) (&(pEProcess)->Pcb)
#define KPROCESS_TO_EPROCESS(pKProcess) (CONTAINING_RECORD((pKProcess), EPROCESS, Pcb))
#define MAX_PROCESS_NOTIFY_ROUTINE_COUNT 8
#define MAX_LOAD_IMAGE_NOTIFY_ROUTINE_COUNT 8
#endif /* ASSEMBLER */
#endif /* __INCLUDE_INTERNAL_PS_H */

View file

@ -53,6 +53,16 @@ UpdatePageDirs(PKTHREAD Thread, PKPROCESS Process)
MmUpdatePageDir((PEPROCESS)Process, (PVOID)Thread, sizeof(ETHREAD));
}
/*
* FUNCTION: Returns a pointer to the current process
*/
PKPROCESS
STDCALL
KeGetCurrentProcess(VOID)
{
return(&(PsGetCurrentProcess()->Pcb));
}
VOID
STDCALL
KeInitializeProcess(PKPROCESS Process,

View file

@ -1,642 +0,0 @@
/* $Id$
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/ps/create.c
* PURPOSE: Thread managment
*
* PROGRAMMERS: David Welch (welch@mcmail.com)
* Phillip Susi
* Skywing
*/
/*
* NOTE:
*
* All of the routines that manipulate the thread queue synchronize on
* a single spinlock
*
*/
/* INCLUDES ****************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <internal/debug.h>
/* GLOBAL *******************************************************************/
#define MAX_THREAD_NOTIFY_ROUTINE_COUNT 8
#define TAG_KAPC TAG('k','p','a','p') /* kpap - kernel ps apc */
static ULONG PiThreadNotifyRoutineCount = 0;
static PCREATE_THREAD_NOTIFY_ROUTINE
PiThreadNotifyRoutine[MAX_THREAD_NOTIFY_ROUTINE_COUNT];
ULONG
STDCALL
KeSuspendThread(PKTHREAD Thread);
/* FUNCTIONS ***************************************************************/
VOID
PiBeforeBeginThread(CONTEXT c)
{
KeLowerIrql(PASSIVE_LEVEL);
}
NTSTATUS
PsInitializeThread (
PEPROCESS Process,
PETHREAD* ThreadPtr,
POBJECT_ATTRIBUTES ObjectAttributes,
KPROCESSOR_MODE AccessMode,
BOOLEAN First )
{
PETHREAD Thread;
NTSTATUS Status;
KIRQL oldIrql;
PAGED_CODE();
if (Process == NULL)
{
Process = PsInitialSystemProcess;
}
/*
* Create and initialize thread
*/
Status = ObCreateObject(AccessMode,
PsThreadType,
ObjectAttributes,
KernelMode,
NULL,
sizeof(ETHREAD),
0,
0,
(PVOID*)&Thread);
if (!NT_SUCCESS(Status))
{
return(Status);
}
/*
* Reference process
*/
ObReferenceObjectByPointer(Process,
PROCESS_CREATE_THREAD,
PsProcessType,
KernelMode);
Thread->ThreadsProcess = Process;
Thread->Cid.UniqueThread = NULL;
Thread->Cid.UniqueProcess = (HANDLE)Thread->ThreadsProcess->UniqueProcessId;
DPRINT("Thread = %x\n",Thread);
KeInitializeThread(&Process->Pcb, &Thread->Tcb, First);
InitializeListHead(&Thread->ActiveTimerListHead);
KeInitializeSpinLock(&Thread->ActiveTimerListLock);
InitializeListHead(&Thread->IrpList);
Thread->DeadThread = FALSE;
Thread->HasTerminated = FALSE;
Thread->Tcb.Win32Thread = NULL;
DPRINT("Thread->Cid.UniqueThread %d\n",Thread->Cid.UniqueThread);
Thread->Tcb.BasePriority = (CHAR)Process->Pcb.BasePriority;
Thread->Tcb.Priority = Thread->Tcb.BasePriority;
/*
* Local Procedure Call facility (LPC)
*/
KeInitializeSemaphore (& Thread->LpcReplySemaphore, 0, LONG_MAX);
Thread->LpcReplyMessage = NULL;
Thread->LpcReplyMessageId = 0; /* not valid */
/* Thread->LpcReceiveMessageId = 0; */
Thread->LpcExitThreadCalled = FALSE;
Thread->LpcReceivedMsgIdValid = FALSE;
oldIrql = KeAcquireDispatcherDatabaseLock();
InsertTailList(&Process->ThreadListHead,
&Thread->ThreadListEntry);
KeReleaseDispatcherDatabaseLock(oldIrql);
*ThreadPtr = Thread;
return STATUS_SUCCESS;
}
static NTSTATUS
PsCreateTeb (
HANDLE ProcessHandle,
PTEB *TebPtr,
PETHREAD Thread,
PINITIAL_TEB InitialTeb )
{
PEPROCESS Process;
NTSTATUS Status;
ULONG ByteCount;
ULONG RegionSize;
ULONG TebSize;
PVOID TebBase;
TEB Teb;
PAGED_CODE();
TebSize = PAGE_SIZE;
if (NULL == Thread->ThreadsProcess)
{
/* We'll be allocating a 64k block here and only use 4k of it, but this
path should almost never be taken. Actually, I never saw it was taken,
so maybe we should just ASSERT(NULL != Thread->ThreadsProcess) and
move on */
TebBase = NULL;
Status = ZwAllocateVirtualMemory(ProcessHandle,
&TebBase,
0,
&TebSize,
MEM_RESERVE | MEM_COMMIT | MEM_TOP_DOWN,
PAGE_READWRITE);
if (! NT_SUCCESS(Status))
{
DPRINT1("Failed to allocate virtual memory for TEB\n");
return Status;
}
}
else
{
Process = Thread->ThreadsProcess;
PsLockProcess(Process, FALSE);
if (NULL == Process->TebBlock ||
Process->TebBlock == Process->TebLastAllocated)
{
Process->TebBlock = NULL;
RegionSize = MM_VIRTMEM_GRANULARITY;
Status = ZwAllocateVirtualMemory(ProcessHandle,
&Process->TebBlock,
0,
&RegionSize,
MEM_RESERVE | MEM_TOP_DOWN,
PAGE_READWRITE);
if (! NT_SUCCESS(Status))
{
PsUnlockProcess(Process);
DPRINT1("Failed to reserve virtual memory for TEB\n");
return Status;
}
Process->TebLastAllocated = (PVOID) ((char *) Process->TebBlock + RegionSize);
}
TebBase = (PVOID) ((char *) Process->TebLastAllocated - PAGE_SIZE);
Status = ZwAllocateVirtualMemory(ProcessHandle,
&TebBase,
0,
&TebSize,
MEM_COMMIT,
PAGE_READWRITE);
if (! NT_SUCCESS(Status))
{
DPRINT1("Failed to commit virtual memory for TEB\n");
return Status;
}
Process->TebLastAllocated = TebBase;
PsUnlockProcess(Process);
}
DPRINT ("TebBase %p TebSize %lu\n", TebBase, TebSize);
ASSERT(NULL != TebBase && PAGE_SIZE <= TebSize);
RtlZeroMemory(&Teb, sizeof(TEB));
/* set all pointers to and from the TEB */
Teb.Tib.Self = TebBase;
if (Thread->ThreadsProcess)
{
Teb.Peb = Thread->ThreadsProcess->Peb; /* No PEB yet!! */
}
DPRINT("Teb.Peb %x\n", Teb.Peb);
/* store stack information from InitialTeb */
if(InitialTeb != NULL)
{
/* fixed-size stack */
if(InitialTeb->StackBase && InitialTeb->StackLimit)
{
Teb.Tib.StackBase = InitialTeb->StackBase;
Teb.Tib.StackLimit = InitialTeb->StackLimit;
Teb.DeallocationStack = InitialTeb->StackLimit;
}
/* expandable stack */
else
{
Teb.Tib.StackBase = InitialTeb->StackCommit;
Teb.Tib.StackLimit = InitialTeb->StackCommitMax;
Teb.DeallocationStack = InitialTeb->StackReserved;
}
}
/* more initialization */
Teb.Cid.UniqueThread = Thread->Cid.UniqueThread;
Teb.Cid.UniqueProcess = Thread->Cid.UniqueProcess;
Teb.CurrentLocale = PsDefaultThreadLocaleId;
/* Terminate the exception handler list */
Teb.Tib.ExceptionList = (PVOID)-1;
DPRINT("sizeof(TEB) %x\n", sizeof(TEB));
/* write TEB data into teb page */
Status = NtWriteVirtualMemory(ProcessHandle,
TebBase,
&Teb,
sizeof(TEB),
&ByteCount);
if (!NT_SUCCESS(Status))
{
/* free TEB */
DPRINT1 ("Writing TEB failed!\n");
RegionSize = 0;
NtFreeVirtualMemory(ProcessHandle,
TebBase,
&RegionSize,
MEM_RELEASE);
return Status;
}
if (TebPtr != NULL)
{
*TebPtr = (PTEB)TebBase;
}
DPRINT("TEB allocated at %p\n", TebBase);
return Status;
}
VOID STDCALL
LdrInitApcRundownRoutine ( PKAPC Apc )
{
ExFreePool(Apc);
}
VOID STDCALL
LdrInitApcKernelRoutine (
PKAPC Apc,
PKNORMAL_ROUTINE* NormalRoutine,
PVOID* NormalContext,
PVOID* SystemArgument1,
PVOID* SystemArgument2)
{
ExFreePool(Apc);
}
NTSTATUS STDCALL
NtCreateThread (
OUT PHANDLE ThreadHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
IN HANDLE ProcessHandle,
OUT PCLIENT_ID ClientId,
IN PCONTEXT ThreadContext,
IN PINITIAL_TEB InitialTeb,
IN BOOLEAN CreateSuspended )
{
HANDLE hThread;
CONTEXT SafeContext;
INITIAL_TEB SafeInitialTeb;
PEPROCESS Process;
PETHREAD Thread;
PTEB TebBase;
PKAPC LdrInitApc;
KIRQL oldIrql;
KPROCESSOR_MODE PreviousMode;
NTSTATUS Status = STATUS_SUCCESS;
PAGED_CODE();
if(ThreadContext == NULL)
{
return STATUS_INVALID_PARAMETER;
}
PreviousMode = ExGetPreviousMode();
if(PreviousMode != KernelMode)
{
_SEH_TRY
{
ProbeForWrite(ThreadHandle,
sizeof(HANDLE),
sizeof(ULONG));
if(ClientId != NULL)
{
ProbeForWrite(ClientId,
sizeof(CLIENT_ID),
sizeof(ULONG));
}
ProbeForRead(ThreadContext,
sizeof(CONTEXT),
sizeof(ULONG));
SafeContext = *ThreadContext;
ThreadContext = &SafeContext;
ProbeForRead(InitialTeb,
sizeof(INITIAL_TEB),
sizeof(ULONG));
SafeInitialTeb = *InitialTeb;
InitialTeb = &SafeInitialTeb;
}
_SEH_HANDLE
{
Status = _SEH_GetExceptionCode();
}
_SEH_END;
if(!NT_SUCCESS(Status))
{
return Status;
}
}
DPRINT("NtCreateThread(ThreadHandle %x, PCONTEXT %x)\n",
ThreadHandle,ThreadContext);
Status = ObReferenceObjectByHandle(
ProcessHandle,
PROCESS_CREATE_THREAD,
PsProcessType,
PreviousMode,
(PVOID*)&Process,
NULL);
if(!NT_SUCCESS(Status))
{
return(Status);
}
Status = PsLockProcess(Process, FALSE);
if (!NT_SUCCESS(Status))
{
ObDereferenceObject(Process);
return(Status);
}
if(Process->ExitTime.QuadPart != 0)
{
PsUnlockProcess(Process);
return STATUS_PROCESS_IS_TERMINATING;
}
PsUnlockProcess(Process);
Status = PsInitializeThread(Process,
&Thread,
ObjectAttributes,
PreviousMode,
FALSE);
ObDereferenceObject(Process);
if (!NT_SUCCESS(Status))
{
return(Status);
}
/* create a client id handle */
Status = PsCreateCidHandle (
Thread, PsThreadType, &Thread->Cid.UniqueThread);
if (!NT_SUCCESS(Status))
{
ObDereferenceObject(Thread);
return Status;
}
Status = KiArchInitThreadWithContext(&Thread->Tcb, ThreadContext);
if (!NT_SUCCESS(Status))
{
PsDeleteCidHandle(Thread->Cid.UniqueThread, PsThreadType);
ObDereferenceObject(Thread);
return(Status);
}
Status = PsCreateTeb(ProcessHandle,
&TebBase,
Thread,
InitialTeb);
if (!NT_SUCCESS(Status))
{
PsDeleteCidHandle(Thread->Cid.UniqueThread, PsThreadType);
ObDereferenceObject(Thread);
return(Status);
}
Thread->Tcb.Teb = TebBase;
Thread->StartAddress = NULL;
/*
* Maybe send a message to the process's debugger
*/
DbgkCreateThread((PVOID)ThreadContext->Eip);
/*
* First, force the thread to be non-alertable for user-mode alerts.
*/
Thread->Tcb.Alertable = FALSE;
/*
* If the thread is to be created suspended then queue an APC to
* do the suspend before we run any userspace code.
*/
if (CreateSuspended)
{
KeSuspendThread(&Thread->Tcb);
}
/*
* Queue an APC to the thread that will execute the ntdll startup
* routine.
*/
LdrInitApc = ExAllocatePoolWithTag (
NonPagedPool, sizeof(KAPC), TAG_KAPC );
KeInitializeApc (
LdrInitApc,
&Thread->Tcb,
OriginalApcEnvironment,
LdrInitApcKernelRoutine,
LdrInitApcRundownRoutine,
LdrpGetSystemDllEntryPoint(),
UserMode,
NULL );
KeInsertQueueApc(LdrInitApc, NULL, NULL, IO_NO_INCREMENT);
/*
* The thread is non-alertable, so the APC we added did not set UserApcPending to TRUE.
* We must do this manually. Do NOT attempt to set the Thread to Alertable before the call,
* doing so is a blatant and erronous hack.
*/
Thread->Tcb.ApcState.UserApcPending = TRUE;
Thread->Tcb.Alerted[KernelMode] = TRUE;
oldIrql = KeAcquireDispatcherDatabaseLock ();
KiUnblockThread(&Thread->Tcb, NULL, 0);
KeReleaseDispatcherDatabaseLock(oldIrql);
Status = ObInsertObject((PVOID)Thread,
NULL,
DesiredAccess,
0,
NULL,
&hThread);
if(NT_SUCCESS(Status))
{
_SEH_TRY
{
if(ClientId != NULL)
{
*ClientId = Thread->Cid;
}
*ThreadHandle = hThread;
}
_SEH_HANDLE
{
Status = _SEH_GetExceptionCode();
}
_SEH_END;
}
return Status;
}
/*
* @implemented
*/
NTSTATUS STDCALL
PsCreateSystemThread (
PHANDLE ThreadHandle,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes,
HANDLE ProcessHandle,
PCLIENT_ID ClientId,
PKSTART_ROUTINE StartRoutine,
PVOID StartContext )
/*
* FUNCTION: Creates a thread which executes in kernel mode
* ARGUMENTS:
* ThreadHandle (OUT) = Caller supplied storage for the returned thread
* handle
* DesiredAccess = Requested access to the thread
* ObjectAttributes = Object attributes (optional)
* ProcessHandle = Handle of process thread will run in
* NULL to use system process
* ClientId (OUT) = Caller supplied storage for the returned client id
* of the thread (optional)
* StartRoutine = Entry point for the thread
* StartContext = Argument supplied to the thread when it begins
* execution
* RETURNS: Success or failure status
*/
{
PETHREAD Thread;
NTSTATUS Status;
KIRQL oldIrql;
PAGED_CODE();
DPRINT("PsCreateSystemThread(ThreadHandle %x, ProcessHandle %x)\n",
ThreadHandle,ProcessHandle);
Status = PsInitializeThread(
NULL,
&Thread,
ObjectAttributes,
KernelMode,
FALSE);
if (!NT_SUCCESS(Status))
{
return(Status);
}
/* Set the thread as a system thread */
Thread->SystemThread = TRUE;
Status = PsCreateCidHandle(Thread,
PsThreadType,
&Thread->Cid.UniqueThread);
if(!NT_SUCCESS(Status))
{
ObDereferenceObject(Thread);
return Status;
}
Thread->StartAddress = StartRoutine;
Status = KiArchInitThread (
&Thread->Tcb, StartRoutine, StartContext);
if (!NT_SUCCESS(Status))
{
ObDereferenceObject(Thread);
return(Status);
}
if (ClientId != NULL)
{
*ClientId=Thread->Cid;
}
oldIrql = KeAcquireDispatcherDatabaseLock ();
KiUnblockThread(&Thread->Tcb, NULL, 0);
KeReleaseDispatcherDatabaseLock(oldIrql);
Status = ObInsertObject(
(PVOID)Thread,
NULL,
DesiredAccess,
0,
NULL,
ThreadHandle);
/* don't dereference the thread, the initial reference serves as the keep-alive
reference which will be removed by the thread reaper */
return Status;
}
VOID STDCALL
PspRunCreateThreadNotifyRoutines (
PETHREAD CurrentThread,
BOOLEAN Create )
{
ULONG i;
CLIENT_ID Cid = CurrentThread->Cid;
for (i = 0; i < PiThreadNotifyRoutineCount; i++)
{
PiThreadNotifyRoutine[i](Cid.UniqueProcess, Cid.UniqueThread, Create);
}
}
/*
* @implemented
*/
NTSTATUS STDCALL
PsSetCreateThreadNotifyRoutine (
IN PCREATE_THREAD_NOTIFY_ROUTINE NotifyRoutine )
{
if (PiThreadNotifyRoutineCount >= MAX_THREAD_NOTIFY_ROUTINE_COUNT)
{
return(STATUS_INSUFFICIENT_RESOURCES);
}
PiThreadNotifyRoutine[PiThreadNotifyRoutineCount] = NotifyRoutine;
PiThreadNotifyRoutineCount++;
return(STATUS_SUCCESS);
}
/* EOF */

View file

@ -79,6 +79,35 @@ PspReapRoutine(PVOID Context)
KeReleaseDispatcherDatabaseLock(OldIrql);
}
VOID
STDCALL
PspKillMostProcesses(VOID)
{
PLIST_ENTRY current_entry;
PEPROCESS current;
/* Acquire the Active Process Lock */
ExAcquireFastMutex(&PspActiveProcessMutex);
/* Loop all processes on the list */
current_entry = PsActiveProcessHead.Flink;
while (current_entry != &PsActiveProcessHead)
{
current = CONTAINING_RECORD(current_entry, EPROCESS, ProcessListEntry);
current_entry = current_entry->Flink;
if (current->UniqueProcessId != PsInitialSystemProcess->UniqueProcessId &&
current->UniqueProcessId != PsGetCurrentProcessId())
{
/* Terminate all the Threads in this Process */
PspTerminateProcessThreads(current, STATUS_SUCCESS);
}
}
/* Release the lock */
ExReleaseFastMutex(&PspActiveProcessMutex);
}
VOID
STDCALL
PspTerminateProcessThreads(PEPROCESS Process,

View file

@ -0,0 +1,194 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/ps/notify.c
* PURPOSE: Notifications
*
* PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
*/
/* INCLUDES ****************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <internal/debug.h>
/* GLOBAL *******************************************************************/
#define MAX_THREAD_NOTIFY_ROUTINE_COUNT 8
#define TAG_KAPC TAG('k','p','a','p') /* kpap - kernel ps apc */
static ULONG PiThreadNotifyRoutineCount = 0;
static PCREATE_THREAD_NOTIFY_ROUTINE
PiThreadNotifyRoutine[MAX_THREAD_NOTIFY_ROUTINE_COUNT];
static PCREATE_PROCESS_NOTIFY_ROUTINE
PspProcessNotifyRoutine[MAX_PROCESS_NOTIFY_ROUTINE_COUNT];
static PLOAD_IMAGE_NOTIFY_ROUTINE
PspLoadImageNotifyRoutine[MAX_LOAD_IMAGE_NOTIFY_ROUTINE_COUNT];
/* FUNCTIONS ***************************************************************/
/*
* @implemented
*/
NTSTATUS
STDCALL
PsSetCreateProcessNotifyRoutine(IN PCREATE_PROCESS_NOTIFY_ROUTINE NotifyRoutine,
IN BOOLEAN Remove)
{
ULONG i;
/* Check if it's a removal or addition */
if (Remove)
{
/* Loop the routines */
for(i=0;i<MAX_PROCESS_NOTIFY_ROUTINE_COUNT;i++)
{
/* Check for a match */
if ((PVOID)PspProcessNotifyRoutine[i] == (PVOID)NotifyRoutine)
{
/* Remove and return */
PspProcessNotifyRoutine[i] = NULL;
return(STATUS_SUCCESS);
}
}
}
else
{
/* Loop the routines */
for(i=0;i<MAX_PROCESS_NOTIFY_ROUTINE_COUNT;i++)
{
/* Find an empty one */
if (PspProcessNotifyRoutine[i] == NULL)
{
/* Add it */
PspProcessNotifyRoutine[i] = NotifyRoutine;
return STATUS_SUCCESS;
}
}
}
/* Nothing found */
return STATUS_INVALID_PARAMETER;
}
/*
* @implemented
*/
NTSTATUS
STDCALL
PsRemoveLoadImageNotifyRoutine(IN PLOAD_IMAGE_NOTIFY_ROUTINE NotifyRoutine)
{
ULONG i;
/* Loop the routines */
for(i=0;i<MAX_LOAD_IMAGE_NOTIFY_ROUTINE_COUNT;i++)
{
/* Check for a match */
if ((PVOID)PspLoadImageNotifyRoutine[i] == (PVOID)NotifyRoutine)
{
/* Remove and return */
PspLoadImageNotifyRoutine[i] = NULL;
return(STATUS_SUCCESS);
}
}
/* Nothing found */
return STATUS_INVALID_PARAMETER;
}
/*
* @implemented
*/
NTSTATUS
STDCALL
PsSetLoadImageNotifyRoutine(IN PLOAD_IMAGE_NOTIFY_ROUTINE NotifyRoutine)
{
ULONG i;
/* Loop the routines */
for (i = 0; i < MAX_LOAD_IMAGE_NOTIFY_ROUTINE_COUNT; i++)
{
/* Find an empty one */
if (PspLoadImageNotifyRoutine[i] == NULL)
{
/* Add it */
PspLoadImageNotifyRoutine[i] = NotifyRoutine;
return STATUS_SUCCESS;
}
}
/* Nothing found */
return STATUS_INVALID_PARAMETER;
}
VOID STDCALL
PspRunCreateThreadNotifyRoutines (
PETHREAD CurrentThread,
BOOLEAN Create )
{
ULONG i;
CLIENT_ID Cid = CurrentThread->Cid;
for (i = 0; i < PiThreadNotifyRoutineCount; i++)
{
PiThreadNotifyRoutine[i](Cid.UniqueProcess, Cid.UniqueThread, Create);
}
}
VOID
STDCALL
PspRunCreateProcessNotifyRoutines(PEPROCESS CurrentProcess,
BOOLEAN Create)
{
ULONG i;
HANDLE ProcessId = (HANDLE)CurrentProcess->UniqueProcessId;
HANDLE ParentId = CurrentProcess->InheritedFromUniqueProcessId;
for(i = 0; i < MAX_PROCESS_NOTIFY_ROUTINE_COUNT; ++i)
{
if(PspProcessNotifyRoutine[i])
{
PspProcessNotifyRoutine[i](ParentId, ProcessId, Create);
}
}
}
VOID
STDCALL
PspRunLoadImageNotifyRoutines(PUNICODE_STRING FullImageName,
HANDLE ProcessId,
PIMAGE_INFO ImageInfo)
{
ULONG i;
for (i = 0; i < MAX_PROCESS_NOTIFY_ROUTINE_COUNT; ++ i)
{
if (PspLoadImageNotifyRoutine[i])
{
PspLoadImageNotifyRoutine[i](FullImageName, ProcessId, ImageInfo);
}
}
}
/*
* @implemented
*/
NTSTATUS STDCALL
PsSetCreateThreadNotifyRoutine (
IN PCREATE_THREAD_NOTIFY_ROUTINE NotifyRoutine )
{
if (PiThreadNotifyRoutineCount >= MAX_THREAD_NOTIFY_ROUTINE_COUNT)
{
return(STATUS_INSUFFICIENT_RESOURCES);
}
PiThreadNotifyRoutine[PiThreadNotifyRoutineCount] = NotifyRoutine;
PiThreadNotifyRoutineCount++;
return(STATUS_SUCCESS);
}
/* EOF */

File diff suppressed because it is too large Load diff

View file

@ -14,13 +14,28 @@
#define NDEBUG
#include <internal/debug.h>
extern LARGE_INTEGER ShortPsLockDelay, PsLockTimeout;
static GENERIC_MAPPING PiProcessMapping = {
STANDARD_RIGHTS_READ | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
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};
VOID
INIT_FUNCTION
PsInitClientIDManagment(VOID);
VOID STDCALL PspKillMostProcesses();
/* FUNCTIONS ***************************************************************/
VOID PiShutdownProcessManager(VOID)
{
DPRINT("PiShutdownProcessManager()\n");
PiKillMostProcesses();
PspKillMostProcesses();
}
VOID INIT_FUNCTION
@ -33,7 +48,177 @@ PiInitProcessManager(VOID)
PsInitialiseW32Call();
}
VOID
INIT_FUNCTION
PsInitProcessManagment(VOID)
{
PKPROCESS KProcess;
NTSTATUS Status;
ShortPsLockDelay.QuadPart = -100LL;
PsLockTimeout.QuadPart = -10000000LL; /* one second */
/*
* Register the process object type
*/
PsProcessType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE));
PsProcessType->Tag = TAG('P', 'R', 'O', 'C');
PsProcessType->TotalObjects = 0;
PsProcessType->TotalHandles = 0;
PsProcessType->PeakObjects = 0;
PsProcessType->PeakHandles = 0;
PsProcessType->PagedPoolCharge = 0;
PsProcessType->NonpagedPoolCharge = sizeof(EPROCESS);
PsProcessType->Mapping = &PiProcessMapping;
PsProcessType->Dump = NULL;
PsProcessType->Open = NULL;
PsProcessType->Close = NULL;
PsProcessType->Delete = PspDeleteProcess;
PsProcessType->Parse = NULL;
PsProcessType->Security = NULL;
PsProcessType->QueryName = NULL;
PsProcessType->OkayToClose = NULL;
PsProcessType->Create = NULL;
PsProcessType->DuplicationNotify = NULL;
RtlInitUnicodeString(&PsProcessType->TypeName, L"Process");
ObpCreateTypeObject(PsProcessType);
InitializeListHead(&PsActiveProcessHead);
ExInitializeFastMutex(&PspActiveProcessMutex);
/*
* Initialize the idle process
*/
Status = ObCreateObject(KernelMode,
PsProcessType,
NULL,
KernelMode,
NULL,
sizeof(EPROCESS),
0,
0,
(PVOID*)&PsIdleProcess);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to create the idle process object, Status: 0x%x\n", Status);
KEBUGCHECK(0);
return;
}
RtlZeroMemory(PsIdleProcess, sizeof(EPROCESS));
PsIdleProcess->Pcb.Affinity = 0xFFFFFFFF;
PsIdleProcess->Pcb.IopmOffset = 0xffff;
PsIdleProcess->Pcb.LdtDescriptor[0] = 0;
PsIdleProcess->Pcb.LdtDescriptor[1] = 0;
PsIdleProcess->Pcb.BasePriority = PROCESS_PRIO_IDLE;
PsIdleProcess->Pcb.ThreadQuantum = 6;
InitializeListHead(&PsIdleProcess->Pcb.ThreadListHead);
InitializeListHead(&PsIdleProcess->ThreadListHead);
InitializeListHead(&PsIdleProcess->ProcessListEntry);
KeInitializeDispatcherHeader(&PsIdleProcess->Pcb.DispatcherHeader,
ProcessObject,
sizeof(EPROCESS),
FALSE);
PsIdleProcess->Pcb.DirectoryTableBase =
(LARGE_INTEGER)(LONGLONG)(ULONG)MmGetPageDirectory();
strcpy(PsIdleProcess->ImageFileName, "Idle");
/*
* Initialize the system process
*/
Status = ObCreateObject(KernelMode,
PsProcessType,
NULL,
KernelMode,
NULL,
sizeof(EPROCESS),
0,
0,
(PVOID*)&PsInitialSystemProcess);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to create the system process object, Status: 0x%x\n", Status);
KEBUGCHECK(0);
return;
}
/* System threads may run on any processor. */
PsInitialSystemProcess->Pcb.Affinity = 0xFFFFFFFF;
PsInitialSystemProcess->Pcb.IopmOffset = 0xffff;
PsInitialSystemProcess->Pcb.LdtDescriptor[0] = 0;
PsInitialSystemProcess->Pcb.LdtDescriptor[1] = 0;
PsInitialSystemProcess->Pcb.BasePriority = PROCESS_PRIO_NORMAL;
PsInitialSystemProcess->Pcb.ThreadQuantum = 6;
InitializeListHead(&PsInitialSystemProcess->Pcb.ThreadListHead);
KeInitializeDispatcherHeader(&PsInitialSystemProcess->Pcb.DispatcherHeader,
ProcessObject,
sizeof(EPROCESS),
FALSE);
KProcess = &PsInitialSystemProcess->Pcb;
MmInitializeAddressSpace(PsInitialSystemProcess,
&PsInitialSystemProcess->AddressSpace);
KeInitializeEvent(&PsInitialSystemProcess->LockEvent, SynchronizationEvent, FALSE);
PsInitialSystemProcess->LockCount = 0;
PsInitialSystemProcess->LockOwner = NULL;
#if defined(__GNUC__)
KProcess->DirectoryTableBase =
(LARGE_INTEGER)(LONGLONG)(ULONG)MmGetPageDirectory();
#else
{
LARGE_INTEGER dummy;
dummy.QuadPart = (LONGLONG)(ULONG)MmGetPageDirectory();
KProcess->DirectoryTableBase = dummy;
}
#endif
strcpy(PsInitialSystemProcess->ImageFileName, "System");
PsInitialSystemProcess->Win32WindowStation = (HANDLE)0;
InsertHeadList(&PsActiveProcessHead,
&PsInitialSystemProcess->ProcessListEntry);
InitializeListHead(&PsInitialSystemProcess->ThreadListHead);
#ifndef SCHED_REWRITE
PTOKEN BootToken;
/* No parent, this is the Initial System Process. Assign Boot Token */
BootToken = SepCreateSystemProcessToken();
BootToken->TokenInUse = TRUE;
PsInitialSystemProcess->Token = BootToken;
ObReferenceObject(BootToken);
#endif
}
VOID
PspPostInitSystemProcess(VOID)
{
NTSTATUS Status;
/* this routine is called directly after the exectuive handle tables were
initialized. We'll set up the Client ID handle table and assign the system
process a PID */
PsInitClientIDManagment();
ObCreateHandleTable(NULL, FALSE, PsInitialSystemProcess);
ObpKernelHandleTable = PsInitialSystemProcess->ObjectTable;
Status = PsCreateCidHandle(PsInitialSystemProcess,
PsProcessType,
&PsInitialSystemProcess->UniqueProcessId);
if(!NT_SUCCESS(Status))
{
DPRINT1("Failed to create CID handle (unique process id) for the system process!\n");
KEBUGCHECK(0);
}
}
/**********************************************************************
* NAME EXPORTED
* PsGetVersion

151
reactos/ntoskrnl/ps/quota.c Normal file
View file

@ -0,0 +1,151 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/ps/quota.c
* PURPOSE: Process Pool Quotas
*
* PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
*/
/* INCLUDES **************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <internal/debug.h>
/* FUNCTIONS ***************************************************************/
/*
* @implemented
*/
VOID
STDCALL
PsChargePoolQuota(IN PEPROCESS Process,
IN POOL_TYPE PoolType,
IN ULONG_PTR Amount)
{
NTSTATUS Status;
/* Charge the usage */
Status = PsChargeProcessPoolQuota(Process, PoolType, Amount);
/* Raise Exception */
if (!NT_SUCCESS(Status))
{
ExRaiseStatus(Status);
}
}
/*
* @implemented
*/
NTSTATUS
STDCALL
PsChargeProcessNonPagedPoolQuota(IN PEPROCESS Process,
IN ULONG_PTR Amount)
{
/* Call the general function */
return PsChargeProcessPoolQuota(Process, NonPagedPool, Amount);
}
/*
* @implemented
*/
NTSTATUS
STDCALL
PsChargeProcessPagedPoolQuota(IN PEPROCESS Process,
IN ULONG_PTR Amount)
{
/* Call the general function */
return PsChargeProcessPoolQuota(Process, PagedPool, Amount);
}
/*
* @implemented
*/
NTSTATUS
STDCALL
PsChargeProcessPoolQuota(IN PEPROCESS Process,
IN POOL_TYPE PoolType,
IN ULONG_PTR Amount)
{
PEPROCESS_QUOTA_BLOCK QuotaBlock;
ULONG NewUsageSize;
ULONG NewMaxQuota;
/* Get current Quota Block */
QuotaBlock = Process->QuotaBlock;
/* Quota Operations are not to be done on the SYSTEM Process */
if (Process == PsInitialSystemProcess) return STATUS_SUCCESS;
/* New Size in use */
NewUsageSize = QuotaBlock->QuotaEntry[PoolType].Usage + Amount;
/* Does this size respect the quota? */
if (NewUsageSize > QuotaBlock->QuotaEntry[PoolType].Limit)
{
/* It doesn't, so keep raising the Quota */
while (MiRaisePoolQuota(PoolType,
QuotaBlock->QuotaEntry[PoolType].Limit,
&NewMaxQuota))
{
/* Save new Maximum Quota */
QuotaBlock->QuotaEntry[PoolType].Limit = NewMaxQuota;
/* See if the new Maximum Quota fulfills our need */
if (NewUsageSize <= NewMaxQuota) goto QuotaChanged;
}
return STATUS_QUOTA_EXCEEDED;
}
QuotaChanged:
/* Save new Usage */
QuotaBlock->QuotaEntry[PoolType].Usage = NewUsageSize;
/* Is this a new peak? */
if (NewUsageSize > QuotaBlock->QuotaEntry[PoolType].Peak)
{
QuotaBlock->QuotaEntry[PoolType].Peak = NewUsageSize;
}
/* All went well */
return STATUS_SUCCESS;
}
/*
* @unimplemented
*/
VOID
STDCALL
PsReturnPoolQuota(IN PEPROCESS Process,
IN POOL_TYPE PoolType,
IN ULONG_PTR Amount)
{
UNIMPLEMENTED;
}
/*
* @unimplemented
*/
VOID
STDCALL
PsReturnProcessNonPagedPoolQuota(IN PEPROCESS Process,
IN ULONG_PTR Amount)
{
UNIMPLEMENTED;
}
/*
* @unimplemented
*/
VOID
STDCALL
PsReturnProcessPagedPoolQuota(IN PEPROCESS Process,
IN ULONG_PTR Amount)
{
UNIMPLEMENTED;
}
/* EOF */

View file

@ -18,9 +18,6 @@ ULONG
STDCALL
KeResumeThread(PKTHREAD Thread);
ULONG
STDCALL
KeSuspendThread(PKTHREAD Thread);
/* FUNCTIONS *****************************************************************/
/*

View file

@ -428,6 +428,573 @@ PsPrepareForApplicationProcessorInit(ULONG Id)
Id, IdleThread->Cid.UniqueThread);
}
VOID
PiBeforeBeginThread(CONTEXT c)
{
KeLowerIrql(PASSIVE_LEVEL);
}
NTSTATUS
PsInitializeThread (
PEPROCESS Process,
PETHREAD* ThreadPtr,
POBJECT_ATTRIBUTES ObjectAttributes,
KPROCESSOR_MODE AccessMode,
BOOLEAN First )
{
PETHREAD Thread;
NTSTATUS Status;
KIRQL oldIrql;
PAGED_CODE();
if (Process == NULL)
{
Process = PsInitialSystemProcess;
}
/*
* Create and initialize thread
*/
Status = ObCreateObject(AccessMode,
PsThreadType,
ObjectAttributes,
KernelMode,
NULL,
sizeof(ETHREAD),
0,
0,
(PVOID*)&Thread);
if (!NT_SUCCESS(Status))
{
return(Status);
}
/*
* Reference process
*/
ObReferenceObjectByPointer(Process,
PROCESS_CREATE_THREAD,
PsProcessType,
KernelMode);
Thread->ThreadsProcess = Process;
Thread->Cid.UniqueThread = NULL;
Thread->Cid.UniqueProcess = (HANDLE)Thread->ThreadsProcess->UniqueProcessId;
DPRINT("Thread = %x\n",Thread);
KeInitializeThread(&Process->Pcb, &Thread->Tcb, First);
InitializeListHead(&Thread->ActiveTimerListHead);
KeInitializeSpinLock(&Thread->ActiveTimerListLock);
InitializeListHead(&Thread->IrpList);
Thread->DeadThread = FALSE;
Thread->HasTerminated = FALSE;
Thread->Tcb.Win32Thread = NULL;
DPRINT("Thread->Cid.UniqueThread %d\n",Thread->Cid.UniqueThread);
Thread->Tcb.BasePriority = (CHAR)Process->Pcb.BasePriority;
Thread->Tcb.Priority = Thread->Tcb.BasePriority;
/*
* Local Procedure Call facility (LPC)
*/
KeInitializeSemaphore (& Thread->LpcReplySemaphore, 0, LONG_MAX);
Thread->LpcReplyMessage = NULL;
Thread->LpcReplyMessageId = 0; /* not valid */
/* Thread->LpcReceiveMessageId = 0; */
Thread->LpcExitThreadCalled = FALSE;
Thread->LpcReceivedMsgIdValid = FALSE;
oldIrql = KeAcquireDispatcherDatabaseLock();
InsertTailList(&Process->ThreadListHead,
&Thread->ThreadListEntry);
KeReleaseDispatcherDatabaseLock(oldIrql);
*ThreadPtr = Thread;
return STATUS_SUCCESS;
}
static NTSTATUS
PsCreateTeb (
HANDLE ProcessHandle,
PTEB *TebPtr,
PETHREAD Thread,
PINITIAL_TEB InitialTeb )
{
PEPROCESS Process;
NTSTATUS Status;
ULONG ByteCount;
ULONG RegionSize;
ULONG TebSize;
PVOID TebBase;
TEB Teb;
PAGED_CODE();
TebSize = PAGE_SIZE;
if (NULL == Thread->ThreadsProcess)
{
/* We'll be allocating a 64k block here and only use 4k of it, but this
path should almost never be taken. Actually, I never saw it was taken,
so maybe we should just ASSERT(NULL != Thread->ThreadsProcess) and
move on */
TebBase = NULL;
Status = ZwAllocateVirtualMemory(ProcessHandle,
&TebBase,
0,
&TebSize,
MEM_RESERVE | MEM_COMMIT | MEM_TOP_DOWN,
PAGE_READWRITE);
if (! NT_SUCCESS(Status))
{
DPRINT1("Failed to allocate virtual memory for TEB\n");
return Status;
}
}
else
{
Process = Thread->ThreadsProcess;
PsLockProcess(Process, FALSE);
if (NULL == Process->TebBlock ||
Process->TebBlock == Process->TebLastAllocated)
{
Process->TebBlock = NULL;
RegionSize = MM_VIRTMEM_GRANULARITY;
Status = ZwAllocateVirtualMemory(ProcessHandle,
&Process->TebBlock,
0,
&RegionSize,
MEM_RESERVE | MEM_TOP_DOWN,
PAGE_READWRITE);
if (! NT_SUCCESS(Status))
{
PsUnlockProcess(Process);
DPRINT1("Failed to reserve virtual memory for TEB\n");
return Status;
}
Process->TebLastAllocated = (PVOID) ((char *) Process->TebBlock + RegionSize);
}
TebBase = (PVOID) ((char *) Process->TebLastAllocated - PAGE_SIZE);
Status = ZwAllocateVirtualMemory(ProcessHandle,
&TebBase,
0,
&TebSize,
MEM_COMMIT,
PAGE_READWRITE);
if (! NT_SUCCESS(Status))
{
DPRINT1("Failed to commit virtual memory for TEB\n");
return Status;
}
Process->TebLastAllocated = TebBase;
PsUnlockProcess(Process);
}
DPRINT ("TebBase %p TebSize %lu\n", TebBase, TebSize);
ASSERT(NULL != TebBase && PAGE_SIZE <= TebSize);
RtlZeroMemory(&Teb, sizeof(TEB));
/* set all pointers to and from the TEB */
Teb.Tib.Self = TebBase;
if (Thread->ThreadsProcess)
{
Teb.Peb = Thread->ThreadsProcess->Peb; /* No PEB yet!! */
}
DPRINT("Teb.Peb %x\n", Teb.Peb);
/* store stack information from InitialTeb */
if(InitialTeb != NULL)
{
/* fixed-size stack */
if(InitialTeb->StackBase && InitialTeb->StackLimit)
{
Teb.Tib.StackBase = InitialTeb->StackBase;
Teb.Tib.StackLimit = InitialTeb->StackLimit;
Teb.DeallocationStack = InitialTeb->StackLimit;
}
/* expandable stack */
else
{
Teb.Tib.StackBase = InitialTeb->StackCommit;
Teb.Tib.StackLimit = InitialTeb->StackCommitMax;
Teb.DeallocationStack = InitialTeb->StackReserved;
}
}
/* more initialization */
Teb.Cid.UniqueThread = Thread->Cid.UniqueThread;
Teb.Cid.UniqueProcess = Thread->Cid.UniqueProcess;
Teb.CurrentLocale = PsDefaultThreadLocaleId;
/* Terminate the exception handler list */
Teb.Tib.ExceptionList = (PVOID)-1;
DPRINT("sizeof(TEB) %x\n", sizeof(TEB));
/* write TEB data into teb page */
Status = NtWriteVirtualMemory(ProcessHandle,
TebBase,
&Teb,
sizeof(TEB),
&ByteCount);
if (!NT_SUCCESS(Status))
{
/* free TEB */
DPRINT1 ("Writing TEB failed!\n");
RegionSize = 0;
NtFreeVirtualMemory(ProcessHandle,
TebBase,
&RegionSize,
MEM_RELEASE);
return Status;
}
if (TebPtr != NULL)
{
*TebPtr = (PTEB)TebBase;
}
DPRINT("TEB allocated at %p\n", TebBase);
return Status;
}
VOID STDCALL
LdrInitApcRundownRoutine ( PKAPC Apc )
{
ExFreePool(Apc);
}
VOID STDCALL
LdrInitApcKernelRoutine (
PKAPC Apc,
PKNORMAL_ROUTINE* NormalRoutine,
PVOID* NormalContext,
PVOID* SystemArgument1,
PVOID* SystemArgument2)
{
ExFreePool(Apc);
}
NTSTATUS STDCALL
NtCreateThread (
OUT PHANDLE ThreadHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
IN HANDLE ProcessHandle,
OUT PCLIENT_ID ClientId,
IN PCONTEXT ThreadContext,
IN PINITIAL_TEB InitialTeb,
IN BOOLEAN CreateSuspended )
{
HANDLE hThread;
CONTEXT SafeContext;
INITIAL_TEB SafeInitialTeb;
PEPROCESS Process;
PETHREAD Thread;
PTEB TebBase;
PKAPC LdrInitApc;
KIRQL oldIrql;
KPROCESSOR_MODE PreviousMode;
NTSTATUS Status = STATUS_SUCCESS;
PAGED_CODE();
if(ThreadContext == NULL)
{
return STATUS_INVALID_PARAMETER;
}
PreviousMode = ExGetPreviousMode();
if(PreviousMode != KernelMode)
{
_SEH_TRY
{
ProbeForWrite(ThreadHandle,
sizeof(HANDLE),
sizeof(ULONG));
if(ClientId != NULL)
{
ProbeForWrite(ClientId,
sizeof(CLIENT_ID),
sizeof(ULONG));
}
ProbeForRead(ThreadContext,
sizeof(CONTEXT),
sizeof(ULONG));
SafeContext = *ThreadContext;
ThreadContext = &SafeContext;
ProbeForRead(InitialTeb,
sizeof(INITIAL_TEB),
sizeof(ULONG));
SafeInitialTeb = *InitialTeb;
InitialTeb = &SafeInitialTeb;
}
_SEH_HANDLE
{
Status = _SEH_GetExceptionCode();
}
_SEH_END;
if(!NT_SUCCESS(Status))
{
return Status;
}
}
DPRINT("NtCreateThread(ThreadHandle %x, PCONTEXT %x)\n",
ThreadHandle,ThreadContext);
Status = ObReferenceObjectByHandle(
ProcessHandle,
PROCESS_CREATE_THREAD,
PsProcessType,
PreviousMode,
(PVOID*)&Process,
NULL);
if(!NT_SUCCESS(Status))
{
return(Status);
}
Status = PsLockProcess(Process, FALSE);
if (!NT_SUCCESS(Status))
{
ObDereferenceObject(Process);
return(Status);
}
if(Process->ExitTime.QuadPart != 0)
{
PsUnlockProcess(Process);
return STATUS_PROCESS_IS_TERMINATING;
}
PsUnlockProcess(Process);
Status = PsInitializeThread(Process,
&Thread,
ObjectAttributes,
PreviousMode,
FALSE);
ObDereferenceObject(Process);
if (!NT_SUCCESS(Status))
{
return(Status);
}
/* create a client id handle */
Status = PsCreateCidHandle (
Thread, PsThreadType, &Thread->Cid.UniqueThread);
if (!NT_SUCCESS(Status))
{
ObDereferenceObject(Thread);
return Status;
}
Status = KiArchInitThreadWithContext(&Thread->Tcb, ThreadContext);
if (!NT_SUCCESS(Status))
{
PsDeleteCidHandle(Thread->Cid.UniqueThread, PsThreadType);
ObDereferenceObject(Thread);
return(Status);
}
Status = PsCreateTeb(ProcessHandle,
&TebBase,
Thread,
InitialTeb);
if (!NT_SUCCESS(Status))
{
PsDeleteCidHandle(Thread->Cid.UniqueThread, PsThreadType);
ObDereferenceObject(Thread);
return(Status);
}
Thread->Tcb.Teb = TebBase;
Thread->StartAddress = NULL;
/*
* Maybe send a message to the process's debugger
*/
DbgkCreateThread((PVOID)ThreadContext->Eip);
/*
* First, force the thread to be non-alertable for user-mode alerts.
*/
Thread->Tcb.Alertable = FALSE;
/*
* If the thread is to be created suspended then queue an APC to
* do the suspend before we run any userspace code.
*/
if (CreateSuspended)
{
KeSuspendThread(&Thread->Tcb);
}
/*
* Queue an APC to the thread that will execute the ntdll startup
* routine.
*/
LdrInitApc = ExAllocatePoolWithTag (
NonPagedPool, sizeof(KAPC), TAG('K', 'a', 'p', 'c'));
KeInitializeApc (
LdrInitApc,
&Thread->Tcb,
OriginalApcEnvironment,
LdrInitApcKernelRoutine,
LdrInitApcRundownRoutine,
LdrpGetSystemDllEntryPoint(),
UserMode,
NULL );
KeInsertQueueApc(LdrInitApc, NULL, NULL, IO_NO_INCREMENT);
/*
* The thread is non-alertable, so the APC we added did not set UserApcPending to TRUE.
* We must do this manually. Do NOT attempt to set the Thread to Alertable before the call,
* doing so is a blatant and erronous hack.
*/
Thread->Tcb.ApcState.UserApcPending = TRUE;
Thread->Tcb.Alerted[KernelMode] = TRUE;
oldIrql = KeAcquireDispatcherDatabaseLock ();
KiUnblockThread(&Thread->Tcb, NULL, 0);
KeReleaseDispatcherDatabaseLock(oldIrql);
Status = ObInsertObject((PVOID)Thread,
NULL,
DesiredAccess,
0,
NULL,
&hThread);
if(NT_SUCCESS(Status))
{
_SEH_TRY
{
if(ClientId != NULL)
{
*ClientId = Thread->Cid;
}
*ThreadHandle = hThread;
}
_SEH_HANDLE
{
Status = _SEH_GetExceptionCode();
}
_SEH_END;
}
return Status;
}
/*
* @implemented
*/
NTSTATUS STDCALL
PsCreateSystemThread (
PHANDLE ThreadHandle,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes,
HANDLE ProcessHandle,
PCLIENT_ID ClientId,
PKSTART_ROUTINE StartRoutine,
PVOID StartContext )
/*
* FUNCTION: Creates a thread which executes in kernel mode
* ARGUMENTS:
* ThreadHandle (OUT) = Caller supplied storage for the returned thread
* handle
* DesiredAccess = Requested access to the thread
* ObjectAttributes = Object attributes (optional)
* ProcessHandle = Handle of process thread will run in
* NULL to use system process
* ClientId (OUT) = Caller supplied storage for the returned client id
* of the thread (optional)
* StartRoutine = Entry point for the thread
* StartContext = Argument supplied to the thread when it begins
* execution
* RETURNS: Success or failure status
*/
{
PETHREAD Thread;
NTSTATUS Status;
KIRQL oldIrql;
PAGED_CODE();
DPRINT("PsCreateSystemThread(ThreadHandle %x, ProcessHandle %x)\n",
ThreadHandle,ProcessHandle);
Status = PsInitializeThread(
NULL,
&Thread,
ObjectAttributes,
KernelMode,
FALSE);
if (!NT_SUCCESS(Status))
{
return(Status);
}
/* Set the thread as a system thread */
Thread->SystemThread = TRUE;
Status = PsCreateCidHandle(Thread,
PsThreadType,
&Thread->Cid.UniqueThread);
if(!NT_SUCCESS(Status))
{
ObDereferenceObject(Thread);
return Status;
}
Thread->StartAddress = StartRoutine;
Status = KiArchInitThread (
&Thread->Tcb, StartRoutine, StartContext);
if (!NT_SUCCESS(Status))
{
ObDereferenceObject(Thread);
return(Status);
}
if (ClientId != NULL)
{
*ClientId=Thread->Cid;
}
oldIrql = KeAcquireDispatcherDatabaseLock ();
KiUnblockThread(&Thread->Tcb, NULL, 0);
KeReleaseDispatcherDatabaseLock(oldIrql);
Status = ObInsertObject(
(PVOID)Thread,
NULL,
DesiredAccess,
0,
NULL,
ThreadHandle);
/* don't dereference the thread, the initial reference serves as the keep-alive
reference which will be removed by the thread reaper */
return Status;
}
VOID INIT_FUNCTION
PsInitThreadManagment(VOID)
/*