-/* $Id: create.c,v 1.89 2004/12/18 15:52:51 hbirr 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
- * 09/08/03: Skywing: ThreadEventPair support (delete)
+ * 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
*/
/*
static PCREATE_THREAD_NOTIFY_ROUTINE
PiThreadNotifyRoutine[MAX_THREAD_NOTIFY_ROUTINE_COUNT];
-/* FUNCTIONS ***************************************************************/
-
-/*
- * @implemented
- */
-NTSTATUS STDCALL
-PsAssignImpersonationToken(PETHREAD Thread,
- HANDLE TokenHandle)
-{
- PACCESS_TOKEN Token;
- SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
- NTSTATUS Status;
-
- if (TokenHandle != NULL)
- {
- Status = ObReferenceObjectByHandle(TokenHandle,
- TOKEN_IMPERSONATE,
- SepTokenObjectType,
- KeGetPreviousMode(),
- (PVOID*)&Token,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- return(Status);
- }
- ImpersonationLevel = Token->ImpersonationLevel;
- }
- else
- {
- Token = NULL;
- ImpersonationLevel = 0;
- }
-
- PsImpersonateClient(Thread,
- Token,
- FALSE,
- FALSE,
- ImpersonationLevel);
- if (Token != NULL)
- {
- ObDereferenceObject(Token);
- }
-
- return(STATUS_SUCCESS);
-}
-
-
-/*
- * @implemented
- */
-VOID STDCALL
-PsRevertToSelf (VOID)
-{
- PsRevertThreadToSelf(PsGetCurrentThread());
-}
-
-/*
- * @implemented
- */
-VOID
-STDCALL
-PsRevertThreadToSelf(
- IN PETHREAD Thread
- )
-{
- if (Thread->ActiveImpersonationInfo == TRUE)
- {
- ObDereferenceObject (Thread->ImpersonationInfo->Token);
- Thread->ActiveImpersonationInfo = FALSE;
- }
-}
-
-/*
- * @implemented
- */
-VOID STDCALL
-PsImpersonateClient (IN PETHREAD Thread,
- IN PACCESS_TOKEN Token,
- IN BOOLEAN CopyOnOpen,
- IN BOOLEAN EffectiveOnly,
- IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
-{
- if (Token == NULL)
- {
- if (Thread->ActiveImpersonationInfo == TRUE)
- {
- Thread->ActiveImpersonationInfo = FALSE;
- if (Thread->ImpersonationInfo->Token != NULL)
- {
- ObDereferenceObject (Thread->ImpersonationInfo->Token);
- }
- }
- return;
- }
-
- if (Thread->ImpersonationInfo == NULL)
- {
- Thread->ImpersonationInfo = ExAllocatePool (NonPagedPool,
- sizeof(PS_IMPERSONATION_INFORMATION));
- }
-
- Thread->ImpersonationInfo->Level = ImpersonationLevel;
- Thread->ImpersonationInfo->CopyOnOpen = CopyOnOpen;
- Thread->ImpersonationInfo->EffectiveOnly = EffectiveOnly;
- Thread->ImpersonationInfo->Token = Token;
- ObReferenceObjectByPointer (Token,
- 0,
- SepTokenObjectType,
- KernelMode);
- Thread->ActiveImpersonationInfo = TRUE;
-}
-
-
-PACCESS_TOKEN
-PsReferenceEffectiveToken(PETHREAD Thread,
- PTOKEN_TYPE TokenType,
- PBOOLEAN EffectiveOnly,
- PSECURITY_IMPERSONATION_LEVEL Level)
-{
- PEPROCESS Process;
- PACCESS_TOKEN Token;
-
- if (Thread->ActiveImpersonationInfo == FALSE)
- {
- Process = Thread->ThreadsProcess;
- *TokenType = TokenPrimary;
- *EffectiveOnly = FALSE;
- Token = Process->Token;
- }
- else
- {
- Token = Thread->ImpersonationInfo->Token;
- *TokenType = TokenImpersonation;
- *EffectiveOnly = Thread->ImpersonationInfo->EffectiveOnly;
- *Level = Thread->ImpersonationInfo->Level;
- }
- return(Token);
-}
-
-
-NTSTATUS STDCALL
-NtImpersonateThread(IN HANDLE ThreadHandle,
- IN HANDLE ThreadToImpersonateHandle,
- IN PSECURITY_QUALITY_OF_SERVICE SecurityQualityOfService)
-{
- SECURITY_CLIENT_CONTEXT ClientContext;
- PETHREAD Thread;
- PETHREAD ThreadToImpersonate;
- NTSTATUS Status;
-
- 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,
- &ClientContext);
- if (!NT_SUCCESS(Status))
- {
- ObDereferenceObject (ThreadToImpersonate);
- ObDereferenceObject (Thread);
- return Status;
- }
-
- SeImpersonateClient (&ClientContext,
- Thread);
- if (ClientContext.Token != NULL)
- {
- ObDereferenceObject (ClientContext.Token);
- }
-
- ObDereferenceObject (ThreadToImpersonate);
- ObDereferenceObject (Thread);
-
- return STATUS_SUCCESS;
-}
-
-/*
- * @implemented
- */
-PACCESS_TOKEN STDCALL
-PsReferenceImpersonationToken(IN PETHREAD Thread,
- OUT PBOOLEAN CopyOnOpen,
- OUT PBOOLEAN EffectiveOnly,
- OUT PSECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
-{
- if (Thread->ActiveImpersonationInfo == FALSE)
- {
- return NULL;
- }
-
- *ImpersonationLevel = Thread->ImpersonationInfo->Level;
- *CopyOnOpen = Thread->ImpersonationInfo->CopyOnOpen;
- *EffectiveOnly = Thread->ImpersonationInfo->EffectiveOnly;
- ObReferenceObjectByPointer (Thread->ImpersonationInfo->Token,
- TOKEN_ALL_ACCESS,
- SepTokenObjectType,
- KernelMode);
-
- return Thread->ImpersonationInfo->Token;
-}
-
-/*
- * @unimplemented
- */
-VOID
-STDCALL
-PsDereferenceImpersonationToken(
- IN PACCESS_TOKEN ImpersonationToken
- )
-{
- UNIMPLEMENTED;
-}
-
-/*
- * @unimplemented
- */
-VOID
+ULONG
STDCALL
-PsDereferencePrimaryToken(
- IN PACCESS_TOKEN PrimaryToken
- )
-{
- UNIMPLEMENTED;
-}
-
-/*
- * @implemented
- */
-BOOLEAN
-STDCALL
-PsDisableImpersonation(
- IN PETHREAD Thread,
- IN PSE_IMPERSONATION_STATE ImpersonationState
- )
-{
- if (Thread->ActiveImpersonationInfo == FALSE)
- {
- ImpersonationState->Token = NULL;
- ImpersonationState->CopyOnOpen = FALSE;
- ImpersonationState->EffectiveOnly = FALSE;
- ImpersonationState->Level = 0;
- return TRUE;
- }
-
-/* FIXME */
-/* ExfAcquirePushLockExclusive(&Thread->ThreadLock); */
-
- Thread->ActiveImpersonationInfo = FALSE;
- ImpersonationState->Token = Thread->ImpersonationInfo->Token;
- ImpersonationState->CopyOnOpen = Thread->ImpersonationInfo->CopyOnOpen;
- ImpersonationState->EffectiveOnly = Thread->ImpersonationInfo->EffectiveOnly;
- ImpersonationState->Level = Thread->ImpersonationInfo->Level;
-
-/* FIXME */
-/* ExfReleasePushLock(&Thread->ThreadLock); */
-
- return TRUE;
-}
-
-/*
- * @implemented
- */
-VOID
-STDCALL
-PsRestoreImpersonation(
- IN PETHREAD Thread,
- IN PSE_IMPERSONATION_STATE ImpersonationState
- )
-{
- PsImpersonateClient(Thread, ImpersonationState->Token,
- ImpersonationState->CopyOnOpen,
- ImpersonationState->EffectiveOnly,
- ImpersonationState->Level);
- ObfDereferenceObject(ImpersonationState->Token);
-}
+KeSuspendThread(PKTHREAD Thread);
+/* FUNCTIONS ***************************************************************/
VOID
PiBeforeBeginThread(CONTEXT c)
KeLowerIrql(PASSIVE_LEVEL);
}
-
-VOID STDCALL
-PiDeleteThread(PVOID ObjectBody)
-{
- PETHREAD Thread;
- PEPROCESS Process;
-
- Thread = (PETHREAD)ObjectBody;
-
- DPRINT("PiDeleteThread(ObjectBody %x)\n",ObjectBody);
-
- Process = Thread->ThreadsProcess;
- Thread->ThreadsProcess = NULL;
-
- PsDeleteCidHandle(Thread->Cid.UniqueThread, PsThreadType);
-
- if(Thread->Tcb.Win32Thread != NULL)
- {
- /* Free the W32THREAD structure if present */
- ExFreePool (Thread->Tcb.Win32Thread);
- }
-
- KeReleaseThread(ETHREAD_TO_KTHREAD(Thread));
-
- ObDereferenceObject(Process);
-
- DPRINT("PiDeleteThread() finished\n");
-}
-
-
NTSTATUS
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;
-
+
+ PAGED_CODE();
+
if (Process == NULL)
{
Process = PsInitialSystemProcess;
}
-
- /*
- * Reference process
- */
- ObReferenceObjectByPointer(Process,
- PROCESS_CREATE_THREAD,
- PsProcessType,
- KernelMode);
/*
* Create and initialize thread
*/
- Status = ObCreateObject(UserMode,
+ Status = ObCreateObject(AccessMode,
PsThreadType,
- ThreadAttributes,
- UserMode,
+ ObjectAttributes,
+ KernelMode,
NULL,
sizeof(ETHREAD),
0,
(PVOID*)&Thread);
if (!NT_SUCCESS(Status))
{
- ObDereferenceObject (Process);
return(Status);
}
- /* create a client id handle */
- Status = PsCreateCidHandle(Thread, PsThreadType, &Thread->Cid.UniqueThread);
- if (!NT_SUCCESS(Status))
- {
- ObDereferenceObject (Thread);
- ObDereferenceObject (Process);
- return Status;
- }
- Thread->ThreadsProcess = Process;
- Thread->Cid.UniqueProcess = (HANDLE)Thread->ThreadsProcess->UniqueProcessId;
-
- Status = ObInsertObject ((PVOID)Thread,
- NULL,
- DesiredAccess,
- 0,
- NULL,
- ThreadHandle);
- if (!NT_SUCCESS(Status))
- {
- ObDereferenceObject (Thread);
- ObDereferenceObject (Process);
- 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->TerminationPortList);
+ InitializeListHead(&Thread->ActiveTimerListHead);
KeInitializeSpinLock(&Thread->ActiveTimerListLock);
InitializeListHead(&Thread->IrpList);
Thread->DeadThread = FALSE;
*ThreadPtr = Thread;
- return(STATUS_SUCCESS);
+ return STATUS_SUCCESS;
}
ULONG TebSize;
PVOID TebBase;
TEB Teb;
+
+ PAGED_CODE();
TebSize = PAGE_SIZE;
else
{
Process = Thread->ThreadsProcess;
- ExAcquireFastMutex(&Process->TebLock);
+ PsLockProcess(Process, FALSE);
if (NULL == Process->TebBlock ||
Process->TebBlock == Process->TebLastAllocated)
{
PAGE_READWRITE);
if (! NT_SUCCESS(Status))
{
- ExReleaseFastMutex(&Process->TebLock);
+ PsUnlockProcess(Process);
DPRINT1("Failed to reserve virtual memory for TEB\n");
return Status;
}
return Status;
}
Process->TebLastAllocated = TebBase;
- ExReleaseFastMutex(&Process->TebLock);
+ PsUnlockProcess(Process);
}
DPRINT ("TebBase %p TebSize %lu\n", TebBase, TebSize);
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
IN HANDLE ProcessHandle,
- OUT PCLIENT_ID Client,
+ 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;
- NTSTATUS Status;
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,
- UserMode,
+ 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,
- ThreadHandle,
- DesiredAccess,
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);
}
InitialTeb);
if (!NT_SUCCESS(Status))
{
+ PsDeleteCidHandle(Thread->Cid.UniqueThread, PsThreadType);
+ ObDereferenceObject(Thread);
return(Status);
}
Thread->Tcb.Teb = TebBase;
Thread->StartAddress = NULL;
- if (Client != NULL)
- {
- *Client = Thread->Cid;
- }
-
/*
* Maybe send a message to the process's debugger
*/
*/
if (CreateSuspended)
{
- PsSuspendThread(Thread, NULL);
+ KeSuspendThread(&Thread->Tcb);
}
/*
Thread->Tcb.Alerted[KernelMode] = TRUE;
oldIrql = KeAcquireDispatcherDatabaseLock ();
- PsUnblockThread(Thread, NULL);
+ KiUnblockThread(&Thread->Tcb, NULL, 0);
KeReleaseDispatcherDatabaseLock(oldIrql);
-
- return(STATUS_SUCCESS);
+ 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 Status;
KIRQL oldIrql;
+ PAGED_CODE();
+
DPRINT("PsCreateSystemThread(ThreadHandle %x, ProcessHandle %x)\n",
ThreadHandle,ProcessHandle);
Status = PsInitializeThread(NULL,
&Thread,
- ThreadHandle,
- DesiredAccess,
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))
{
- return(Status);
+ ObDereferenceObject(Thread);
+ return(Status);
}
if (ClientId != NULL)
*ClientId=Thread->Cid;
}
- oldIrql = KeAcquireDispatcherDatabaseLock ();
- PsUnblockThread(Thread, NULL);
- KeReleaseDispatcherDatabaseLock(oldIrql);
+ oldIrql = KeAcquireDispatcherDatabaseLock ();
+ KiUnblockThread(&Thread->Tcb, NULL, 0);
+ KeReleaseDispatcherDatabaseLock(oldIrql);
- return(STATUS_SUCCESS);
+ 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;
}