- Send proper ClientID structure
[reactos.git] / reactos / lib / kernel32 / thread / thread.c
index 0f59d8f..888a3f8 100644 (file)
@@ -1,13 +1,10 @@
-/* $Id$
- *
+/*
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS system libraries
  * FILE:            lib/kernel32/thread/thread.c
  * PURPOSE:         Thread functions
- * PROGRAMMER:      Ariadne ( ariadne@xs4all.nl)
- *                     Tls functions are modified from WINE
- * UPDATE HISTORY:
- *                  Created 01/11/98
+ * PROGRAMMERS:     Alex Ionescu (alex@relsoft.net)
+ *                  Ariadne ( ariadne@xs4all.nl)
  *
  */
 
 #define NDEBUG
 #include "../include/debug.h"
 
-
 /* FUNCTIONS *****************************************************************/
-
-/* FIXME: please put this in some header */
-static EXCEPTION_DISPOSITION __cdecl
-_except_handler(EXCEPTION_RECORD *ExceptionRecord,
-               void * EstablisherFrame,
-               CONTEXT *ContextRecord,
-               void * DispatcherContext)
+_SEH_FILTER(BaseThreadExceptionFilter)
 {
-   EXCEPTION_POINTERS ExceptionInfo;
-   EXCEPTION_DISPOSITION ExceptionDisposition;
-
-   ExceptionInfo.ExceptionRecord = ExceptionRecord;
-   ExceptionInfo.ContextRecord = ContextRecord;
+   EXCEPTION_POINTERS * ExceptionInfo = _SEH_GetExceptionPointers();
+   LONG ExceptionDisposition = EXCEPTION_EXECUTE_HANDLER;
 
    if (GlobalTopLevelExceptionFilter != NULL)
    {
       _SEH_TRY
       {
-         ExceptionDisposition = GlobalTopLevelExceptionFilter(&ExceptionInfo);
+         ExceptionDisposition = GlobalTopLevelExceptionFilter(ExceptionInfo);
       }
       _SEH_HANDLE
       {
-         ExceptionDisposition = UnhandledExceptionFilter(&ExceptionInfo);
+         ExceptionDisposition = UnhandledExceptionFilter(ExceptionInfo);
       }
       _SEH_END;
    }
-   else 
-   {
-      ExceptionDisposition = EXCEPTION_EXECUTE_HANDLER;
-   }
-
-   if (ExceptionDisposition == EXCEPTION_EXECUTE_HANDLER)
-      ExitThread(ExceptionRecord->ExceptionCode);
 
-   /* translate EXCEPTION_XXX defines into EXCEPTION_DISPOSITION enum values */
-   if (ExceptionDisposition == EXCEPTION_CONTINUE_EXECUTION)
-     return ExceptionContinueExecution;
-   else if (ExceptionDisposition == EXCEPTION_CONTINUE_SEARCH)
-     return ExceptionContinueSearch;
-
-   return -1; /* unknown return from UnhandledExceptionFilter */
+   return ExceptionDisposition;
 }
 
-
-__declspec(noreturn) void STDCALL
-ThreadStartup
-(
- LPTHREAD_START_ROUTINE lpStartAddress,
- LPVOID lpParameter
-)
+__declspec(noreturn)
+VOID
+STDCALL
+BaseThreadStartup(LPTHREAD_START_ROUTINE lpStartAddress,
+                  LPVOID lpParameter)
 {
-  volatile UINT uExitCode = 0;
+    volatile UINT uExitCode = 0;
 
-  __try1(_except_handler)
-  {
-    /* FIXME: notify csrss of thread creation ?? */
-    uExitCode = (lpStartAddress)(lpParameter);
-  }
-  __except1
-
-  ExitThread(uExitCode);
+    /* Attempt to call the Thread Start Address */
+    _SEH_TRY
+    {
+        /* Get the exit code from the Thread Start */
+        uExitCode = (lpStartAddress)((PVOID)lpParameter);
+    }
+    _SEH_EXCEPT(BaseThreadExceptionFilter)
+    {
+        /* Get the Exit code from the SEH Handler */
+        uExitCode = _SEH_GetExceptionCode();
+    } _SEH_END;
+   
+    /* Exit the Thread */
+    ExitThread(uExitCode);
 }
 
