branch update for HEAD-2003050101
[reactos.git] / lib / ntdll / rtl / thread.c
index 0bd496c..fc39ff3 100644 (file)
  * REVISION HISTORY:
  *                    09/07/99: Created
  *                    09/10/99: Cleanup and full stack support.
+ *                    25/04/03: Near rewrite. Made code more readable, replaced
+ *                              INITIAL_TEB with USER_STACK, added support for
+ *                              fixed-size stacks
+ *                    28/04/03: Moved all code to a new statically linked
+ *                              library (ROSRTL) so it can be shared with
+ *                              kernel32.dll without exporting non-standard
+ *                              functions from ntdll.dll
  */
 
 /* INCLUDES *****************************************************************/
 
 #include <ddk/ntddk.h>
-#include <napi/i386/segment.h>
 #include <napi/teb.h>
 #include <ntdll/rtl.h>
+#include <rosrtl/thread.h>
 
 #define NDEBUG
 #include <ntdll/ntdll.h>
 
-
 /* FUNCTIONS ***************************************************************/
 
-
-NTSTATUS STDCALL
-RtlCreateUserThread(HANDLE ProcessHandle,
-                    PSECURITY_DESCRIPTOR SecurityDescriptor,
-                    BOOLEAN CreateSuspended,
-                    LONG StackZeroBits,
-                    PULONG StackReserve,
-                    PULONG StackCommit,
-                    PTHREAD_START_ROUTINE StartAddress,
-                    PVOID   Parameter,
-                    PHANDLE ThreadHandle,
-                    PCLIENT_ID ClientId)
+NTSTATUS STDCALL RtlCreateUserThread
+(
+ HANDLE ProcessHandle,
+ PSECURITY_DESCRIPTOR SecurityDescriptor,
+ BOOLEAN CreateSuspended,
+ LONG StackZeroBits,
+ PULONG StackReserve,
+ PULONG StackCommit,
+ PTHREAD_START_ROUTINE StartAddress,
+ PVOID Parameter,
+ PHANDLE ThreadHandle,
+ PCLIENT_ID ClientId
+)
 {
-  HANDLE LocalThreadHandle;
-  CLIENT_ID LocalClientId;
-  OBJECT_ATTRIBUTES ObjectAttributes;
-  INITIAL_TEB InitialTeb;
-  CONTEXT ThreadContext;
-  ULONG OldPageProtection;
-  NTSTATUS Status;
-
-  /* initialize initial teb */
-  if ((StackReserve != NULL) && (*StackReserve > 0x100000))
-    InitialTeb.StackReserve = *StackReserve;
-  else
-    InitialTeb.StackReserve = 0x100000; /* 1MByte */
-
-  /* FIXME: use correct commit size */
-#if 0
-  if ((StackCommit != NULL) && (*StackCommit > PAGE_SIZE))
-    InitialTeb.StackCommit = *StackCommit;
-  else
-    InitialTeb.StackCommit = PAGE_SIZE;
-#endif
-  InitialTeb.StackCommit = InitialTeb.StackReserve - PAGE_SIZE;
-
-  /* add size of guard page */
-  InitialTeb.StackCommit += PAGE_SIZE;
-
-  /* Reserve stack */
-  InitialTeb.StackAllocate = NULL;
-  Status = NtAllocateVirtualMemory(ProcessHandle,
-                                  &InitialTeb.StackAllocate,
-                                  0,
-                                  &InitialTeb.StackReserve,
-                                  MEM_RESERVE,
-                                  PAGE_READWRITE);
-  if (!NT_SUCCESS(Status))
-    {
-      DPRINT("Error reserving stack space!\n");
-      return(Status);
-    }
-
-  DPRINT("StackAllocate: %p ReserveSize: 0x%lX\n",
-        InitialTeb.StackAllocate, InitialTeb.StackReserve);
-
-  InitialTeb.StackBase = (PVOID)((ULONG)InitialTeb.StackAllocate + InitialTeb.StackReserve);
-  InitialTeb.StackLimit = (PVOID)((ULONG)InitialTeb.StackBase - InitialTeb.StackCommit);
-
-  DPRINT("StackBase: %p  StackCommit: 0x%lX\n",
-        InitialTeb.StackBase, InitialTeb.StackCommit);
-
-  /* Commit stack */
-  Status = NtAllocateVirtualMemory(ProcessHandle,
-                                  &InitialTeb.StackLimit,
-                                  0,
-                                  &InitialTeb.StackCommit,
-                                  MEM_COMMIT,
-                                  PAGE_READWRITE);
-  if (!NT_SUCCESS(Status))
-    {
-      /* release the stack space */
-      NtFreeVirtualMemory(ProcessHandle,
-                         InitialTeb.StackAllocate,
-                         &InitialTeb.StackReserve,
-                         MEM_RELEASE);
-
-      DPRINT("Error comitting stack page!\n");
-      return(Status);
-    }
-
-  DPRINT("StackLimit: %p\nStackCommit: 0x%lX\n",
-         InitialTeb.StackLimit,
-         InitialTeb.StackCommit);
-
-  /* Protect guard page */
-  Status = NtProtectVirtualMemory(ProcessHandle,
-                                 InitialTeb.StackLimit,
-                                 PAGE_SIZE,
-                                 PAGE_GUARD | PAGE_READWRITE,
-                                 &OldPageProtection);
-  if (!NT_SUCCESS(Status))
-    {
-      /* release the stack space */
-      NtFreeVirtualMemory(ProcessHandle,
-                         InitialTeb.StackAllocate,
-                         &InitialTeb.StackReserve,
-                         MEM_RELEASE);
-
-      DPRINT("Error protecting guard page!\n");
-      return(Status);
-    }
-
-  /* initialize thread context */
-  RtlInitializeContext(ProcessHandle,
-                      &ThreadContext,
-                      Parameter,
-                      StartAddress,
-                      &InitialTeb);
-
-  /* create the thread */
-  ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES);
-  ObjectAttributes.RootDirectory = NULL;
-  ObjectAttributes.ObjectName = NULL;
-  ObjectAttributes.Attributes = OBJ_INHERIT;
-  ObjectAttributes.SecurityDescriptor = SecurityDescriptor;
-  ObjectAttributes.SecurityQualityOfService = NULL;
-
-  Status = NtCreateThread(&LocalThreadHandle,
-                         THREAD_ALL_ACCESS,
-                         &ObjectAttributes,
-                         ProcessHandle,
-                         &LocalClientId,
-                         &ThreadContext,
-                         &InitialTeb,
-                         CreateSuspended);
-  if (!NT_SUCCESS(Status))
-    {
-      /* release the stack space */
-      NtFreeVirtualMemory(ProcessHandle,
-                         InitialTeb.StackAllocate,
-                         &InitialTeb.StackReserve,
-                         MEM_RELEASE);
-
-      DPRINT("Error creating thread!\n");
-      return(Status);
-    }
-
-  /* return committed stack size */
-  if (StackCommit)
-    *StackCommit = InitialTeb.StackCommit;
-
-  /* return reserved stack size */
-  if (StackReserve)
-    *StackReserve = InitialTeb.StackReserve;
-
-  /* return thread handle */
-  if (ThreadHandle)
-    *ThreadHandle = LocalThreadHandle;
-
-  /* return client id */
-  if (ClientId)
-    {
-      ClientId->UniqueProcess = LocalClientId.UniqueProcess;
-      ClientId->UniqueThread  = LocalClientId.UniqueThread;
-    }
-
-  return(STATUS_SUCCESS);
+ OBJECT_ATTRIBUTES oaThreadAttribs;
+ InitializeObjectAttributes
+ (
+  &oaThreadAttribs,
+  NULL,
+  0,
+  NULL,
+  SecurityDescriptor
+ );
+ return RtlRosCreateUserThreadEx
+ (
+  ProcessHandle,
+  &oaThreadAttribs,
+  CreateSuspended,
+  StackZeroBits,
+  StackReserve,
+  StackCommit,
+  StartAddress,
+  ThreadHandle,
+  ClientId,
+  1,
+  (ULONG_PTR *)&Parameter
+ );
 }
 
