[KERNEL32]: Formatting cleanups and annotations.
authorAlex Ionescu <aionescu@gmail.com>
Wed, 23 May 2012 17:35:25 +0000 (17:35 +0000)
committerAlex Ionescu <aionescu@gmail.com>
Wed, 23 May 2012 17:35:25 +0000 (17:35 +0000)
[KERNEL32]: Simplify QueueWorkItem since the trampoline is in Rtl.
[KERNEL32]: Add SxS support to QueueUserApc.
[KERNEL32]: Add some extra sanity checks/assertions in certain places.

svn path=/trunk/; revision=56651

reactos/dll/win32/kernel32/client/thread.c

index 099164c..adb9bb6 100644 (file)
@@ -8,15 +8,13 @@
  *
  */
 
-/* INCLUDES ******************************************************************/
+/* INCLUDES *******************************************************************/
 
 #include <k32.h>
 
 #define NDEBUG
 #include <debug.h>
 
-/* FIXME: NDK */
-#define HIGH_PRIORITY 31
 #define SXS_SUPPORT_FIXME
 
 typedef NTSTATUS (NTAPI *PCSR_CREATE_REMOTE_THREAD)(IN HANDLE ThreadHandle, IN PCLIENT_ID ClientId);
@@ -26,14 +24,15 @@ WINAPI
 BasepNotifyCsrOfThread(IN HANDLE ThreadHandle,
                        IN PCLIENT_ID ClientId);
 
