- Send proper ClientID structure
[reactos.git] / reactos / lib / kernel32 / thread / thread.c
index fa4f278..888a3f8 100644 (file)
@@ -1,13 +1,10 @@
-/* $Id: thread.c,v 1.54 2004/10/24 12:16:54 weiden Exp $
- *
+/*
  * 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)
 {
-  ExitThread(0);
-
-  /* We should not get to here */
-  return(ExceptionContinueSearch);
+   EXCEPTION_POINTERS * ExceptionInfo = _SEH_GetExceptionPointers();
+   LONG ExceptionDisposition = EXCEPTION_EXECUTE_HANDLER;
+
+   if (GlobalTopLevelExceptionFilter != NULL)
+   {
+      _SEH_TRY
+      {
+         ExceptionDisposition = GlobalTopLevelExceptionFilter(ExceptionInfo);
+      }
+      _SEH_HANDLE
+      {
+         ExceptionDisposition = UnhandledExceptionFilter(ExceptionInfo);
+      }
+      _SEH_END;
+   }
+
+   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
@@ -264,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,
@@ -303,9 +305,9 @@ GetTeb(VOID)
 BOOL STDCALL
 SwitchToThread(VOID)
 {
-  NTSTATUS errCode;
-  errCode = NtYieldExecution();
-  return TRUE;
+  NTSTATUS Status;
+  Status = NtYieldExecution();
+  return Status != STATUS_NO_YIELD_PERFORMED;
 }
 
 
@@ -318,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
  */
@@ -375,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;
 
@@ -674,7 +645,7 @@ GetThreadSelectorEntry(IN HANDLE hThread,
 {
   DESCRIPTOR_TABLE_ENTRY DescriptionTableEntry;
   NTSTATUS Status;
-  
+
   DescriptionTableEntry.Selector = dwSelector;
   Status = NtQueryInformationThread(hThread,
                                     ThreadDescriptorTableEntry,
@@ -714,4 +685,161 @@ SetThreadIdealProcessor(HANDLE hThread,
   return dwIdealProcessor;
 }
 
+
+/*
+ * @implemented
+ */
+DWORD STDCALL
+GetProcessIdOfThread(HANDLE Thread)
+{
+  THREAD_BASIC_INFORMATION ThreadBasic;
+  NTSTATUS Status;
+
+  Status = NtQueryInformationThread(Thread,
+                                    ThreadBasicInformation,
+                                    &ThreadBasic,
+                                    sizeof(THREAD_BASIC_INFORMATION),
+                                    NULL);
+  if(!NT_SUCCESS(Status))
+  {
+    SetLastErrorByStatus(Status);
+    return 0;
+  }
+
+  return (DWORD)ThreadBasic.ClientId.UniqueProcess;
+}
+
+
+/*
+ * @implemented
+ */
+DWORD STDCALL
+GetThreadId(HANDLE Thread)
+{
+  THREAD_BASIC_INFORMATION ThreadBasic;
+  NTSTATUS Status;
+
+  Status = NtQueryInformationThread(Thread,
+                                    ThreadBasicInformation,
+                                    &ThreadBasic,
+                                    sizeof(THREAD_BASIC_INFORMATION),
+                                    NULL);
+  if(!NT_SUCCESS(Status))
+  {
+    SetLastErrorByStatus(Status);
+    return 0;
+  }
+
+  return (DWORD)ThreadBasic.ClientId.UniqueThread;
+}
+
+/*
+ * @unimplemented
+ */
+LANGID STDCALL
+SetThreadUILanguage(WORD wReserved)
+{
+  DPRINT1("SetThreadUILanguage(0x%4x) unimplemented!\n", wReserved);
+  return 0;
+}
+
+static void CALLBACK
+IntCallUserApc(PVOID Function, PVOID dwData, PVOID Argument3)
+{
+   PAPCFUNC pfnAPC = (PAPCFUNC)Function;
+   pfnAPC((ULONG_PTR)dwData);
+}
+
+/*
+ * @implemented
+ */
+DWORD STDCALL
+QueueUserAPC(PAPCFUNC pfnAPC, HANDLE hThread, ULONG_PTR dwData)
+{
+  NTSTATUS Status;
+
+  Status = NtQueueApcThread(hThread, IntCallUserApc, pfnAPC,
+                            (PVOID)dwData, NULL);
+  if (Status)
+    SetLastErrorByStatus(Status);
+
+  return NT_SUCCESS(Status);
+}
+
+/*
+ * @implemented
+ */
+BOOL STDCALL
+GetThreadIOPendingFlag(HANDLE hThread,
+                       PBOOL lpIOIsPending)
+{
+  ULONG IoPending;
+  NTSTATUS Status;
+
+  if(lpIOIsPending == NULL)
+  {
+    SetLastError(ERROR_INVALID_PARAMETER);
+    return FALSE;
+  }
+
+  Status = NtQueryInformationThread(hThread,
+                                    ThreadIsIoPending,
+                                    (PVOID)&IoPending,
+                                    sizeof(IoPending),
+                                    NULL);
+  if(NT_SUCCESS(Status))
+  {
+    *lpIOIsPending = ((IoPending != 0) ? TRUE : FALSE);
+    return TRUE;
+  }
+
+  SetLastErrorByStatus(Status);
+  return FALSE;
+}
+
+
+/*
+ * @implemented
+ */
+VOID STDCALL
+Sleep(DWORD dwMilliseconds)
+{
+  SleepEx(dwMilliseconds, FALSE);
+  return;
+}
+
+
+/*
+ * @implemented
+ */
+DWORD STDCALL
+SleepEx(DWORD dwMilliseconds,
+       BOOL bAlertable)
+{
+  LARGE_INTEGER Interval;
+  NTSTATUS errCode;
+
+  if (dwMilliseconds != INFINITE)
+    {
+      /*
+       * System time units are 100 nanoseconds (a nanosecond is a billionth of
+       * a second).
+       */
+      Interval.QuadPart = -((ULONGLONG)dwMilliseconds * 10000);
+    }
+  else
+    {
+      /* Approximately 292000 years hence */
+      Interval.QuadPart = -0x7FFFFFFFFFFFFFFFLL;
+    }
+
+  errCode = NtDelayExecution ((bAlertable ? TRUE : FALSE), &Interval);
+  if (!NT_SUCCESS(errCode))
+    {
+      SetLastErrorByStatus (errCode);
+      return -1;
+    }
+  return 0;
+}
+
 /* EOF */