-
 /*
  * @implemented
  */
-HANDLE STDCALL
-CreateThread
-(
- LPSECURITY_ATTRIBUTES lpThreadAttributes,
- DWORD dwStackSize,
- LPTHREAD_START_ROUTINE lpStartAddress,
- LPVOID lpParameter,
- DWORD dwCreationFlags,
- LPDWORD lpThreadId
-)
+HANDLE
+STDCALL
+CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,
+             DWORD dwStackSize,
+             LPTHREAD_START_ROUTINE lpStartAddress,
+             LPVOID lpParameter,
+             DWORD dwCreationFlags,
+             LPDWORD lpThreadId)
 {
- return CreateRemoteThread
- (
-  NtCurrentProcess(),
-  lpThreadAttributes,
-  dwStackSize,
-  lpStartAddress,
-  lpParameter,
-  dwCreationFlags,
-  lpThreadId
- );
+    /* Act as if we're going to create a remote thread in ourselves */
+    return CreateRemoteThread(NtCurrentProcess(),
+                              lpThreadAttributes,
+                              dwStackSize,
+                              lpStartAddress,
+                              lpParameter,
+                              dwCreationFlags,
+                              lpThreadId);
 }
 
-
 /*
  * @implemented
  */
-HANDLE STDCALL
-CreateRemoteThread
-(
- HANDLE hProcess,
- LPSECURITY_ATTRIBUTES lpThreadAttributes,
- DWORD dwStackSize,
- LPTHREAD_START_ROUTINE lpStartAddress,
- LPVOID lpParameter,
- DWORD dwCreationFlags,
- LPDWORD lpThreadId
-)
+HANDLE
+STDCALL
+CreateRemoteThread(HANDLE hProcess,
+                   LPSECURITY_ATTRIBUTES lpThreadAttributes,
+                   DWORD dwStackSize,
+                   LPTHREAD_START_ROUTINE lpStartAddress,
+                   LPVOID lpParameter,
+                   DWORD dwCreationFlags,
+                   LPDWORD lpThreadId)
 {
- HANDLE hThread;
- CLIENT_ID cidClientId;
- NTSTATUS nErrCode;
- ULONG_PTR nStackReserve;
- ULONG_PTR nStackCommit;
- OBJECT_ATTRIBUTES oaThreadAttribs;
- PIMAGE_NT_HEADERS pinhHeader =
-  RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress);
-
- DPRINT
- (
-  "hProcess           %08X\n"
-  "lpThreadAttributes %08X\n"
-  "dwStackSize        %08X\n"
-  "lpStartAddress     %08X\n"
-  "lpParameter        %08X\n"
-  "dwCreationFlags    %08X\n"
-  "lpThreadId         %08X\n",
-  hProcess,
-  lpThreadAttributes,
-  dwStackSize,
-  lpStartAddress,
-  lpParameter,
-  dwCreationFlags,
-  lpThreadId
- );
-
- /* FIXME: do more checks - e.g. the image may not have an optional header */
- if(pinhHeader == NULL)
- {
-  nStackReserve = 0x100000;
-  nStackCommit = PAGE_SIZE;
- }
- else
- {
-  nStackReserve = pinhHeader->OptionalHeader.SizeOfStackReserve;
-  nStackCommit = pinhHeader->OptionalHeader.SizeOfStackCommit;
- }
-
- /* FIXME: this should be defined in winbase.h */
-#ifndef STACK_SIZE_PARAM_IS_A_RESERVATION
-#define STACK_SIZE_PARAM_IS_A_RESERVATION 0x00010000
-#endif
-
- /* use defaults */
- if(dwStackSize == 0);
- /* dwStackSize specifies the size to reserve */
- else if(dwCreationFlags & STACK_SIZE_PARAM_IS_A_RESERVATION)
-  nStackReserve = dwStackSize;
- /* dwStackSize specifies the size to commit */
- else
-  nStackCommit = dwStackSize;
-
- /* fix the stack reserve size */
- if(nStackCommit > nStackReserve)
-  nStackReserve = ROUNDUP(nStackCommit, 0x100000);
-
- /* initialize the attributes for the thread object */
- InitializeObjectAttributes
- (
-  &oaThreadAttribs,
-  NULL,
-  0,
-  NULL,
-  NULL
- );
- if(lpThreadAttributes)
- {
-  /* make the handle inheritable */
-  if(lpThreadAttributes->bInheritHandle)
-   oaThreadAttribs.Attributes |= OBJ_INHERIT;
-
-  /* user-defined security descriptor */
-  oaThreadAttribs.SecurityDescriptor = lpThreadAttributes->lpSecurityDescriptor;
- }
-
- DPRINT
- (
-  "RtlRosCreateUserThreadVa\n"
-  "(\n"
-  " ProcessHandle    %p,\n"
-  " ObjectAttributes %p,\n"
-  " CreateSuspended  %d,\n"
-  " StackZeroBits    %d,\n"
-  " StackReserve     %lu,\n"
-  " StackCommit      %lu,\n"
-  " StartAddress     %p,\n"
-  " ThreadHandle     %p,\n"
-  " ClientId         %p,\n"
-  " ParameterCount   %u,\n"
-  " Parameters[0]    %p,\n"
-  " Parameters[1]    %p\n"
-  ")\n",
-  hProcess,
-  &oaThreadAttribs,
-  dwCreationFlags & CREATE_SUSPENDED,
-  0,
-  nStackReserve,
-  nStackCommit,
-  ThreadStartup,
-  &hThread,
-  &cidClientId,
-  2,
-  lpStartAddress,
-  lpParameter
- );
-
- /* create the thread */
- nErrCode = RtlRosCreateUserThreadVa
- (
-  hProcess,
-  &oaThreadAttribs,
-  dwCreationFlags & CREATE_SUSPENDED,
-  0,
-  &nStackReserve,
-  &nStackCommit,
-  (PTHREAD_START_ROUTINE)ThreadStartup,
-  &hThread,
-  &cidClientId,
-  2,
-  lpStartAddress,
-  lpParameter
- );
-
- /* failure */
- if(!NT_SUCCESS(nErrCode))
- {
-  SetLastErrorByStatus(nErrCode);
-  return NULL;
- }
- DPRINT
- (
-  "StackReserve          %p\n"
-  "StackCommit           %p\n"
-  "ThreadHandle          %p\n"
-  "ClientId.UniqueThread %p\n",
-  nStackReserve,
-  nStackCommit,
-  hThread,
-  cidClientId.UniqueThread
- );
-
- /* success */
- if(lpThreadId) *lpThreadId = (DWORD)cidClientId.UniqueThread;
- return hThread;
+    NTSTATUS Status;
+    INITIAL_TEB InitialTeb;
+    CONTEXT Context;
+    CLIENT_ID ClientId;
+    OBJECT_ATTRIBUTES LocalObjectAttributes;
+    POBJECT_ATTRIBUTES ObjectAttributes;
+    HANDLE hThread;
+    ULONG Dummy;
+    
+    DPRINT("CreateRemoteThread: hProcess: %ld dwStackSize: %ld lpStartAddress"
+            ": %p lpParameter: %lx, dwCreationFlags: %lx\n", hProcess, 
+            dwStackSize, lpStartAddress, lpParameter, dwCreationFlags);
+    
+    /* Clear the Context */
+    RtlZeroMemory(&Context, sizeof(CONTEXT));
+    
+    /* Write PID */
+    ClientId.UniqueProcess = hProcess;
+    
+    /* Create the Stack */
+    Status = BasepCreateStack(hProcess,
+                              dwStackSize,
+                              dwCreationFlags & STACK_SIZE_PARAM_IS_A_RESERVATION ?
+                              dwStackSize : 0,
+                              &InitialTeb);    
+    if(!NT_SUCCESS(Status))
+    {
+        SetLastErrorByStatus(Status);
+        return NULL;
+    }
+    
+    /* Create Initial Context */
+    BasepInitializeContext(&Context,
+                           lpParameter,
+                           lpStartAddress,
+                           InitialTeb.StackBase,
+                           1);
+    
+    /* initialize the attributes for the thread object */
+    ObjectAttributes = BasepConvertObjectAttributes(&LocalObjectAttributes,
+                                                    lpThreadAttributes,
+                                                    NULL);
+    
+    /* Create the Kernel Thread Object */
+    Status = NtCreateThread(&hThread,
+                            THREAD_ALL_ACCESS,
+                            ObjectAttributes,
+                            hProcess,
+                            &ClientId,
+                            &Context,
+                            &InitialTeb,
+                            TRUE);
+    if(!NT_SUCCESS(Status))
+    {
+        BasepFreeStack(hProcess, &InitialTeb);
+        SetLastErrorByStatus(Status);
+        return NULL;
+    }
+    
+    #ifdef SXS_SUPPORT_ENABLED
+    /* Are we in the same process? */
+    if (Process = NtCurrentProcess())
+    {
+        PTEB Teb;
+        PVOID ActivationContextStack;
+        PTHREAD_BASIC_INFORMATION ThreadBasicInfo;
+        PACTIVATION_CONTEXT_BASIC_INFORMATION ActivationCtxInfo;
+        ULONG_PTR Cookie;
+        
+        /* Get the TEB */
+        Status = NtQueryInformationThread(hThread,
+                                          ThreadBasicIformation,
+                                          &ThreadBasicInfo,
+                                          sizeof(ThreadBasicInfo),
+                                          NULL);
+                                          
+        /* Allocate the Activation Context Stack */
+        Status = RtlAllocateActivationContextStack(&ActivationContextStack);
+        Teb = ThreadBasicInfo.TebBaseAddress;
+        
+        /* Save it */
+        Teb->ActivationContextStackPointer = ActivationContextStack;
+        
+        /* Query the Context */
+        Status = RtlQueryInformationActivationContext(1,
+                                                      0,
+                                                      NULL,
+                                                      ActivationContextBasicInformation,
+                                                      &ActivationCtxInfo,
+                                                      sizeof(ActivationCtxInfo),
+                                                      NULL);
+                                                      
+        /* Does it need to be activated? */
+        if (!ActivationCtxInfo.hActCtx)
+        {
+            /* Activate it */
+            Status = RtlActivateActivationContextEx(1,
+                                                    Teb,
+                                                    ActivationCtxInfo.hActCtx,
+                                                    &Cookie);
+        }
+    }
+    #endif
+    
+    /* FIXME: Notify CSR */
+
+    /* Success */
+    if(lpThreadId) *lpThreadId = (DWORD)ClientId.UniqueThread;
+    
+    /* Resume it if asked */
+    if (!(dwCreationFlags & CREATE_SUSPENDED))
+    {
+        NtResumeThread(hThread, &Dummy);
+    }
+    
+    /* Return handle to thread */
+    return hThread;
 }
 
