mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 01:55:19 +00:00
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:
parent
781c6b374f
commit
f4d2ac0b1e
12 changed files with 1712 additions and 1726 deletions
|
@ -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 \
|
||||
|
|
|
@ -98,6 +98,10 @@ KiUnblockThread(PKTHREAD Thread,
|
|||
PNTSTATUS WaitStatus,
|
||||
KPRIORITY Increment);
|
||||
|
||||
NTSTATUS
|
||||
STDCALL
|
||||
KeSuspendThread(PKTHREAD Thread);
|
||||
|
||||
/* gmutex.c ********************************************************************/
|
||||
|
||||
VOID
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 */
|
|
@ -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,
|
||||
|
|
194
reactos/ntoskrnl/ps/notify.c
Normal file
194
reactos/ntoskrnl/ps/notify.c
Normal 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
|
@ -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
151
reactos/ntoskrnl/ps/quota.c
Normal 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 */
|
|
@ -18,9 +18,6 @@ ULONG
|
|||
STDCALL
|
||||
KeResumeThread(PKTHREAD Thread);
|
||||
|
||||
ULONG
|
||||
STDCALL
|
||||
KeSuspendThread(PKTHREAD Thread);
|
||||
/* FUNCTIONS *****************************************************************/
|
||||
|
||||
/*
|
||||
|
|
|
@ -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)
|
||||
/*
|
||||
|
|
Loading…
Reference in a new issue