- Send proper ClientID structure
[reactos.git] / reactos / lib / kernel32 / thread / thread.c
index 1167b5a..888a3f8 100644 (file)
@@ -1,13 +1,11 @@
-/* $Id: thread.c,v 1.34 2003/01/22 02:24:36 ekohl 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)
+ *
  */
 
 /* INCLUDES ******************************************************************/
 #include <k32.h>
 
 #define NDEBUG
-#include <kernel32/kernel32.h>
-
-
-//static VOID ThreadAttachDlls (VOID);
+#include "../include/debug.h"
 
 /* FUNCTIONS *****************************************************************/
-
-static EXCEPTION_DISPOSITION __cdecl
-_except_handler(struct _EXCEPTION_RECORD *ExceptionRecord,
-               void * EstablisherFrame,
-               struct _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;
 }
 
-
-static VOID STDCALL
-ThreadStartup(LPTHREAD_START_ROUTINE lpStartAddress,
-             LPVOID lpParameter)
+__declspec(noreturn)
+VOID
+STDCALL
+BaseThreadStartup(LPTHREAD_START_ROUTINE lpStartAddress,
+                  LPVOID lpParameter)
 {
-  UINT uExitCode;
+    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);
 }
 
-
-HANDLE STDCALL
+/*
+ * @implemented
+ */
+HANDLE
+STDCALL
 CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,
-            DWORD dwStackSize,
-            LPTHREAD_START_ROUTINE lpStartAddress,
-            LPVOID lpParameter,
-            DWORD dwCreationFlags,
-            LPDWORD lpThreadId)
+             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);
 }
 
-
-HANDLE STDCALL
+/*
+ * @implemented
+ */
+HANDLE
+STDCALL
 CreateRemoteThread(HANDLE hProcess,
-                  LPSECURITY_ATTRIBUTES lpThreadAttributes,
-                  DWORD dwStackSize,
-                  LPTHREAD_START_ROUTINE lpStartAddress,
-                  LPVOID lpParameter,
-                  DWORD dwCreationFlags,
-                  LPDWORD lpThreadId)
+                   LPSECURITY_ATTRIBUTES lpThreadAttributes,
+                   DWORD dwStackSize,
+                   LPTHREAD_START_ROUTINE lpStartAddress,
+                   LPVOID lpParameter,
+                   DWORD dwCreationFlags,
+                   LPDWORD lpThreadId)
 {
-  HANDLE ThreadHandle;
-  OBJECT_ATTRIBUTES ObjectAttributes;
-  CLIENT_ID ClientId;
-  CONTEXT ThreadContext;
-  INITIAL_TEB InitialTeb;
-  BOOLEAN CreateSuspended = FALSE;
-  PVOID BaseAddress;
-  ULONG OldPageProtection;
-  NTSTATUS Status;
-
-  ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES);
-  ObjectAttributes.RootDirectory = NULL;
-  ObjectAttributes.ObjectName = NULL;
-  ObjectAttributes.Attributes = 0;
-  if (lpThreadAttributes != NULL)
+    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))
     {
-      if (lpThreadAttributes->bInheritHandle)
-       ObjectAttributes.Attributes = OBJ_INHERIT;
-      ObjectAttributes.SecurityDescriptor = 
-       lpThreadAttributes->lpSecurityDescriptor;
+        SetLastErrorByStatus(Status);
+        return NULL;
     }