-
-NTSTATUS STDCALL
-RtlInitializeContext(HANDLE ProcessHandle,
-                     PCONTEXT Context,
-                     PVOID Parameter,
-                     PTHREAD_START_ROUTINE StartAddress,
-                     PINITIAL_TEB InitialTeb)
+NTSTATUS STDCALL RtlInitializeContext
+(
+ HANDLE ProcessHandle,
+ PCONTEXT Context,
+ PVOID Parameter,
+ PTHREAD_START_ROUTINE StartAddress,
+ PUSER_STACK UserStack
+)
 {
-    ULONG Buffer[2];
-    ULONG BytesWritten;
-    NTSTATUS Status;
-
-    memset (Context, 0, sizeof(CONTEXT));
-    Context->Eip = (LONG)StartAddress;
-    Context->SegGs = USER_DS;
-    Context->SegFs = TEB_SELECTOR;
-    Context->SegEs = USER_DS;
-    Context->SegDs = USER_DS;
-    Context->SegCs = USER_CS;
-    Context->SegSs = USER_DS;
-    Context->Esp = (ULONG)InitialTeb->StackBase - 8;
-    Context->EFlags = (1<<1) + (1<<9);
-
-    /* prepare the thread stack for execution */
-    if (ProcessHandle == NtCurrentProcess())
-    {
-        *((PULONG)(InitialTeb->StackBase - 4)) = (ULONG)Parameter;
-        *((PULONG)(InitialTeb->StackBase - 8)) = 0xdeadbeef;
-    }
-    else
-    {
-        Buffer[0] = (ULONG)Parameter;
-        Buffer[1] = 0xdeadbeef;
-        
-        Status = NtWriteVirtualMemory(ProcessHandle,
-                                      (PVOID)((ULONG)InitialTeb->StackBase - 8),
-                                      Buffer,
-                                      2 * sizeof(ULONG),
-                                      &BytesWritten);
-        return Status;
-    }
-
-    return STATUS_SUCCESS;
+ return RtlRosInitializeContextEx
+ (
+  ProcessHandle,
+  Context,
+  StartAddress,
+  UserStack,
+  1,
+  (ULONG_PTR *)&Parameter
+ );
 }
 
