Initialize LPC-related fields in ETHREAD.
[reactos.git] / reactos / ntoskrnl / ps / create.c
index 9227f88..afca150 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: create.c,v 1.39 2001/08/26 17:30:21 ekohl Exp $
+/* $Id: create.c,v 1.73 2004/03/24 22:00:39 ea Exp $
  *
  * COPYRIGHT:              See COPYING in the top level directory
  * PROJECT:                ReactOS kernel
@@ -8,6 +8,7 @@
  * REVISION HISTORY: 
  *               23/06/98: Created
  *               12/10/99: Phillip Susi:  Thread priorities, and APC work
+ *               09/08/03: Skywing:       ThreadEventPair support (delete)
  */
 
 /*
 
 /* INCLUDES ****************************************************************/
 
-#include <ddk/ntddk.h>
+#include <limits.h>
+
+#define NTOS_MODE_KERNEL
+#include <ntos.h>
 #include <internal/ke.h>
 #include <internal/ob.h>
 #include <internal/ps.h>
-#include <internal/ob.h>
+#include <internal/se.h>
 #include <internal/id.h>
 #include <internal/dbg.h>
+#include <internal/ldr.h>
 
 #define NDEBUG
 #include <internal/debug.h>
@@ -40,6 +45,12 @@ extern ULONG PiNrThreads;
 
 extern LIST_ENTRY PiThreadListHead;
 
+#define MAX_THREAD_NOTIFY_ROUTINE_COUNT    8
+
+static ULONG PiThreadNotifyRoutineCount = 0;
+static PCREATE_THREAD_NOTIFY_ROUTINE
+PiThreadNotifyRoutine[MAX_THREAD_NOTIFY_ROUTINE_COUNT];
+
 /* FUNCTIONS ***************************************************************/
 
 NTSTATUS STDCALL