-  ObjectAttributes.SecurityQualityOfService = NULL;
-
-  if ((dwCreationFlags & CREATE_SUSPENDED) == CREATE_SUSPENDED)
-    CreateSuspended = TRUE;
-  else
-    CreateSuspended = FALSE;
-
-  InitialTeb.StackReserve = 0x100000; /* 1MByte */
-  /* FIXME: use correct commit size */
-#if 0
-  InitialTeb.StackCommit = (dwStackSize == 0) ? PAGE_SIZE : dwStackSize;
-#endif
-  InitialTeb.StackCommit = InitialTeb.StackReserve - PAGE_SIZE;
-
-  /* size of guard page */
-  InitialTeb.StackCommit += PAGE_SIZE;
-
-  /* Reserve stack */
-  InitialTeb.StackAllocate = NULL;
-  Status = NtAllocateVirtualMemory(hProcess,
-                                  &InitialTeb.StackAllocate,
-                                  0,
-                                  &InitialTeb.StackReserve,
-                                  MEM_RESERVE,
-                                  PAGE_READWRITE);
-  if (!NT_SUCCESS(Status))
+    
+    /* 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))
     {
-      DPRINT("Error reserving stack space!\n");
-      SetLastErrorByStatus(Status);
-      return(NULL);
+        BasepFreeStack(hProcess, &InitialTeb);
+        SetLastErrorByStatus(Status);
+        return NULL;
     }
-
-  DPRINT("StackDeallocation: %p ReserveSize: 0x%lX\n",
-        InitialTeb.StackDeallocation, InitialTeb.StackReserve);
-
-  InitialTeb.StackBase = (PVOID)((ULONG)InitialTeb.StackAllocate + InitialTeb.StackReserve);
-  InitialTeb.StackLimit = (PVOID)((ULONG)InitialTeb.StackBase - InitialTeb.StackCommit);
-
-  DPRINT("StackBase: %p\nStackCommit: 0x%lX\n",
-        InitialTeb.StackBase,
-        InitialTeb.StackCommit);
-
-  /* Commit stack pages */
-  Status = NtAllocateVirtualMemory(hProcess,
-                                  &InitialTeb.StackLimit,
-                                  0,
-                                  &InitialTeb.StackCommit,
-                                  MEM_COMMIT,
-                                  PAGE_READWRITE);
-  if (!NT_SUCCESS(Status))
+    
+    #ifdef SXS_SUPPORT_ENABLED
+    /* Are we in the same process? */
+    if (Process = NtCurrentProcess())
     {
-      /* release the stack space */
-      NtFreeVirtualMemory(hProcess,
-                         InitialTeb.StackAllocate,
-                         &InitialTeb.StackReserve,
-                         MEM_RELEASE);
-
-      DPRINT("Error comitting stack page(s)!\n");
-      SetLastErrorByStatus(Status);
-      return(NULL);
+        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);
+        }
     }
-
-  DPRINT("StackLimit: %p\n",
-        InitialTeb.StackLimit);
-
-  /* Protect guard page */
-  Status = NtProtectVirtualMemory(hProcess,
-                                 InitialTeb.StackLimit,
-                                 PAGE_SIZE,
-                                 PAGE_GUARD | PAGE_READWRITE,
-                                 &OldPageProtection);
-  if (!NT_SUCCESS(Status))
+    #endif
+    
+    /* FIXME: Notify CSR */
+
+    /* Success */
+    if(lpThreadId) *lpThreadId = (DWORD)ClientId.UniqueThread;
+    
+    /* Resume it if asked */
+    if (!(dwCreationFlags & CREATE_SUSPENDED))
     {
-      /* release the stack space */
-      NtFreeVirtualMemory(hProcess,
-                         InitialTeb.StackAllocate,
-                         &InitialTeb.StackReserve,
-                         MEM_RELEASE);
-
-      DPRINT("Error comitting guard page!\n");
-      SetLastErrorByStatus(Status);
-      return(NULL);
+        NtResumeThread(hThread, &Dummy);
     }
+    
+    /* Return handle to thread */
+    return hThread;
+}
 
-  memset(&ThreadContext,0,sizeof(CONTEXT));
-  ThreadContext.Eip = (LONG)ThreadStartup;
-  ThreadContext.SegGs = USER_DS;
-  ThreadContext.SegFs = TEB_SELECTOR;
-  ThreadContext.SegEs = USER_DS;
-  ThreadContext.SegDs = USER_DS;
-  ThreadContext.SegCs = USER_CS;
-  ThreadContext.SegSs = USER_DS;
-  ThreadContext.Esp = (ULONG)InitialTeb.StackBase - 12;
-  ThreadContext.EFlags = (1<<1) + (1<<9);
-
-  /* initialize call stack */
-  *((PULONG)((ULONG)InitialTeb.StackBase - 4)) = (ULONG)lpParameter;
-  *((PULONG)((ULONG)InitialTeb.StackBase - 8)) = (ULONG)lpStartAddress;
-  *((PULONG)((ULONG)InitialTeb.StackBase - 12)) = 0xdeadbeef;
-
-  DPRINT("Esp: %p\n", ThreadContext.Esp);
-  DPRINT("Eip: %p\n", ThreadContext.Eip);
-
-  Status = NtCreateThread(&ThreadHandle,
-                         THREAD_ALL_ACCESS,
-                         &ObjectAttributes,
-                         hProcess,
-                         &ClientId,
-                         &ThreadContext,
-                         &InitialTeb,
-                         CreateSuspended);
-  if (!NT_SUCCESS(Status))
+/*
+ * @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)
     {
-      NtFreeVirtualMemory(hProcess,
-                         InitialTeb.StackAllocate,
-                         &InitialTeb.StackReserve,
-                         MEM_RELEASE);
-
-      DPRINT("NtCreateThread() failed!\n");
-      SetLastErrorByStatus(Status);
-      return(NULL);
+        /* Exit the Process */
+        ExitProcess(uExitCode);
     }
 