+/*
+ * @implemented
+ */
+VOID
+STDCALL
+ExitThread(DWORD uExitCode)
+{
+    NTSTATUS Status;
+    BOOLEAN LastThread;
+    
+    /*
+     * Terminate process if this is the last thread
+     * of the current process
+     */
+    Status = NtQueryInformationThread(NtCurrentThread(),
+                                      ThreadAmILastThread,
+                                      &LastThread,
+                                      sizeof(BOOLEAN),
+                                      NULL);
+    if (NT_SUCCESS(Status) && LastThread)
+    {
+        /* Exit the Process */
+        ExitProcess(uExitCode);
+    }
+
+    /* Notify DLLs and TLS Callbacks of termination */
+    LdrShutdownThread();
+    
+    /* Tell the Kernel to free the Stack */
+    NtCurrentTeb()->FreeStackOnTermination = TRUE;
+    NtTerminateThread(NULL, uExitCode);
+    
+    /* We will never reach this place. This silences the compiler */
+    ExitThread(uExitCode);
+}
 
 /*
  * @implemented
@@ -291,16 +266,16 @@ OpenThread(
    HANDLE ThreadHandle;
    OBJECT_ATTRIBUTES ObjectAttributes;
    CLIENT_ID ClientId ;
-   
-   ClientId.UniqueProcess = INVALID_HANDLE_VALUE;
+
+   ClientId.UniqueProcess = 0;
    ClientId.UniqueThread = (HANDLE)dwThreadId;
-   
+
    InitializeObjectAttributes (&ObjectAttributes,
                              NULL,
                              (bInheritHandle ? OBJ_INHERIT : 0),
                              NULL,
                              NULL);
-   
+
    errCode = NtOpenThread(&ThreadHandle,
                           dwDesiredAccess,
                           &ObjectAttributes,
@@ -345,37 +320,6 @@ GetCurrentThreadId(VOID)
   return((DWORD)(NtCurrentTeb()->Cid).UniqueThread);
 }
 
-/*
- * @implemented
- */
-VOID STDCALL
-ExitThread(DWORD uExitCode)
-{
-  NTSTATUS Status;
-  BOOLEAN LastThread;
-
-  /*
-   * Terminate process if this is the last thread
-   * of the current process
-   */
-  Status = NtQueryInformationThread(NtCurrentThread(),
-                                   ThreadAmILastThread,
-                                   &LastThread,
-                                   sizeof(BOOLEAN),
-                                   NULL);
-  if (NT_SUCCESS(Status) && LastThread == TRUE)
-    {
-      ExitProcess(uExitCode);
-    }
-
-  /* FIXME: notify csrss of thread termination */
-
-  LdrShutdownThread();
-
-  RtlRosExitUserThread(uExitCode);
-}
-
-
 /*
  * @implemented
  */