@@ -49,12 +60,12 @@ PsAssignImpersonationToken(PETHREAD Thread,
    PACCESS_TOKEN Token;
    SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
    NTSTATUS Status;
-   
+
    if (TokenHandle != NULL)
      {
        Status = ObReferenceObjectByHandle(TokenHandle,
                                           0,
-                                          SeTokenType,
+                                          SepTokenObjectType,
                                           UserMode,
                                           (PVOID*)&Token,
                                           NULL);
@@ -69,7 +80,7 @@ PsAssignImpersonationToken(PETHREAD Thread,
        Token = NULL;
        ImpersonationLevel = 0;
      }
-   
+
    PsImpersonateClient(Thread,
                       Token,
                       0,
@@ -82,143 +93,162 @@ PsAssignImpersonationToken(PETHREAD Thread,
    return(STATUS_SUCCESS);
 }
 
-VOID STDCALL 
-PsRevertToSelf(PETHREAD Thread)
+
+/*
+ * @implemented
+ */
+VOID STDCALL
+PsRevertToSelf (VOID)
 {
-   if (Thread->ActiveImpersonationInfo != 0)
-     {
-       Thread->ActiveImpersonationInfo = 0;
-       ObDereferenceObject(Thread->ImpersonationInfo->Token);
-     }
+  PETHREAD Thread;
+
+  Thread = PsGetCurrentThread ();
+
+  if (Thread->ActiveImpersonationInfo == TRUE)
+    {
+      ObDereferenceObject (Thread->ImpersonationInfo->Token);
+      Thread->ActiveImpersonationInfo = FALSE;
+    }
 }
 
-VOID STDCALL 
-PsImpersonateClient(PETHREAD Thread,
-                   PACCESS_TOKEN Token,
-                   UCHAR b,
-                   UCHAR c,
-                   SECURITY_IMPERSONATION_LEVEL Level)
+
+/*
+ * @implemented
+ */
+VOID STDCALL
+PsImpersonateClient (IN PETHREAD Thread,
+                    IN PACCESS_TOKEN Token,
+                    IN BOOLEAN CopyOnOpen,
+                    IN BOOLEAN EffectiveOnly,
+                    IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
 {
-   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,
+  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_INFO));
+    }
+
+  Thread->ImpersonationInfo->Level = ImpersonationLevel;
+  Thread->ImpersonationInfo->CopyOnOpen = CopyOnOpen;
+  Thread->ImpersonationInfo->EffectiveOnly = EffectiveOnly;
+  Thread->ImpersonationInfo->Token = Token;
+  ObReferenceObjectByPointer (Token,
                              0,
-                             SeTokenType,
+                             SepTokenObjectType,
                              KernelMode);
-   Thread->ActiveImpersonationInfo = 1;
+  Thread->ActiveImpersonationInfo = TRUE;
 }
 
-PACCESS_TOKEN 
+
+PACCESS_TOKEN
 PsReferenceEffectiveToken(PETHREAD Thread,
                          PTOKEN_TYPE TokenType,
-                         PUCHAR b,
+                         PBOOLEAN EffectiveOnly,
                          PSECURITY_IMPERSONATION_LEVEL Level)
 {
    PEPROCESS Process;
    PACCESS_TOKEN Token;
    
-   if (Thread->ActiveImpersonationInfo == 0)
+   if (Thread->ActiveImpersonationInfo == FALSE)
      {
        Process = Thread->ThreadsProcess;
        *TokenType = TokenPrimary;
-       *b = 0;
+       *EffectiveOnly = FALSE;
        Token = Process->Token;
      }
    else
      {
        Token = Thread->ImpersonationInfo->Token;
        *TokenType = TokenImpersonation;
-       *b = Thread->ImpersonationInfo->Unknown2;
-       *Level = Thread->ImpersonationInfo->Level;      
+       *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)
+
+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,
+  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,
+  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,
+  if (!NT_SUCCESS(Status))
+    {
+      ObDereferenceObject (Thread);
+      return Status;
+    }
+
+  Status = SeCreateClientSecurity (ThreadToImpersonate,
                                   SecurityQualityOfService,
                                   0,
-                                  &b);
-   if (!NT_SUCCESS(Status))
-     {
-       ObDereferenceObject(Thread);
-       ObDereferenceObject(ThreadToImpersonate);
-       return(Status);
+                                  &ClientContext);
+  if (!NT_SUCCESS(Status))
+    {
+      ObDereferenceObject (ThreadToImpersonate);
+      ObDereferenceObject (Thread);
+      return Status;
      }
-   
-   SeImpersonateClient(&b, Thread);
-   if (b.Token != NULL)
-     {
-       ObDereferenceObject(b.Token);
-     }
-   return(STATUS_SUCCESS);
+
+  SeImpersonateClient (&ClientContext,
+                      Thread);
+  if (ClientContext.Token != NULL)
+    {
+      ObDereferenceObject (ClientContext.Token);
+    }
+
+  ObDereferenceObject (ThreadToImpersonate);
+  ObDereferenceObject (Thread);
+
+  return STATUS_SUCCESS;
 }
 
-NTSTATUS STDCALL 
-NtOpenThreadToken(IN   HANDLE          ThreadHandle,  
-                 IN    ACCESS_MASK     DesiredAccess,  
-                 IN    BOOLEAN         OpenAsSelf,     
-                 OUT   PHANDLE         TokenHandle)
+
+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,
+  PACCESS_TOKEN Token;
+  PETHREAD Thread;
+  NTSTATUS Status;
+
+  Status = ObReferenceObjectByHandle (ThreadHandle,
                                      0,
                                      PsThreadType,
                                      UserMode,
@@ -228,100 +258,96 @@ NtOpenThreadToken(IN     HANDLE          ThreadHandle,
      {
        return(Status);
      }
-   
-   Token = PsReferencePrimaryToken(Thread->ThreadsProcess);
-   SepCreateImpersonationTokenDacl(Token);
-#endif
-   return(STATUS_UNSUCCESSFUL);
+
+  if (OpenAsSelf)
+    {
+      if (Thread->ActiveImpersonationInfo == FALSE)
+       {
+         ObDereferenceObject (Thread);
+         return STATUS_NO_TOKEN;
+       }
+
+      Token = Thread->ImpersonationInfo->Token;
+    }
+  else
+    {
+      Token = Thread->ThreadsProcess->Token;
+    }
+
+  if (Token == NULL)
+    {
+      ObDereferenceObject (Thread);
+      return STATUS_NO_TOKEN;
+    }
+
+  Status = ObCreateHandle (PsGetCurrentProcess(),
+                          Token,
+                          DesiredAccess,
+                          FALSE,
+                          TokenHandle);
+
+  ObDereferenceObject (Thread);
+
+  return Status;
 }
 
-PACCESS_TOKEN STDCALL 
-PsReferenceImpersonationToken(PETHREAD Thread,
-                             PULONG Unknown1,
-                             PULONG Unknown2,
-                             SECURITY_IMPERSONATION_LEVEL* Level)
+
+/*
+ * @implemented
+ */
+PACCESS_TOKEN STDCALL
+PsReferenceImpersonationToken(IN PETHREAD Thread,
+                             OUT PBOOLEAN CopyOnOpen,
+                             OUT PBOOLEAN EffectiveOnly,
+                             OUT PSECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
 {
-   if (Thread->ActiveImpersonationInfo == 0)
-     {
-       return(NULL);
-     }
-   
-   *Level = Thread->ImpersonationInfo->Level;
-   *Unknown1 = Thread->ImpersonationInfo->Unknown1;
-   *Unknown2 = Thread->ImpersonationInfo->Unknown2;
-   ObReferenceObjectByPointer(Thread->ImpersonationInfo->Token,
+  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,
-                             SeTokenType,
+                             SepTokenObjectType,
                              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);
+  return Thread->ImpersonationInfo->Token;
 }
 
-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 STDCALL
 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");
-}
+  KIRQL oldIrql;
+  PETHREAD Thread;
 
-VOID STDCALL
-PiCloseThread(PVOID ObjectBody,
-             ULONG HandleCount)
-{
-   DPRINT("PiCloseThread(ObjectBody %x)\n", ObjectBody);
-   DPRINT("ObGetReferenceCount(ObjectBody) %d "
-          "ObGetHandleCount(ObjectBody) %d\n",
-          ObGetReferenceCount(ObjectBody),
-          ObGetHandleCount(ObjectBody));
+  Thread = (PETHREAD)ObjectBody;
+
+  DPRINT("PiDeleteThread(ObjectBody %x)\n",ObjectBody);
+
+  ObDereferenceObject(Thread->ThreadsProcess);
+  Thread->ThreadsProcess = NULL;
+
+  KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
+  PiNrThreads--;
+  RemoveEntryList(&Thread->Tcb.ThreadListEntry);
+  KeReleaseSpinLock(&PiThreadListLock, oldIrql);
+
+  KeReleaseThread(Thread);
+  DPRINT("PiDeleteThread() finished\n");
 }
 
+
 NTSTATUS
 PsInitializeThread(HANDLE ProcessHandle,
                   PETHREAD* ThreadPtr,
@@ -334,7 +360,7 @@ PsInitializeThread(HANDLE ProcessHandle,
    NTSTATUS Status;
    KIRQL oldIrql;
    PEPROCESS Process;
-   
+
    /*
     * Reference process
     */
@@ -365,16 +391,32 @@ PsInitializeThread(HANDLE ProcessHandle,
    /*
     * Create and initialize thread
     */
-   Status = ObCreateObject(ThreadHandle,
-                          DesiredAccess,
-                          ThreadAttributes,
+   Status = ObCreateObject(UserMode,
                           PsThreadType,
+                          ThreadAttributes,
+                          UserMode,
+                          NULL,
+                          sizeof(ETHREAD),
+                          0,
+                          0,
                           (PVOID*)&Thread);
    if (!NT_SUCCESS(Status))
      {
        return(Status);
      }
 
+  Status = ObInsertObject ((PVOID)Thread,
+                          NULL,
+                          DesiredAccess,
+                          0,
+                          NULL,
+                          ThreadHandle);
+  if (!NT_SUCCESS(Status))
+    {
+      ObDereferenceObject (Thread);
+      return Status;
+    }
+
    DPRINT("Thread = %x\n",Thread);
    
    PiNrThreads++;
@@ -390,7 +432,7 @@ PsInitializeThread(HANDLE ProcessHandle,
    KeInitializeSpinLock(&Thread->ActiveTimerListLock);
    InitializeListHead(&Thread->IrpList);
    Thread->Cid.UniqueThread = (HANDLE)InterlockedIncrement(
-                                             &PiNextThreadUniqueId);
+                                             (LONG *)&PiNextThreadUniqueId);
    Thread->Cid.UniqueProcess = (HANDLE)Thread->ThreadsProcess->UniqueProcessId;
    Thread->DeadThread = 0;
    Thread->Win32Thread = 0;
@@ -402,9 +444,19 @@ PsInitializeThread(HANDLE ProcessHandle,
    InsertTailList(&PiThreadListHead, &Thread->Tcb.ThreadListEntry);
    KeReleaseSpinLock(&PiThreadListLock, oldIrql);
 
-   Thread->Tcb.BasePriority = Thread->ThreadsProcess->Pcb.BasePriority;
+   Thread->Tcb.BasePriority = (CHAR)Thread->ThreadsProcess->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;
+
    return(STATUS_SUCCESS);
 }
 
@@ -413,7 +465,7 @@ static NTSTATUS
 PsCreateTeb(HANDLE ProcessHandle,
            PTEB *TebPtr,
            PETHREAD Thread,
-           PINITIAL_TEB InitialTeb)
+           PUSER_STACK UserStack)
 {
    MEMORY_BASIC_INFORMATION Info;
    NTSTATUS Status;
@@ -425,7 +477,7 @@ PsCreateTeb(HANDLE ProcessHandle,
    ULONG ResultLength;
 
    TebBase = (PVOID)0x7FFDE000;
-   TebSize = PAGESIZE;
+   TebSize = PAGE_SIZE;
 
    while (TRUE)
      {
@@ -437,8 +489,8 @@ PsCreateTeb(HANDLE ProcessHandle,
                                      &ResultLength);
        if (!NT_SUCCESS(Status))
          {
-            DbgPrint("NtQueryVirtualMemory (Status %x)\n", Status);
-            KeBugCheck(0);
+            CPRINT("NtQueryVirtualMemory (Status %x)\n", Status);
+            KEBUGCHECK(0);
          }
        /* FIXME: Race between this and the above check */
        if (Info.State == MEM_FREE)
@@ -456,11 +508,12 @@ PsCreateTeb(HANDLE ProcessHandle,
               }
          }
             
-       TebBase = TebBase - TebSize;
+       TebBase = (char*)TebBase - TebSize;
      }
 
    DPRINT ("TebBase %p TebSize %lu\n", TebBase, TebSize);
 
+   RtlZeroMemory(&Teb, sizeof(TEB));
    /* set all pointers to and from the TEB */
    Teb.Tib.Self = TebBase;
    if (Thread->ThreadsProcess)
@@ -469,18 +522,32 @@ PsCreateTeb(HANDLE ProcessHandle,
      }
    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;
-     }
+   /* store stack information from UserStack */
+   if(UserStack != NULL)
+   {
+    /* fixed-size stack */
+    if(UserStack->FixedStackBase && UserStack->FixedStackLimit)
+    {
+     Teb.Tib.StackBase = UserStack->FixedStackBase;
+     Teb.Tib.StackLimit = UserStack->FixedStackLimit;
+     Teb.DeallocationStack = UserStack->FixedStackLimit;
+    }
+    /* expandable stack */
+    else
+    {
+     Teb.Tib.StackBase = UserStack->ExpandableStackBase;
+     Teb.Tib.StackLimit = UserStack->ExpandableStackLimit;
+     Teb.DeallocationStack = UserStack->ExpandableStackBottom;
+    }
+   }
 
    /* 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));
    
@@ -516,81 +583,120 @@ PsCreateTeb(HANDLE ProcessHandle,
 }
 
 
-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);
-     }
-   
-   Status = Ke386InitThreadWithContext(&Thread->Tcb,
-                                      ThreadContext);
-   if (!NT_SUCCESS(Status))
-     {
-       return(Status);
-     }
-   
-   Status = PsCreateTeb(ProcessHandle,
-                        &TebBase,
-                        Thread,
-                        InitialTeb);
-   if (!NT_SUCCESS(Status))
-     {
-        return(Status);
-     }
-   
-   /* Attention: TebBase is in user memory space */
-   Thread->Tcb.Teb = TebBase;
+   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);
+VOID STDCALL
+LdrInitApcKernelRoutine(PKAPC Apc,
+                       PKNORMAL_ROUTINE* NormalRoutine,
+                       PVOID* NormalContext,
+                       PVOID* SystemArgument1,
+                       PVOID* SystemArgument2)
+{
+  ExFreePool(Apc);
 }
 
 
+NTSTATUS STDCALL
+NtCreateThread(PHANDLE ThreadHandle,
+              ACCESS_MASK DesiredAccess,
+              POBJECT_ATTRIBUTES ObjectAttributes,
+              HANDLE ProcessHandle,
+              PCLIENT_ID Client,
+              PCONTEXT ThreadContext,
+              PUSER_STACK UserStack,
+              BOOLEAN CreateSuspended)
+{
+  PETHREAD Thread;
+  PTEB TebBase;
+  NTSTATUS Status;
+  PKAPC LdrInitApc;
+
+  DPRINT("NtCreateThread(ThreadHandle %x, PCONTEXT %x)\n",
+        ThreadHandle,ThreadContext);
+
+  Status = PsInitializeThread(ProcessHandle,
+                             &Thread,
+                             ThreadHandle,
+                             DesiredAccess,
+                             ObjectAttributes,
+                             FALSE);
+  if (!NT_SUCCESS(Status))
+    {
+      return(Status);
+    }
+
+  Status = KiArchInitThreadWithContext(&Thread->Tcb, ThreadContext);
+  if (!NT_SUCCESS(Status))
+    {
+      return(Status);
+    }
+
+  Status = PsCreateTeb(ProcessHandle,
+                      &TebBase,
+                      Thread,
+                      UserStack);
+  if (!NT_SUCCESS(Status))
+    {
+      return(Status);
+    }
+  Thread->Tcb.Teb = TebBase;
+
+  Thread->StartAddress = NULL;
+
+  if (Client != NULL)
+    {
+      *Client = Thread->Cid;
+    }
+
+  /*
+   * 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)
+    {
+      PsSuspendThread(Thread, NULL);
+    }
+
+  /*
+   * 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);
+
+  /*
+   * Start the thread running and force it to execute the APC(s) we just
+   * queued before it runs anything else in user-mode.
+   */
+  Thread->Tcb.Alertable = TRUE;
+  Thread->Tcb.Alerted[0] = 1;
+  PsUnblockThread(Thread, NULL);
+
+  return(STATUS_SUCCESS);
+}
+
+
+/*
+ * @implemented
+ */
 NTSTATUS STDCALL
 PsCreateSystemThread(PHANDLE ThreadHandle,
                     ACCESS_MASK DesiredAccess,
@@ -633,16 +739,14 @@ PsCreateSystemThread(PHANDLE ThreadHandle,
        return(Status);
      }
    
-   Thread->StartAddress=StartRoutine;
-   Status = Ke386InitThread(&Thread->Tcb,
-                           StartRoutine,
-                           StartContext);
+   Thread->StartAddress = StartRoutine;
+   Status = KiArchInitThread(&Thread->Tcb, StartRoutine, StartContext);
    if (!NT_SUCCESS(Status))
      {
        return(Status);
      }
 
-   if (ClientId!=NULL)
+   if (ClientId != NULL)
      {
        *ClientId=Thread->Cid;
      }
@@ -652,4 +756,36 @@ PsCreateSystemThread(PHANDLE ThreadHandle,
    return(STATUS_SUCCESS);
 }
 
+
+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 */