-  if (lpThreadId != NULL)
-    memcpy(lpThreadId, &ClientId.UniqueThread,sizeof(ULONG));
+    /* 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);
+}
 
-  return(ThreadHandle);
+/*
+ * @implemented
+ */
+HANDLE
+STDCALL
+OpenThread(
+    DWORD dwDesiredAccess,
+    BOOL bInheritHandle,
+    DWORD dwThreadId
+    )
+{
+   NTSTATUS errCode;
+   HANDLE ThreadHandle;
+   OBJECT_ATTRIBUTES ObjectAttributes;
+   CLIENT_ID ClientId ;
+
+   ClientId.UniqueProcess = 0;
+   ClientId.UniqueThread = (HANDLE)dwThreadId;
+
+   InitializeObjectAttributes (&ObjectAttributes,
+                             NULL,
+                             (bInheritHandle ? OBJ_INHERIT : 0),
+                             NULL,
+                             NULL);
+
+   errCode = NtOpenThread(&ThreadHandle,
+                          dwDesiredAccess,
+                          &ObjectAttributes,
+                          &ClientId);
+   if (!NT_SUCCESS(errCode))
+     {
+       SetLastErrorByStatus (errCode);
+       return NULL;
+     }
+   return ThreadHandle;
 }
 
 
+/*
+ * @implemented
+ */
 PTEB
 GetTeb(VOID)
 {
@@ -239,56 +299,31 @@ GetTeb(VOID)
 }
 
 
-WINBOOL STDCALL
+/*
+ * @implemented
+ */
+BOOL STDCALL
 SwitchToThread(VOID)
 {
-  NTSTATUS errCode;
-  errCode = NtYieldExecution();
-  return TRUE;
+  NTSTATUS Status;
+  Status = NtYieldExecution();
+  return Status != STATUS_NO_YIELD_PERFORMED;
 }
 
 
+/*
+ * @implemented
+ */
 DWORD STDCALL
 GetCurrentThreadId(VOID)
 {
   return((DWORD)(NtCurrentTeb()->Cid).UniqueThread);
 }
 
