fixed a few race conditions during thread/process termination leading to dead-locks
[reactos.git] / reactos / ntoskrnl / ps / create.c
index fbed9ab..0aa5a92 100644 (file)
@@ -1,14 +1,13 @@
-/* $Id: create.c,v 1.84 2004/10/24 20:37:27 weiden 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
  */
 
 /*
 
 /* GLOBAL *******************************************************************/
 
-extern KSPIN_LOCK PiThreadLock;
-
 #define MAX_THREAD_NOTIFY_ROUTINE_COUNT    8
 
 static ULONG PiThreadNotifyRoutineCount = 0;
 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
- */
-NTSTATUS STDCALL
-NtOpenThreadToken (IN HANDLE ThreadHandle,
-                  IN ACCESS_MASK DesiredAccess,
-                  IN BOOLEAN OpenAsSelf,
-                  OUT PHANDLE TokenHandle)
-{
-  PACCESS_TOKEN Token;
-  PETHREAD Thread;
-  NTSTATUS Status;
-
-  Status = ObReferenceObjectByHandle (ThreadHandle,
-                                     0,
-                                     PsThreadType,
-                                     UserMode,
-                                     (PVOID*)&Thread,
-                                     NULL);
-   if (!NT_SUCCESS(Status))
-     {
-       return(Status);
-     }
-
-  if (OpenAsSelf)
-    {
-      Token = Thread->ThreadsProcess->Token;
-    }
-  else
-    {
-      if (Thread->ActiveImpersonationInfo == FALSE)
-       {
-         ObDereferenceObject (Thread);
-         return STATUS_NO_TOKEN;
-       }
-
-      Token = Thread->ImpersonationInfo->Token;
-    }
-
-  if (Token == NULL)
-    {
-      ObDereferenceObject (Thread);
-      return STATUS_NO_TOKEN;
-    }
-
-  Status = ObCreateHandle (PsGetCurrentProcess(),
-                          Token,
-                          DesiredAccess,
-                          FALSE,
-                          TokenHandle);
-
-  ObDereferenceObject (Thread);
-
-  return Status;
-}
-
-
-/*
- * @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
-STDCALL
-PsDereferencePrimaryToken(
-    IN PACCESS_TOKEN PrimaryToken
-    )
-{
-       UNIMPLEMENTED;  
-}
-
-/*
- * @unimplemented
- */
-BOOLEAN
+ULONG
 STDCALL
-PsDisableImpersonation(
-    IN PETHREAD Thread,
-    IN PSE_IMPERSONATION_STATE ImpersonationState
-    )
-{
-       UNIMPLEMENTED;
-       return FALSE;   
-}
-
-/*
- * @unimplemented
- */                       
-VOID
-STDCALL
-PsRestoreImpersonation(
-       IN PETHREAD      Thread,
-       IN PSE_IMPERSONATION_STATE      ImpersonationState
-       )
-{
-       UNIMPLEMENTED;
-}
+KeSuspendThread(PKTHREAD Thread);
+/* FUNCTIONS ***************************************************************/
 
 VOID
 PiBeforeBeginThread(CONTEXT c)
@@ -371,62 +43,31 @@ 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);
-
-  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,
@@ -434,38 +75,25 @@ PsInitializeThread(PEPROCESS Process,
                           (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;
@@ -487,14 +115,14 @@ PsInitializeThread(PEPROCESS Process,
    Thread->LpcExitThreadCalled = FALSE;
    Thread->LpcReceivedMsgIdValid = FALSE;
 
-   KeAcquireSpinLock(&PiThreadLock, &oldIrql);
+   oldIrql = KeAcquireDispatcherDatabaseLock();
    InsertTailList(&Process->ThreadListHead,
                  &Thread->ThreadListEntry);
-   KeReleaseSpinLock(&PiThreadLock, oldIrql);
+   KeReleaseDispatcherDatabaseLock(oldIrql);
 
    *ThreadPtr = Thread;
 
-   return(STATUS_SUCCESS);
+   return STATUS_SUCCESS;
 }
 
 
@@ -511,6 +139,8 @@ PsCreateTeb(HANDLE ProcessHandle,
    ULONG TebSize;
    PVOID TebBase;
    TEB Teb;
+   
+   PAGED_CODE();
 
    TebSize = PAGE_SIZE;
 
@@ -536,7 +166,7 @@ PsCreateTeb(HANDLE ProcessHandle,
    else
      {
        Process = Thread->ThreadsProcess;
-       ExAcquireFastMutex(&Process->TebLock);
+       PsLockProcess(Process, FALSE);
        if (NULL == Process->TebBlock ||
            Process->TebBlock == Process->TebLastAllocated)
          {
@@ -550,7 +180,7 @@ PsCreateTeb(HANDLE ProcessHandle,
                                             PAGE_READWRITE);
            if (! NT_SUCCESS(Status))
              {
-               ExReleaseFastMutex(&Process->TebLock);
+               PsUnlockProcess(Process);
                DPRINT1("Failed to reserve virtual memory for TEB\n");
                return Status;
              }
@@ -569,7 +199,7 @@ PsCreateTeb(HANDLE ProcessHandle,
            return Status;
          }
        Process->TebLastAllocated = TebBase;
-       ExReleaseFastMutex(&Process->TebLock);
+       PsUnlockProcess(Process);
      }
 
    DPRINT ("TebBase %p TebSize %lu\n", TebBase, TebSize);
@@ -668,16 +298,66 @@ NtCreateThread(OUT PHANDLE ThreadHandle,
               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);
@@ -685,31 +365,55 @@ NtCreateThread(OUT PHANDLE ThreadHandle,
   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);
     }
 
@@ -719,17 +423,14 @@ NtCreateThread(OUT PHANDLE ThreadHandle,
                       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
    */
@@ -746,7 +447,7 @@ NtCreateThread(OUT PHANDLE ThreadHandle,
    */
   if (CreateSuspended)
     {
-      PsSuspendThread(Thread, NULL);
+      KeSuspendThread(&Thread->Tcb);
     }
 
   /*
@@ -758,16 +459,43 @@ NtCreateThread(OUT PHANDLE ThreadHandle,
                  LdrInitApcRundownRoutine, LdrpGetSystemDllEntryPoint(), 
                  UserMode, NULL);
   KeInsertQueueApc(LdrInitApc, NULL, NULL, IO_NO_INCREMENT);
-
-  /*
-   * Start the thread running and force it to execute the APC(s) we just
-   * queued before it runs anything else in user-mode.
+  
+  /* 
+   * 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.Alertable = TRUE;
-  Thread->Tcb.Alerted[0] = 1;
-  PsUnblockThread(Thread, NULL);
-
-  return(STATUS_SUCCESS);
+  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;
 }
 
 
@@ -801,26 +529,41 @@ PsCreateSystemThread(PHANDLE ThreadHandle,
 {
    PETHREAD Thread;
    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)
@@ -828,9 +571,21 @@ PsCreateSystemThread(PHANDLE ThreadHandle,
        *ClientId=Thread->Cid;
      }
 
-   PsUnblockThread(Thread, NULL);
+   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;
 }