-/* FUNCTIONS *****************************************************************/
+/* FUNCTIONS ******************************************************************/
+
 static
 LONG BaseThreadExceptionFilter(EXCEPTION_POINTERS * ExceptionInfo)
 {
    LONG ExceptionDisposition = EXCEPTION_EXECUTE_HANDLER;
    LPTOP_LEVEL_EXCEPTION_FILTER RealFilter;
    RealFilter = RtlDecodePointer(GlobalTopLevelExceptionFilter);
-   
+
    if (RealFilter != NULL)
    {
       _SEH2_TRY
@@ -53,8 +52,8 @@ LONG BaseThreadExceptionFilter(EXCEPTION_POINTERS * ExceptionInfo)
 __declspec(noreturn)
 VOID
 WINAPI
-BaseThreadStartup(LPTHREAD_START_ROUTINE lpStartAddress,
-                  LPVOID lpParameter)
+BaseThreadStartup(IN LPTHREAD_START_ROUTINE lpStartAddress,
+                  IN LPVOID lpParameter)
 {
     /* Attempt to call the Thread Start Address */
     _SEH2_TRY
@@ -86,17 +85,58 @@ BaseThreadStartup(LPTHREAD_START_ROUTINE lpStartAddress,
     _SEH2_END;
 }
 
+VOID
+NTAPI
+BaseDispatchApc(IN PAPCFUNC ApcRoutine,
+                IN PVOID Data,
+                IN PACTIVATION_CONTEXT ActivationContext)
+{
+    RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME ActivationFrame;
+
+    /* Setup the activation context */
+    ActivationFrame.Size = sizeof(ActivationFrame);
+    ActivationFrame.Format = RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER;
+
+    /* Check if caller wanted one */
+    if (ActivationContext == INVALID_ACTIVATION_CONTEXT)
+    {
+        /* Do the APC directly */
+        ApcRoutine((ULONG_PTR)Data);
+        return;
+    }
+
+    /* Then activate it */
+    RtlActivateActivationContextUnsafeFast(&ActivationFrame, ActivationContext);
+
+    /* Call the routine under SEH */
+    _SEH2_TRY
+    {
+        ApcRoutine((ULONG_PTR)Data);
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+
+    }
+    _SEH2_END;
+
+    /* Now de-activate and release the activation context */
+    RtlDeactivateActivationContextUnsafeFast(&ActivationFrame);
+    RtlReleaseActivationContext(ActivationContext);
+}
+
+/* PUBLIC FUNCTIONS ***********************************************************/
+
 /*
  * @implemented
  */
 HANDLE
 WINAPI
-CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,
-             DWORD dwStackSize,
-             LPTHREAD_START_ROUTINE lpStartAddress,
-             LPVOID lpParameter,
-             DWORD dwCreationFlags,
-             LPDWORD lpThreadId)
+CreateThread(IN LPSECURITY_ATTRIBUTES lpThreadAttributes,
+             IN DWORD dwStackSize,
+             IN LPTHREAD_START_ROUTINE lpStartAddress,
+             IN LPVOID lpParameter,
+             IN DWORD dwCreationFlags,
+             OUT LPDWORD lpThreadId)
 {
     /* Act as if we're going to create a remote thread in ourselves */
     return CreateRemoteThread(NtCurrentProcess(),
@@ -251,7 +291,7 @@ CreateRemoteThread(HANDLE hProcess,
         if (hProcess != NtCurrentProcess())
         {
             PCSR_CREATE_REMOTE_THREAD CsrCreateRemoteThread;
-            
+
             /* Get the direct CSRSRV export */
             CsrCreateRemoteThread = (PCSR_CREATE_REMOTE_THREAD)
                                     GetProcAddress(GetModuleHandleA("csrsrv"),
@@ -263,7 +303,7 @@ CreateRemoteThread(HANDLE hProcess,
             }
         }
     }
-    
+
     if (!NT_SUCCESS(Status))
     {
         ASSERT(FALSE);
@@ -287,10 +327,15 @@ CreateRemoteThread(HANDLE hProcess,
  */
 VOID
 WINAPI
-ExitThread(DWORD uExitCode)
+ExitThread(IN DWORD uExitCode)
 {
     NTSTATUS Status;
     ULONG LastThread;
+    PRTL_CRITICAL_SECTION LoaderLock;
+
+    /* Make sure loader lock isn't held */
+    LoaderLock = NtCurrentPeb()->LoaderLock;
+    if (LoaderLock) ASSERT(NtCurrentTeb()->ClientId.UniqueThread != LoaderLock->OwningThread);
 
     /*
      * Terminate process if this is the last thread
@@ -301,11 +346,7 @@ ExitThread(DWORD uExitCode)
                                       &LastThread,
                                       sizeof(LastThread),
                                       NULL);
-    if (NT_SUCCESS(Status) && LastThread)
-    {
-        /* Exit the Process */
-        ExitProcess(uExitCode);
-    }
+    if ((NT_SUCCESS(Status)) && (LastThread)) ExitProcess(uExitCode);
 
     /* Notify DLLs and TLS Callbacks of termination */
     LdrShutdownThread();
@@ -316,7 +357,7 @@ ExitThread(DWORD uExitCode)
 
     /* We should never reach this place */
     DPRINT1("It should not happen\n");
-    while (TRUE) ;
+    while (TRUE);
 }
 
 /*
@@ -324,14 +365,14 @@ ExitThread(DWORD uExitCode)
  */
 HANDLE
 WINAPI
-OpenThread(DWORD dwDesiredAccess,
-           BOOL bInheritHandle,
-           DWORD dwThreadId)
+OpenThread(IN DWORD dwDesiredAccess,
+           IN BOOL bInheritHandle,
+           IN DWORD dwThreadId)
 {
     NTSTATUS Status;
     HANDLE ThreadHandle;
     OBJECT_ATTRIBUTES ObjectAttributes;
-    CLIENT_ID ClientId ;
+    CLIENT_ID ClientId;
 
     ClientId.UniqueProcess = 0;
     ClientId.UniqueThread = ULongToHandle(dwThreadId);
@@ -390,11 +431,11 @@ GetCurrentThreadId(VOID)
  */
 BOOL
 NTAPI
-GetThreadTimes(HANDLE hThread,
-               LPFILETIME lpCreationTime,
-               LPFILETIME lpExitTime,
-               LPFILETIME lpKernelTime,
-               LPFILETIME lpUserTime)
+GetThreadTimes(IN HANDLE hThread,
+               OUT LPFILETIME lpCreationTime,
+               OUT LPFILETIME lpExitTime,
+               OUT LPFILETIME lpKernelTime,
+               OUT LPFILETIME lpUserTime)
 {
     KERNEL_USER_TIMES KernelUserTimes;
     NTSTATUS Status;
@@ -407,7 +448,7 @@ GetThreadTimes(HANDLE hThread,
     if (!NT_SUCCESS(Status))
     {
         BaseSetLastNTError(Status);
-        return(FALSE);
+        return FALSE;
     }
 
     *lpCreationTime = *(LPFILETIME)&KernelUserTimes.CreateTime;
@@ -422,8 +463,8 @@ GetThreadTimes(HANDLE hThread,
  */
 BOOL
 WINAPI
-GetThreadContext(HANDLE hThread,
-                 LPCONTEXT lpContext)
+GetThreadContext(IN HANDLE hThread,
+                 OUT LPCONTEXT lpContext)
 {
     NTSTATUS Status;
 
@@ -442,8 +483,8 @@ GetThreadContext(HANDLE hThread,
  */
 BOOL
 WINAPI
-SetThreadContext(HANDLE hThread,
-                 CONST CONTEXT *lpContext)
+SetThreadContext(IN HANDLE hThread,
+                 IN CONST CONTEXT *lpContext)
 {
     NTSTATUS Status;
 
@@ -462,8 +503,8 @@ SetThreadContext(HANDLE hThread,
  */
 BOOL
 WINAPI
-GetExitCodeThread(HANDLE hThread,
-                  LPDWORD lpExitCode)
+GetExitCodeThread(IN HANDLE hThread,
+                  OUT LPDWORD lpExitCode)
 {
     THREAD_BASIC_INFORMATION ThreadBasic;
     NTSTATUS Status;
@@ -476,7 +517,7 @@ GetExitCodeThread(HANDLE hThread,
     if (!NT_SUCCESS(Status))
     {
         BaseSetLastNTError(Status);
-        return(FALSE);
+        return FALSE;
     }
 
     *lpExitCode = ThreadBasic.ExitStatus;
@@ -488,7 +529,7 @@ GetExitCodeThread(HANDLE hThread,
  */
 DWORD
 WINAPI
-ResumeThread(HANDLE hThread)
+ResumeThread(IN HANDLE hThread)
 {
     ULONG PreviousResumeCount;
     NTSTATUS Status;
@@ -508,24 +549,49 @@ ResumeThread(HANDLE hThread)
  */
 BOOL
 WINAPI
-TerminateThread(HANDLE hThread,
-                DWORD dwExitCode)
+TerminateThread(IN HANDLE hThread,
+                IN DWORD dwExitCode)
 {
     NTSTATUS Status;
+    PRTL_CRITICAL_SECTION LoaderLock;
+    THREAD_BASIC_INFORMATION ThreadInfo;
 
+    /* Check for invalid thread handle */
     if (!hThread)
     {
+        /* Fail if one was passed */
         SetLastError(ERROR_INVALID_HANDLE);
         return FALSE;
     }
 
+    /* Get the loader lock */
+    LoaderLock = NtCurrentPeb()->LoaderLock;
+    if (LoaderLock)
+    {
+        /* Get our TID */
+        Status = NtQueryInformationThread(hThread,
+                                          ThreadBasicInformation,
+                                          &ThreadInfo,
+                                          sizeof(ThreadInfo),
+                                          NULL);
+        if (!NT_SUCCESS(Status))
+        {
+            /* Assert that we don't hold the loader lock */
+            ASSERT(NtCurrentTeb()->ClientId.UniqueThread != ThreadInfo.ClientId.UniqueThread);
+            ASSERT(NtCurrentTeb()->ClientId.UniqueThread != LoaderLock->OwningThread);
+        }
+    }
+
+    /* Now terminate the thread */
     Status = NtTerminateThread(hThread, dwExitCode);
     if (!NT_SUCCESS(Status))
     {
+        /* Fail */
         BaseSetLastNTError(Status);
         return FALSE;
     }
 
+    /* All done */
     return TRUE;
 }
 
@@ -534,7 +600,7 @@ TerminateThread(HANDLE hThread,
  */
 DWORD
 WINAPI
-SuspendThread(HANDLE hThread)
+SuspendThread(IN HANDLE hThread)
 {
     ULONG PreviousSuspendCount;
     NTSTATUS Status;
@@ -554,8 +620,8 @@ SuspendThread(HANDLE hThread)
  */
 DWORD_PTR
 WINAPI
-SetThreadAffinityMask(HANDLE hThread,
-                      DWORD_PTR dwThreadAffinityMask)
+SetThreadAffinityMask(IN HANDLE hThread,
+                      IN DWORD_PTR dwThreadAffinityMask)
 {
     THREAD_BASIC_INFORMATION ThreadBasic;
     KAFFINITY AffinityMask;
@@ -592,8 +658,8 @@ SetThreadAffinityMask(HANDLE hThread,
  */
 BOOL
 WINAPI
-SetThreadPriority(HANDLE hThread,
-                  int nPriority)
+SetThreadPriority(IN HANDLE hThread,
+                  IN int nPriority)
 {
     LONG Prio = nPriority;
     NTSTATUS Status;
@@ -601,10 +667,12 @@ SetThreadPriority(HANDLE hThread,
     /* Check if values forcing saturation should be used */
     if (Prio == THREAD_PRIORITY_TIME_CRITICAL)
     {
+        /* This is 16 */
         Prio = (HIGH_PRIORITY + 1) / 2;
     }
     else if (Prio == THREAD_PRIORITY_IDLE)
     {
+        /* This is -16 */
         Prio = -((HIGH_PRIORITY + 1) / 2);
     }
 
@@ -629,7 +697,7 @@ SetThreadPriority(HANDLE hThread,
  */
 int
 WINAPI
-GetThreadPriority(HANDLE hThread)
+GetThreadPriority(IN HANDLE hThread)
 {
     THREAD_BASIC_INFORMATION ThreadBasic;
     NTSTATUS Status;
@@ -700,7 +768,7 @@ SetThreadPriorityBoost(IN HANDLE hThread,
     ULONG PriorityBoost;
     NTSTATUS Status;
 
-    PriorityBoost = (ULONG)bDisablePriorityBoost;
+    PriorityBoost = bDisablePriorityBoost != FALSE;
 
     Status = NtSetInformationThread(hThread,
                                     ThreadPriorityBoost,
@@ -756,8 +824,8 @@ GetThreadSelectorEntry(IN HANDLE hThread,
  */
 DWORD
 WINAPI
-SetThreadIdealProcessor(HANDLE hThread,
-                        DWORD dwIdealProcessor)
+SetThreadIdealProcessor(IN HANDLE hThread,
+                        IN DWORD dwIdealProcessor)
 {
     NTSTATUS Status;
 
@@ -777,197 +845,171 @@ SetThreadIdealProcessor(HANDLE hThread,
 /*
  * @implemented
  */
-DWORD WINAPI
-GetProcessIdOfThread(HANDLE Thread)
+DWORD
+WINAPI
+GetProcessIdOfThread(IN HANDLE Thread)
 {
-  THREAD_BASIC_INFORMATION ThreadBasic;
-  NTSTATUS Status;
-
-  Status = NtQueryInformationThread(Thread,
-                                    ThreadBasicInformation,
-                                    &ThreadBasic,
-                                    sizeof(THREAD_BASIC_INFORMATION),
-                                    NULL);
-  if(!NT_SUCCESS(Status))
-  {
-    BaseSetLastNTError(Status);
-    return 0;
-  }
+    THREAD_BASIC_INFORMATION ThreadBasic;
+    NTSTATUS Status;
 
-  return HandleToUlong(ThreadBasic.ClientId.UniqueProcess);
+    Status = NtQueryInformationThread(Thread,
+                                      ThreadBasicInformation,
+                                      &ThreadBasic,
+                                      sizeof(THREAD_BASIC_INFORMATION),
+                                      NULL);
+    if (!NT_SUCCESS(Status))
+    {
+        BaseSetLastNTError(Status);
+        return 0;
+    }
+
+    return HandleToUlong(ThreadBasic.ClientId.UniqueProcess);
 }
 
 /*
  * @implemented
  */
-DWORD WINAPI
-GetThreadId(HANDLE Thread)
+DWORD
+WINAPI
+GetThreadId(IN HANDLE Thread)
 {
-  THREAD_BASIC_INFORMATION ThreadBasic;
-  NTSTATUS Status;
-
-  Status = NtQueryInformationThread(Thread,
-                                    ThreadBasicInformation,
-                                    &ThreadBasic,
-                                    sizeof(THREAD_BASIC_INFORMATION),
-                                    NULL);
-  if(!NT_SUCCESS(Status))
-  {
-    BaseSetLastNTError(Status);
-    return 0;
-  }
+    THREAD_BASIC_INFORMATION ThreadBasic;
+    NTSTATUS Status;
 
-  return HandleToUlong(ThreadBasic.ClientId.UniqueThread);
+    Status = NtQueryInformationThread(Thread,
+                                      ThreadBasicInformation,
+                                      &ThreadBasic,
+                                      sizeof(THREAD_BASIC_INFORMATION),
+                                      NULL);
+    if (!NT_SUCCESS(Status))
+    {
+        BaseSetLastNTError(Status);
+        return 0;
+    }
+
+    return HandleToUlong(ThreadBasic.ClientId.UniqueThread);
 }
 
 /*
  * @unimplemented
  */
-LANGID WINAPI
-SetThreadUILanguage(LANGID LangId)
-{
-  DPRINT1("SetThreadUILanguage(0x%4x) unimplemented!\n", LangId);
-  return LangId;
-}
-
-static void CALLBACK
-IntCallUserApc(PVOID Function, PVOID dwData, PVOID Argument3)
+LANGID
+WINAPI
+SetThreadUILanguage(IN LANGID LangId)
 {
-   PAPCFUNC pfnAPC = (PAPCFUNC)Function;
-   pfnAPC((ULONG_PTR)dwData);
+    UNIMPLEMENTED;
+    return NtCurrentTeb()->CurrentLocale;
 }
 
 /*
  * @implemented
  */
-DWORD WINAPI
-QueueUserAPC(PAPCFUNC pfnAPC, HANDLE hThread, ULONG_PTR dwData)
+DWORD
+WINAPI
+QueueUserAPC(IN PAPCFUNC pfnAPC,
+             IN HANDLE hThread,
+             IN ULONG_PTR dwData)
 {
-  NTSTATUS Status;
+    NTSTATUS Status;
+    ACTIVATION_CONTEXT_BASIC_INFORMATION ActCtxInfo;
+
+    /* Zero the activation context and query information on it */
+    RtlZeroMemory(&ActCtxInfo, sizeof(ActCtxInfo));
+    // WARNING!!! THIS IS USING THE WIN32 FLAG BECAUSE REACTOS CONTINUES TO BE A POS!!! ///
+    Status = RtlQueryInformationActivationContext(QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX,
+                                                  NULL,
+                                                  0,
+                                                  ActivationContextBasicInformation,
+                                                  &ActCtxInfo,
+                                                  sizeof(ActCtxInfo),
+                                                  NULL);
+    if (!NT_SUCCESS(Status))
+    {
+        /* Fail due to SxS */
+        DbgPrint("SXS: %s failing because RtlQueryInformationActivationContext()"
+                 "returned status %08lx\n", __FUNCTION__, Status);
+        BaseSetLastNTError(Status);
+        return FALSE;
+    }
 
-  Status = NtQueueApcThread(hThread, IntCallUserApc, pfnAPC,
-                            (PVOID)dwData, NULL);
-  if (!NT_SUCCESS(Status))
-  {
-    BaseSetLastNTError(Status);
-    return 0;
-  }
+    /* Queue the APC */
+    Status = NtQueueApcThread(hThread,
+                              (PKNORMAL_ROUTINE)BaseDispatchApc,
+                              pfnAPC,
+                              (PVOID)dwData,
+                              (ActCtxInfo.dwFlags & 1) ?
+                              INVALID_ACTIVATION_CONTEXT : ActCtxInfo.hActCtx);
+    if (!NT_SUCCESS(Status))
+    {
+        BaseSetLastNTError(Status);
+        return FALSE;
+    }
 
-  return 1;
+    /* All good */
+    return TRUE;
 }
 
+/*
+ * @implemented
+ */
 BOOL
 WINAPI
 SetThreadStackGuarantee(IN OUT PULONG StackSizeInBytes)
 {
-    STUB;
+    UNIMPLEMENTED;
     return FALSE;
 }
 
-
 /*
  * @implemented
  */
-BOOL WINAPI
-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;
-  }
-
-  BaseSetLastNTError(Status);
-  return FALSE;
-}
-
-
-typedef struct _QUEUE_USER_WORKITEM_CONTEXT
-{
-    LPTHREAD_START_ROUTINE Function;
-    PVOID Context;
-} QUEUE_USER_WORKITEM_CONTEXT, *PQUEUE_USER_WORKITEM_CONTEXT;
-
-static VOID
-NTAPI
-InternalWorkItemTrampoline(PVOID Context)
+BOOL
+WINAPI
+GetThreadIOPendingFlag(IN HANDLE hThread,
+                       OUT PBOOL lpIOIsPending)
 {
-    QUEUE_USER_WORKITEM_CONTEXT Info;
-
-    ASSERT(Context);
-
-    /* Save the context to the stack */
-    Info = *(volatile QUEUE_USER_WORKITEM_CONTEXT *)Context;
+    ULONG IoPending;
+    NTSTATUS Status;
 
-    /* Free the context before calling the callback. This avoids
-       a memory leak in case the thread dies... */
-    RtlFreeHeap(RtlGetProcessHeap(),
-                0,
-                Context);
+    /* Query the flag */
+    Status = NtQueryInformationThread(hThread,
+                                      ThreadIsIoPending,
+                                      &IoPending,
+                                      sizeof(IoPending),
+                                      NULL);
+    if (NT_SUCCESS(Status))
+    {
+        /* Return the flag */
+        *lpIOIsPending = IoPending ? TRUE : FALSE;
+        return TRUE;
+    }
 
-    /* Call the real callback */
-    Info.Function(Info.Context);
+    /* Fail */
+    BaseSetLastNTError(Status);
+    return FALSE;
 }
 
-
 /*
  * @implemented
  */
 BOOL
 WINAPI
-QueueUserWorkItem(
-    LPTHREAD_START_ROUTINE Function,
-    PVOID Context,
-    ULONG Flags
-    )
+QueueUserWorkItem(IN LPTHREAD_START_ROUTINE Function,
+                  IN PVOID Context,
+                  IN ULONG Flags)
 {
-    PQUEUE_USER_WORKITEM_CONTEXT WorkItemContext;
     NTSTATUS Status;
 
-    /* Save the context for the trampoline function */
-    WorkItemContext = RtlAllocateHeap(RtlGetProcessHeap(),
-                                      0,
-                                      sizeof(*WorkItemContext));
-    if (WorkItemContext == NULL)
-    {
-        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-        return FALSE;
-    }
-
-    WorkItemContext->Function = Function;
-    WorkItemContext->Context = Context;
-
-    /* NOTE: Don't use Function directly since the callback signature
-             differs. This might cause problems on certain platforms... */
-    Status = RtlQueueWorkItem(InternalWorkItemTrampoline,
-                              WorkItemContext,
-                              Flags);
+    /* NOTE: Rtl needs to safely call the function using a trampoline */
+    Status = RtlQueueWorkItem((WORKERCALLBACKFUNC)Function, Context, Flags);
     if (!NT_SUCCESS(Status))
     {
-        /* Free the allocated context in case of failure */
-        RtlFreeHeap(RtlGetProcessHeap(),
-                    0,
-                    WorkItemContext);
-
+        /* Failed */
         BaseSetLastNTError(Status);
         return FALSE;
     }
 
+    /* All good */
     return TRUE;
 }
 
@@ -1207,5 +1249,4 @@ TlsSetValue(IN DWORD Index,
     return TRUE;
 }
 
-
 /* EOF */