-
-VOID STDCALL
-ExitThread(DWORD uExitCode)
-{
-  BOOLEAN LastThread;
-  NTSTATUS Status;
-
-  /*
-   * 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();
-
-  Status = NtTerminateThread(NtCurrentThread(),
-                            uExitCode);
-  if (!NT_SUCCESS(Status))
-    {
-      SetLastErrorByStatus(Status);
-    }
-}
-
-
-WINBOOL STDCALL
+/*
+ * @implemented
+ */
+BOOL STDCALL
 GetThreadTimes(HANDLE hThread,
               LPFILETIME lpCreationTime,
               LPFILETIME lpExitTime,
@@ -296,30 +331,39 @@ GetThreadTimes(HANDLE hThread,
               LPFILETIME lpUserTime)
 {
   KERNEL_USER_TIMES KernelUserTimes;
-  ULONG ReturnLength;
   NTSTATUS Status;
 
   Status = NtQueryInformationThread(hThread,
                                    ThreadTimes,
                                    &KernelUserTimes,
                                    sizeof(KERNEL_USER_TIMES),
-                                   &ReturnLength);
+                                   NULL);
   if (!NT_SUCCESS(Status))
     {
       SetLastErrorByStatus(Status);
       return(FALSE);
     }
 
-  memcpy(lpCreationTime, &KernelUserTimes.CreateTime, sizeof(FILETIME));
-  memcpy(lpExitTime, &KernelUserTimes.ExitTime, sizeof(FILETIME));
-  memcpy(lpKernelTime, &KernelUserTimes.KernelTime, sizeof(FILETIME));
-  memcpy(lpUserTime, &KernelUserTimes.UserTime, sizeof(FILETIME));
+  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;
 
   return(TRUE);
 }
 
 
-WINBOOL STDCALL
+/*
+ * @implemented
+ */
+BOOL STDCALL
 GetThreadContext(HANDLE hThread,
                 LPCONTEXT lpContext)
 {
@@ -337,7 +381,10 @@ GetThreadContext(HANDLE hThread,
 }
 
 
-WINBOOL STDCALL
+/*
+ * @implemented
+ */
+BOOL STDCALL
 SetThreadContext(HANDLE hThread,
                 CONST CONTEXT *lpContext)
 {
@@ -355,19 +402,21 @@ SetThreadContext(HANDLE hThread,
 }
 
 
-WINBOOL STDCALL
+/*
+ * @implemented
+ */
+BOOL STDCALL
 GetExitCodeThread(HANDLE hThread,
                  LPDWORD lpExitCode)
 {
   THREAD_BASIC_INFORMATION ThreadBasic;
-  ULONG DataWritten;
   NTSTATUS Status;
 
   Status = NtQueryInformationThread(hThread,
                                    ThreadBasicInformation,
                                    &ThreadBasic,
                                    sizeof(THREAD_BASIC_INFORMATION),
-                                   &DataWritten);
+                                   NULL);
   if (!NT_SUCCESS(Status))
     {
       SetLastErrorByStatus(Status);
@@ -380,6 +429,9 @@ GetExitCodeThread(HANDLE hThread,
 }
 
 
+/*
+ * @implemented
+ */
 DWORD STDCALL
 ResumeThread(HANDLE hThread)
 {
@@ -398,7 +450,10 @@ ResumeThread(HANDLE hThread)
 }
 
 
-WINBOOL STDCALL
+/*
+ * @implemented
+ */
+BOOL STDCALL
 TerminateThread(HANDLE hThread,
                DWORD dwExitCode)
 {
@@ -422,6 +477,9 @@ TerminateThread(HANDLE hThread,
 }
 
 
+/*
+ * @implemented
+ */
 DWORD STDCALL
 SuspendThread(HANDLE hThread)
 {
@@ -440,13 +498,15 @@ SuspendThread(HANDLE hThread)
 }
 
 
+/*
+ * @implemented
+ */
 DWORD STDCALL
 SetThreadAffinityMask(HANDLE hThread,
                      DWORD dwThreadAffinityMask)
 {
   THREAD_BASIC_INFORMATION ThreadBasic;
   KAFFINITY AffinityMask;
-  ULONG DataWritten;
   NTSTATUS Status;
 
   AffinityMask = (KAFFINITY)dwThreadAffinityMask;
@@ -455,7 +515,7 @@ SetThreadAffinityMask(HANDLE hThread,
                                    ThreadBasicInformation,
                                    &ThreadBasic,
                                    sizeof(THREAD_BASIC_INFORMATION),
-                                   &DataWritten);
+                                   NULL);
   if (!NT_SUCCESS(Status))
     {
       SetLastErrorByStatus(Status);
@@ -473,31 +533,21 @@ SetThreadAffinityMask(HANDLE hThread,
 }
 
 
-WINBOOL STDCALL
+/*
+ * @implemented
+ */
+BOOL STDCALL
 SetThreadPriority(HANDLE hThread,
                  int nPriority)
 {
-  THREAD_BASIC_INFORMATION ThreadBasic;
-  ULONG DataWritten;
+  ULONG Prio = nPriority;
   NTSTATUS Status;
 
-  Status = NtQueryInformationThread(hThread,
-                                   ThreadBasicInformation,
-                                   &ThreadBasic,
-                                   sizeof(THREAD_BASIC_INFORMATION),
-                                   &DataWritten);
-  if (!NT_SUCCESS(Status))
-    {
-      SetLastErrorByStatus(Status);
-      return(FALSE);
-    }
-
-  ThreadBasic.BasePriority = nPriority;
-
   Status = NtSetInformationThread(hThread,
-                                 ThreadBasicInformation,
-                                 &ThreadBasic,
-                                 sizeof(THREAD_BASIC_INFORMATION));
+                                 ThreadBasePriority,
+                                 &Prio,
+                                 sizeof(ULONG));
+
   if (!NT_SUCCESS(Status))
     {
       SetLastErrorByStatus(Status);
@@ -508,18 +558,20 @@ SetThreadPriority(HANDLE hThread,
 }
 
 
+/*
+ * @implemented
+ */
 int STDCALL
 GetThreadPriority(HANDLE hThread)
 {
   THREAD_BASIC_INFORMATION ThreadBasic;
-  ULONG DataWritten;
   NTSTATUS Status;
 
   Status = NtQueryInformationThread(hThread,
                                    ThreadBasicInformation,
                                    &ThreadBasic,
                                    sizeof(THREAD_BASIC_INFORMATION),
-                                   &DataWritten);
+                                   NULL);
   if (!NT_SUCCESS(Status))
     {
       SetLastErrorByStatus(Status);
@@ -530,34 +582,39 @@ GetThreadPriority(HANDLE hThread)
 }
 
 
-WINBOOL STDCALL
+/*
+ * @implemented
+ */
+BOOL STDCALL
 GetThreadPriorityBoost(IN HANDLE hThread,
                       OUT PBOOL pDisablePriorityBoost)
 {
   ULONG PriorityBoost;
-  ULONG DataWritten;
   NTSTATUS Status;
 
   Status = NtQueryInformationThread(hThread,
                                    ThreadPriorityBoost,
                                    &PriorityBoost,
                                    sizeof(ULONG),
-                                   &DataWritten);
+                                   NULL);
   if (!NT_SUCCESS(Status))
     {
       SetLastErrorByStatus(Status);
       return(FALSE);
     }
 
-  *pDisablePriorityBoost = !((WINBOOL)PriorityBoost);
+  *pDisablePriorityBoost = !((BOOL)PriorityBoost);
 
   return(TRUE);
 }
 
 
-WINBOOL STDCALL
+/*
+ * @implemented
+ */
+BOOL STDCALL
 SetThreadPriorityBoost(IN HANDLE hThread,
-                      IN WINBOOL bDisablePriorityBoost)
+                      IN BOOL bDisablePriorityBoost)
 {
   ULONG PriorityBoost;
   NTSTATUS Status;
@@ -578,13 +635,211 @@ SetThreadPriorityBoost(IN HANDLE hThread,
 }
 
 
-WINBOOL STDCALL
+/*
+ * @implemented
+ */
+BOOL STDCALL
 GetThreadSelectorEntry(IN HANDLE hThread,
                       IN DWORD dwSelector,
                       OUT LPLDT_ENTRY lpSelectorEntry)
 {
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-  return(FALSE);
+  DESCRIPTOR_TABLE_ENTRY DescriptionTableEntry;
+  NTSTATUS Status;
+
+  DescriptionTableEntry.Selector = dwSelector;
+  Status = NtQueryInformationThread(hThread,
+                                    ThreadDescriptorTableEntry,
+                                    &DescriptionTableEntry,
+                                    sizeof(DESCRIPTOR_TABLE_ENTRY),
+                                    NULL);
+  if(!NT_SUCCESS(Status))
+  {
+    SetLastErrorByStatus(Status);
+    return FALSE;
+  }
+
+  *lpSelectorEntry = DescriptionTableEntry.Descriptor;
+  return TRUE;
+}
+
+
+/*
+ * @implemented
+ */
+DWORD STDCALL
+SetThreadIdealProcessor(HANDLE hThread,
+                       DWORD dwIdealProcessor)
+{
+  NTSTATUS Status;
+
+  Status = NtSetInformationThread(hThread,
+                                 ThreadIdealProcessor,
+                                 &dwIdealProcessor,
+                                 sizeof(ULONG));
+  if (!NT_SUCCESS(Status))
+    {
+      SetLastErrorByStatus(Status);
+      return -1;
+    }
+
+  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 */