-
-NTSTATUS STDCALL
-RtlFreeUserThreadStack(HANDLE ProcessHandle,
-                      HANDLE ThreadHandle)
+NTSTATUS STDCALL RtlFreeUserThreadStack
+(
+ HANDLE ProcessHandle,
+ HANDLE ThreadHandle
+)
 {
-  THREAD_BASIC_INFORMATION ThreadInfo;
-  NTSTATUS Status;
-  ULONG BytesRead;
-  ULONG RegionSize;
-  PVOID StackBase;
-  PTEB Teb;
-
-  Status = NtQueryInformationThread(ThreadHandle,
-                                   ThreadBasicInformation,
-                                   &ThreadInfo,
-                                   sizeof(THREAD_BASIC_INFORMATION),
-                                   NULL);
-  if (!NT_SUCCESS(Status))
-    return(Status);
-
-  if (ThreadInfo.TebBaseAddress == NULL)
-    return(Status);
-
-  Teb = (PTEB)ThreadInfo.TebBaseAddress;
-  Status = NtReadVirtualMemory(ProcessHandle,
-                              &Teb->DeallocationStack,
-                              &StackBase,
-                              sizeof(PVOID),
-                              &BytesRead);
-  if (!NT_SUCCESS(Status))
-    return(Status);
-
-  if (StackBase == NULL)
-    return(Status);
+ THREAD_BASIC_INFORMATION tbiInfo;
+ NTSTATUS nErrCode;
+ ULONG nDummy;
+ ULONG nSize = 0;
+ PVOID pStackBase;
+ PTEB pTeb;
+
+ /* query basic information about the thread */
+ nErrCode = NtQueryInformationThread
+ (
+  ThreadHandle,
+  ThreadBasicInformation,
+  &tbiInfo,
+  sizeof(tbiInfo),
+  NULL
+ );
+
+ /* failure */
+ if(!NT_SUCCESS(nErrCode)) return nErrCode;
+ if(tbiInfo.TebBaseAddress == NULL) return STATUS_ACCESS_VIOLATION;
+
+ pTeb = (PTEB)tbiInfo.TebBaseAddress;
+
+ /* read the base address of the stack to be deallocated */
+ nErrCode = NtReadVirtualMemory
+ (
+  ProcessHandle,
+  &pTeb->DeallocationStack,
+  &pStackBase,
+  sizeof(pStackBase),
+  &nDummy
+ );
+
+ /* failure */
+ if(!NT_SUCCESS(nErrCode)) return nErrCode;
+ if(pStackBase == NULL) return STATUS_ACCESS_VIOLATION;
+
+ /* deallocate the stack */
+ nErrCode = NtFreeVirtualMemory(ProcessHandle, pStackBase, &nSize, MEM_RELEASE);
+
+ return nErrCode;
+}
 
-  RegionSize = 0;
-  Status = NtFreeVirtualMemory(ProcessHandle,
-                              StackBase,
-                              &RegionSize,
-                              MEM_RELEASE);
-  return(Status);
+NTSTATUS STDCALL RtlExitUserThread(NTSTATUS nErrCode)
+{
+ return NtTerminateThread(NtCurrentThread(), nErrCode);
 }
 
 /* EOF */