-/* $Id: create.c,v 1.36 2001/08/03 17:15:00 ekohl Exp $
+/* $Id$
*
- * COPYRIGHT: See COPYING in the top level directory
- * PROJECT: ReactOS kernel
- * FILE: ntoskrnl/ps/thread.c
- * PURPOSE: Thread managment
- * PROGRAMMER: David Welch (welch@mcmail.com)
- * REVISION HISTORY:
- * 23/06/98: Created
- * 12/10/99: Phillip Susi: Thread priorities, and APC work
+ * 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
*/
/*
/* INCLUDES ****************************************************************/
-#include <ddk/ntddk.h>
-#include <internal/ke.h>
-#include <internal/ob.h>
-#include <internal/ps.h>
-#include <internal/ob.h>
-#include <internal/id.h>
-#include <internal/dbg.h>
-
+#include <ntoskrnl.h>
#define NDEBUG
#include <internal/debug.h>
/* GLOBAL *******************************************************************/
-static ULONG PiNextThreadUniqueId = 0;
+#define MAX_THREAD_NOTIFY_ROUTINE_COUNT 8
-extern KSPIN_LOCK PiThreadListLock;
-extern ULONG PiNrThreads;
-
-extern LIST_ENTRY PiThreadListHead;
+static ULONG PiThreadNotifyRoutineCount = 0;
+static PCREATE_THREAD_NOTIFY_ROUTINE
+PiThreadNotifyRoutine[MAX_THREAD_NOTIFY_ROUTINE_COUNT];
+ULONG
+STDCALL
+KeSuspendThread(PKTHREAD Thread);
/* FUNCTIONS ***************************************************************/
-NTSTATUS STDCALL
-PsAssignImpersonationToken(PETHREAD Thread,
- HANDLE TokenHandle)
-{
- PACCESS_TOKEN Token;
- SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
- NTSTATUS Status;
-
- if (TokenHandle != NULL)
- {
- Status = ObReferenceObjectByHandle(TokenHandle,
- 0,
- SeTokenType,
- UserMode,
- (PVOID*)&Token,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- return(Status);
- }
- ImpersonationLevel = Token->ImpersonationLevel;
- }
- else
- {
- Token = NULL;
- ImpersonationLevel = 0;
- }
-
- PsImpersonateClient(Thread,
- Token,
- 0,
- 0,
- ImpersonationLevel);
- if (Token != NULL)
- {
- ObDereferenceObject(Token);
- }
- return(STATUS_SUCCESS);
-}
-
-VOID STDCALL
-PsRevertToSelf(PETHREAD Thread)
-{
- if (Thread->ActiveImpersonationInfo != 0)
- {
- Thread->ActiveImpersonationInfo = 0;
- ObDereferenceObject(Thread->ImpersonationInfo->Token);
- }
-}
-
-VOID STDCALL
-PsImpersonateClient(PETHREAD Thread,
- PACCESS_TOKEN Token,
- UCHAR b,
- UCHAR c,
- SECURITY_IMPERSONATION_LEVEL Level)
-{
- if (Token == 0)
- {
- if (Thread->ActiveImpersonationInfo != 0)
- {
- Thread->ActiveImpersonationInfo = 0;
- if (Thread->ImpersonationInfo->Token != NULL)
- {
- ObDereferenceObject(Thread->ImpersonationInfo->Token);
- }
- }
- return;
- }
- if (Thread->ActiveImpersonationInfo == 0 ||
- Thread->ImpersonationInfo == NULL)
- {
- Thread->ImpersonationInfo = ExAllocatePool(NonPagedPool,
- sizeof(PS_IMPERSONATION_INFO));
- }
- Thread->ImpersonationInfo->Level = Level;
- Thread->ImpersonationInfo->Unknown2 = c;
- Thread->ImpersonationInfo->Unknown1 = b;
- Thread->ImpersonationInfo->Token = Token;
- ObReferenceObjectByPointer(Token,
- 0,
- SeTokenType,
- KernelMode);
- Thread->ActiveImpersonationInfo = 1;
-}
-
-PACCESS_TOKEN
-PsReferenceEffectiveToken(PETHREAD Thread,
- PTOKEN_TYPE TokenType,
- PUCHAR b,
- PSECURITY_IMPERSONATION_LEVEL Level)
-{
- PEPROCESS Process;
- PACCESS_TOKEN Token;
-
- if (Thread->ActiveImpersonationInfo == 0)
- {
- Process = Thread->ThreadsProcess;
- *TokenType = TokenPrimary;
- *b = 0;
- Token = Process->Token;
- }
- else
- {
- Token = Thread->ImpersonationInfo->Token;
- *TokenType = TokenImpersonation;
- *b = Thread->ImpersonationInfo->Unknown2;
- *Level = Thread->ImpersonationInfo->Level;
- }
- return(Token);
-}
-
-NTSTATUS STDCALL
-NtImpersonateThread (IN HANDLE ThreadHandle,
- IN HANDLE ThreadToImpersonateHandle,
- IN PSECURITY_QUALITY_OF_SERVICE
- SecurityQualityOfService)
-{
- PETHREAD Thread;
- PETHREAD ThreadToImpersonate;
- NTSTATUS Status;
- SE_SOME_STRUCT2 b;
-
- Status = ObReferenceObjectByHandle(ThreadHandle,
- 0,
- PsThreadType,
- UserMode,
- (PVOID*)&Thread,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- return(Status);
- }
-
- Status = ObReferenceObjectByHandle(ThreadToImpersonateHandle,
- 0,
- PsThreadType,
- UserMode,
- (PVOID*)&ThreadToImpersonate,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- ObDereferenceObject(Thread);
- return(Status);
- }
-
- Status = SeCreateClientSecurity(ThreadToImpersonate,
- SecurityQualityOfService,
- 0,
- &b);
- if (!NT_SUCCESS(Status))
- {
- ObDereferenceObject(Thread);
- ObDereferenceObject(ThreadToImpersonate);
- return(Status);
- }
-
- SeImpersonateClient(&b, Thread);
- if (b.Token != NULL)
- {
- ObDereferenceObject(b.Token);
- }
- return(STATUS_SUCCESS);
-}
-
-NTSTATUS STDCALL
-NtOpenThreadToken(IN HANDLE ThreadHandle,
- IN ACCESS_MASK DesiredAccess,
- IN BOOLEAN OpenAsSelf,
- OUT PHANDLE TokenHandle)
-{
-#if 0
- PETHREAD Thread;
- NTSTATUS Status;
- PACCESS_TOKEN Token;
-
- Status = ObReferenceObjectByHandle(ThreadHandle,
- 0,
- PsThreadType,
- UserMode,
- (PVOID*)&Thread,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- return(Status);
- }
-
- Token = PsReferencePrimaryToken(Thread->ThreadsProcess);
- SepCreateImpersonationTokenDacl(Token);
-#endif
- return(STATUS_UNSUCCESSFUL);
-}
-
-PACCESS_TOKEN STDCALL
-PsReferenceImpersonationToken(PETHREAD Thread,
- PULONG Unknown1,
- PULONG Unknown2,
- SECURITY_IMPERSONATION_LEVEL* Level)
-{
- if (Thread->ActiveImpersonationInfo == 0)
- {
- return(NULL);
- }
-
- *Level = Thread->ImpersonationInfo->Level;
- *Unknown1 = Thread->ImpersonationInfo->Unknown1;
- *Unknown2 = Thread->ImpersonationInfo->Unknown2;
- ObReferenceObjectByPointer(Thread->ImpersonationInfo->Token,
- TOKEN_ALL_ACCESS,
- SeTokenType,
- KernelMode);
- return(Thread->ImpersonationInfo->Token);
-}
-
-VOID
-PiTimeoutThread(struct _KDPC *dpc,
- PVOID Context,
- PVOID arg1,
- PVOID arg2)
-{
- // wake up the thread, and tell it it timed out
- NTSTATUS Status = STATUS_TIMEOUT;
-
- DPRINT("PiTimeoutThread()\n");
-
- KeRemoveAllWaitsThread((PETHREAD)Context, Status);
-}
-
-VOID
+VOID
PiBeforeBeginThread(CONTEXT c)
{
- DPRINT("PiBeforeBeginThread(Eip %x)\n", c.Eip);
- //KeReleaseSpinLock(&PiThreadListLock, PASSIVE_LEVEL);
KeLowerIrql(PASSIVE_LEVEL);
}
-#if 0
-VOID
-PsBeginThread(PKSTART_ROUTINE StartRoutine, PVOID StartContext)
-{
- NTSTATUS Ret;
-
- // KeReleaseSpinLock(&PiThreadListLock,PASSIVE_LEVEL);
- KeLowerIrql(PASSIVE_LEVEL);
- Ret = StartRoutine(StartContext);
- PsTerminateSystemThread(Ret);
- KeBugCheck(0);
-}
-#endif
-
-VOID
-PiDeleteThread(PVOID ObjectBody)
-{
- KIRQL oldIrql;
-
- DPRINT("PiDeleteThread(ObjectBody %x)\n",ObjectBody);
-
- KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
- DPRINT("Process %x(%d)\n", ((PETHREAD)ObjectBody)->ThreadsProcess,
- ObGetReferenceCount(((PETHREAD)ObjectBody)->ThreadsProcess));
- ObDereferenceObject(((PETHREAD)ObjectBody)->ThreadsProcess);
- ((PETHREAD)ObjectBody)->ThreadsProcess = NULL;
- PiNrThreads--;
- RemoveEntryList(&((PETHREAD)ObjectBody)->Tcb.ThreadListEntry);
- HalReleaseTask((PETHREAD)ObjectBody);
- KeReleaseSpinLock(&PiThreadListLock, oldIrql);
- DPRINT("PiDeleteThread() finished\n");
-}
-
-VOID
-PiCloseThread(PVOID ObjectBody,
- ULONG HandleCount)
-{
- DPRINT("PiCloseThread(ObjectBody %x)\n", ObjectBody);
- DPRINT("ObGetReferenceCount(ObjectBody) %d "
- "ObGetHandleCount(ObjectBody) %d\n",
- ObGetReferenceCount(ObjectBody),
- ObGetHandleCount(ObjectBody));
-}
-
NTSTATUS
-PsInitializeThread(HANDLE ProcessHandle,
+PsInitializeThread(PEPROCESS Process,
PETHREAD* ThreadPtr,
- PHANDLE ThreadHandle,
- ACCESS_MASK DesiredAccess,
- POBJECT_ATTRIBUTES ThreadAttributes,
+ POBJECT_ATTRIBUTES ObjectAttributes,
+ KPROCESSOR_MODE AccessMode,
BOOLEAN First)
{
PETHREAD Thread;
NTSTATUS Status;
KIRQL oldIrql;
- PEPROCESS Process;
- /*
- * Reference process
- */
- if (ProcessHandle != NULL)
- {
- Status = ObReferenceObjectByHandle(ProcessHandle,
- PROCESS_CREATE_THREAD,
- PsProcessType,
- UserMode,
- (PVOID*)&Process,
- NULL);
- if (Status != STATUS_SUCCESS)
- {
- DPRINT("Failed at %s:%d\n",__FILE__,__LINE__);
- return(Status);
- }
- DPRINT( "Creating thread in process %x\n", Process );
- }
- else
+ PAGED_CODE();
+
+ if (Process == NULL)
{
Process = PsInitialSystemProcess;
- ObReferenceObjectByPointer(Process,
- PROCESS_CREATE_THREAD,
- PsProcessType,
- UserMode);
}
/*
* Create and initialize thread
*/
- Status = ObCreateObject(ThreadHandle,
- DesiredAccess,
- ThreadAttributes,
+ Status = ObCreateObject(AccessMode,
PsThreadType,
+ ObjectAttributes,
+ KernelMode,
+ NULL,
+ sizeof(ETHREAD),
+ 0,
+ 0,
(PVOID*)&Thread);
if (!NT_SUCCESS(Status))
{
- return(Status);
+ return(Status);
}
- DPRINT("Thread = %x\n",Thread);
-
- PiNrThreads++;
-
- KeInitializeThread(&Process->Pcb, &Thread->Tcb, First);
- Thread->ThreadsProcess = Process;
/*
- * FIXME: What lock protects this?
+ * Reference process
*/
- InsertTailList(&Thread->ThreadsProcess->ThreadListHead,
- &Thread->Tcb.ProcessThreadListEntry);
- InitializeListHead(&Thread->TerminationPortList);
+ 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->Cid.UniqueThread = (HANDLE)InterlockedIncrement(
- &PiNextThreadUniqueId);
- Thread->Cid.UniqueProcess = (HANDLE)Thread->ThreadsProcess->UniqueProcessId;
- Thread->DeadThread = 0;
- Thread->Win32Thread = 0;
+ Thread->DeadThread = FALSE;
+ Thread->HasTerminated = FALSE;
+ Thread->Tcb.Win32Thread = NULL;
DPRINT("Thread->Cid.UniqueThread %d\n",Thread->Cid.UniqueThread);
- *ThreadPtr = Thread;
-
- KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
- InsertTailList(&PiThreadListHead, &Thread->Tcb.ThreadListEntry);
- KeReleaseSpinLock(&PiThreadListLock, oldIrql);
- Thread->Tcb.BasePriority = Thread->ThreadsProcess->Pcb.BasePriority;
+ Thread->Tcb.BasePriority = (CHAR)Process->Pcb.BasePriority;
Thread->Tcb.Priority = Thread->Tcb.BasePriority;
-
- return(STATUS_SUCCESS);
+
+ /*
+ * 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;
}
PETHREAD Thread,
PINITIAL_TEB InitialTeb)
{
- MEMORY_BASIC_INFORMATION Info;
+ PEPROCESS Process;
NTSTATUS Status;
ULONG ByteCount;
ULONG RegionSize;
ULONG TebSize;
PVOID TebBase;
TEB Teb;
- ULONG ResultLength;
-
- TebBase = (PVOID)0x7FFDE000;
- TebSize = PAGESIZE;
-
- while (TRUE)
+
+ 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
{
- Status = NtQueryVirtualMemory(ProcessHandle,
- TebBase,
- MemoryBasicInformation,
- &Info,
- sizeof(Info),
- &ResultLength);
- if (!NT_SUCCESS(Status))
- {
- DbgPrint("NtQueryVirtualMemory (Status %x)\n", Status);
- KeBugCheck(0);
- }
- /* FIXME: Race between this and the above check */
- if (Info.State == MEM_FREE)
- {
- /* The TEB must reside in user space */
- Status = NtAllocateVirtualMemory(ProcessHandle,
- &TebBase,
- 0,
- &TebSize,
- MEM_COMMIT,
- PAGE_READWRITE);
- if (NT_SUCCESS(Status))
- {
- break;
- }
- }
-
- TebBase = TebBase - TebSize;
+ 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)
DPRINT("Teb.Peb %x\n", Teb.Peb);
/* store stack information from InitialTeb */
- if (InitialTeb != NULL)
- {
- Teb.Tib.StackBase = InitialTeb->StackBase;
- Teb.Tib.StackLimit = InitialTeb->StackLimit;
- Teb.DeallocationStack = InitialTeb->StackAllocate;
- }
+ 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));
}
-NTSTATUS STDCALL
-NtCreateThread (PHANDLE ThreadHandle,
- ACCESS_MASK DesiredAccess,
- POBJECT_ATTRIBUTES ObjectAttributes,
- HANDLE ProcessHandle,
- PCLIENT_ID Client,
- PCONTEXT ThreadContext,
- PINITIAL_TEB InitialTeb,
- BOOLEAN CreateSuspended)
+VOID STDCALL
+LdrInitApcRundownRoutine(PKAPC Apc)
{
- PETHREAD Thread;
- PTEB TebBase;
- NTSTATUS Status;
-
- DPRINT("NtCreateThread(ThreadHandle %x, PCONTEXT %x)\n",
- ThreadHandle,ThreadContext);
-
- Status = PsInitializeThread(ProcessHandle,&Thread,ThreadHandle,
- DesiredAccess,ObjectAttributes, FALSE);
- if (!NT_SUCCESS(Status))
- {
- return(Status);
- }
-
-#if 0
- Status = NtWriteVirtualMemory(ProcessHandle,
- (PVOID)(((ULONG)ThreadContext->Esp) - 8),
- &ThreadContext->Eip,
- sizeof(ULONG),
- &Length);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("NtWriteVirtualMemory failed\n");
- KeBugCheck(0);
- }
- ThreadContext->Eip = LdrpGetSystemDllEntryPoint;
-#endif
-
- Status = Ke386InitThreadWithContext(&Thread->Tcb, ThreadContext);
- if (!NT_SUCCESS(Status))
- {
- return(Status);
- }
+ ExFreePool(Apc);
+}
- Status = PsCreateTeb (ProcessHandle,
- &TebBase,
- Thread,
- InitialTeb);
- if (!NT_SUCCESS(Status))
- {
- return(Status);
- }
- /* Attention: TebBase is in user memory space */
- Thread->Tcb.Teb = TebBase;
+VOID STDCALL
+LdrInitApcKernelRoutine(PKAPC Apc,
+ PKNORMAL_ROUTINE* NormalRoutine,
+ PVOID* NormalContext,
+ PVOID* SystemArgument1,
+ PVOID* SystemArgument2)
+{
+ ExFreePool(Apc);
+}
- Thread->StartAddress=NULL;
- if (Client != NULL)
- {
- *Client=Thread->Cid;
- }
-
- /*
- * Maybe send a message to the process's debugger
- */
- DbgkCreateThread((PVOID)ThreadContext->Eip);
-
- /*
- * Start the thread running
- */
- if (!CreateSuspended)
- {
- DPRINT("Not creating suspended\n");
- PsUnblockThread(Thread, NULL);
- }
- else
- {
- KeBugCheck(0);
- }
- return(STATUS_SUCCESS);
+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 = ExAllocatePool(NonPagedPool, sizeof(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;
}
-NTSTATUS STDCALL
+/*
+ * @implemented
+ */
+NTSTATUS STDCALL
PsCreateSystemThread(PHANDLE ThreadHandle,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes,
{
PETHREAD Thread;
NTSTATUS Status;
+ KIRQL oldIrql;
+
+ PAGED_CODE();
DPRINT("PsCreateSystemThread(ThreadHandle %x, ProcessHandle %x)\n",
ThreadHandle,ProcessHandle);
- Status = PsInitializeThread(ProcessHandle,&Thread,ThreadHandle,
- DesiredAccess,ObjectAttributes, FALSE);
+ Status = PsInitializeThread(NULL,
+ &Thread,
+ ObjectAttributes,
+ KernelMode,
+ FALSE);
if (!NT_SUCCESS(Status))
{
return(Status);
}
-
- Thread->StartAddress=StartRoutine;
- Status = Ke386InitThread(&Thread->Tcb, StartRoutine, StartContext);
+
+ /* 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))
{
- return(Status);
+ ObDereferenceObject(Thread);
+ return(Status);
}
- if (ClientId!=NULL)
+ if (ClientId != NULL)
{
*ClientId=Thread->Cid;
}
- PsUnblockThread(Thread, NULL);
+ oldIrql = KeAcquireDispatcherDatabaseLock ();
+ KiUnblockThread(&Thread->Tcb, NULL, 0);
+ KeReleaseDispatcherDatabaseLock(oldIrql);
+
+ Status = ObInsertObject((PVOID)Thread,
+ NULL,
+ DesiredAccess,
+ 0,
+ NULL,
+ ThreadHandle);
- return(STATUS_SUCCESS);
+ /* 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 */