@@ -402,13 +346,13 @@ GetThreadTimes(HANDLE hThread,
 
   lpCreationTime->dwLowDateTime = KernelUserTimes.CreateTime.u.LowPart;
   lpCreationTime->dwHighDateTime = KernelUserTimes.CreateTime.u.HighPart;
-  
+
   lpExitTime->dwLowDateTime = KernelUserTimes.ExitTime.u.LowPart;
   lpExitTime->dwHighDateTime = KernelUserTimes.ExitTime.u.HighPart;
-  
+
   lpKernelTime->dwLowDateTime = KernelUserTimes.KernelTime.u.LowPart;
   lpKernelTime->dwHighDateTime = KernelUserTimes.KernelTime.u.HighPart;
-  
+
   lpUserTime->dwLowDateTime = KernelUserTimes.UserTime.u.LowPart;
   lpUserTime->dwHighDateTime = KernelUserTimes.UserTime.u.HighPart;
 
@@ -701,7 +645,7 @@ GetThreadSelectorEntry(IN HANDLE hThread,
 {
   DESCRIPTOR_TABLE_ENTRY DescriptionTableEntry;
   NTSTATUS Status;
-  
+
   DescriptionTableEntry.Selector = dwSelector;
   Status = NtQueryInformationThread(hThread,
                                     ThreadDescriptorTableEntry,
@@ -792,10 +736,11 @@ GetThreadId(HANDLE Thread)
 /*
  * @unimplemented
  */
-VOID STDCALL
-SetThreadUILanguage(DWORD Unknown1)
+LANGID STDCALL
+SetThreadUILanguage(WORD wReserved)
 {
-  DPRINT1("SetThreadUILanguage(0x%x) unimplemented!\n", Unknown1);
+  DPRINT1("SetThreadUILanguage(0x%4x) unimplemented!\n", wReserved);
+  return 0;
 }
 
 static void CALLBACK
@@ -830,13 +775,13 @@ GetThreadIOPendingFlag(HANDLE hThread,
 {
   ULONG IoPending;
   NTSTATUS Status;
-  
+
   if(lpIOIsPending == NULL)
   {
     SetLastError(ERROR_INVALID_PARAMETER);
     return FALSE;
   }
-  
+
   Status = NtQueryInformationThread(hThread,
                                     ThreadIsIoPending,
                                     (PVOID)&IoPending,
@@ -847,7 +792,7 @@ GetThreadIOPendingFlag(HANDLE hThread,
     *lpIOIsPending = ((IoPending != 0) ? TRUE : FALSE);
     return TRUE;
   }
-  
+
   SetLastErrorByStatus(Status);
   return FALSE;
 }