[KERNEL32]: Formatting cleanups and annotations.

[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
This commit is contained in:
Alex Ionescu 2012-05-23 17:35:25 +00:00
parent 7b19834435
commit 7efa1d4b81

View file

@ -8,15 +8,13 @@
* *
*/ */
/* INCLUDES ******************************************************************/ /* INCLUDES *******************************************************************/
#include <k32.h> #include <k32.h>
#define NDEBUG #define NDEBUG
#include <debug.h> #include <debug.h>
/* FIXME: NDK */
#define HIGH_PRIORITY 31
#define SXS_SUPPORT_FIXME #define SXS_SUPPORT_FIXME
typedef NTSTATUS (NTAPI *PCSR_CREATE_REMOTE_THREAD)(IN HANDLE ThreadHandle, IN PCLIENT_ID ClientId); typedef NTSTATUS (NTAPI *PCSR_CREATE_REMOTE_THREAD)(IN HANDLE ThreadHandle, IN PCLIENT_ID ClientId);
@ -26,7 +24,8 @@ WINAPI
BasepNotifyCsrOfThread(IN HANDLE ThreadHandle, BasepNotifyCsrOfThread(IN HANDLE ThreadHandle,
IN PCLIENT_ID ClientId); IN PCLIENT_ID ClientId);
/* FUNCTIONS *****************************************************************/ /* FUNCTIONS ******************************************************************/
static static
LONG BaseThreadExceptionFilter(EXCEPTION_POINTERS * ExceptionInfo) LONG BaseThreadExceptionFilter(EXCEPTION_POINTERS * ExceptionInfo)
{ {
@ -53,8 +52,8 @@ LONG BaseThreadExceptionFilter(EXCEPTION_POINTERS * ExceptionInfo)
__declspec(noreturn) __declspec(noreturn)
VOID VOID
WINAPI WINAPI
BaseThreadStartup(LPTHREAD_START_ROUTINE lpStartAddress, BaseThreadStartup(IN LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter) IN LPVOID lpParameter)
{ {
/* Attempt to call the Thread Start Address */ /* Attempt to call the Thread Start Address */
_SEH2_TRY _SEH2_TRY
@ -86,17 +85,58 @@ BaseThreadStartup(LPTHREAD_START_ROUTINE lpStartAddress,
_SEH2_END; _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 * @implemented
*/ */
HANDLE HANDLE
WINAPI WINAPI
CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, CreateThread(IN LPSECURITY_ATTRIBUTES lpThreadAttributes,
DWORD dwStackSize, IN DWORD dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress, IN LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter, IN LPVOID lpParameter,
DWORD dwCreationFlags, IN DWORD dwCreationFlags,
LPDWORD lpThreadId) OUT LPDWORD lpThreadId)
{ {
/* Act as if we're going to create a remote thread in ourselves */ /* Act as if we're going to create a remote thread in ourselves */
return CreateRemoteThread(NtCurrentProcess(), return CreateRemoteThread(NtCurrentProcess(),
@ -287,10 +327,15 @@ CreateRemoteThread(HANDLE hProcess,
*/ */
VOID VOID
WINAPI WINAPI
ExitThread(DWORD uExitCode) ExitThread(IN DWORD uExitCode)
{ {
NTSTATUS Status; NTSTATUS Status;
ULONG LastThread; 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 * Terminate process if this is the last thread
@ -301,11 +346,7 @@ ExitThread(DWORD uExitCode)
&LastThread, &LastThread,
sizeof(LastThread), sizeof(LastThread),
NULL); NULL);
if (NT_SUCCESS(Status) && LastThread) if ((NT_SUCCESS(Status)) && (LastThread)) ExitProcess(uExitCode);
{
/* Exit the Process */
ExitProcess(uExitCode);
}
/* Notify DLLs and TLS Callbacks of termination */ /* Notify DLLs and TLS Callbacks of termination */
LdrShutdownThread(); LdrShutdownThread();
@ -316,7 +357,7 @@ ExitThread(DWORD uExitCode)
/* We should never reach this place */ /* We should never reach this place */
DPRINT1("It should not happen\n"); DPRINT1("It should not happen\n");
while (TRUE) ; while (TRUE);
} }
/* /*
@ -324,14 +365,14 @@ ExitThread(DWORD uExitCode)
*/ */
HANDLE HANDLE
WINAPI WINAPI
OpenThread(DWORD dwDesiredAccess, OpenThread(IN DWORD dwDesiredAccess,
BOOL bInheritHandle, IN BOOL bInheritHandle,
DWORD dwThreadId) IN DWORD dwThreadId)
{ {
NTSTATUS Status; NTSTATUS Status;
HANDLE ThreadHandle; HANDLE ThreadHandle;
OBJECT_ATTRIBUTES ObjectAttributes; OBJECT_ATTRIBUTES ObjectAttributes;
CLIENT_ID ClientId ; CLIENT_ID ClientId;
ClientId.UniqueProcess = 0; ClientId.UniqueProcess = 0;
ClientId.UniqueThread = ULongToHandle(dwThreadId); ClientId.UniqueThread = ULongToHandle(dwThreadId);
@ -390,11 +431,11 @@ GetCurrentThreadId(VOID)
*/ */
BOOL BOOL
NTAPI NTAPI
GetThreadTimes(HANDLE hThread, GetThreadTimes(IN HANDLE hThread,
LPFILETIME lpCreationTime, OUT LPFILETIME lpCreationTime,
LPFILETIME lpExitTime, OUT LPFILETIME lpExitTime,
LPFILETIME lpKernelTime, OUT LPFILETIME lpKernelTime,
LPFILETIME lpUserTime) OUT LPFILETIME lpUserTime)
{ {
KERNEL_USER_TIMES KernelUserTimes; KERNEL_USER_TIMES KernelUserTimes;
NTSTATUS Status; NTSTATUS Status;
@ -407,7 +448,7 @@ GetThreadTimes(HANDLE hThread,
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
BaseSetLastNTError(Status); BaseSetLastNTError(Status);
return(FALSE); return FALSE;
} }
*lpCreationTime = *(LPFILETIME)&KernelUserTimes.CreateTime; *lpCreationTime = *(LPFILETIME)&KernelUserTimes.CreateTime;
@ -422,8 +463,8 @@ GetThreadTimes(HANDLE hThread,
*/ */
BOOL BOOL
WINAPI WINAPI
GetThreadContext(HANDLE hThread, GetThreadContext(IN HANDLE hThread,
LPCONTEXT lpContext) OUT LPCONTEXT lpContext)
{ {
NTSTATUS Status; NTSTATUS Status;
@ -442,8 +483,8 @@ GetThreadContext(HANDLE hThread,
*/ */
BOOL BOOL
WINAPI WINAPI
SetThreadContext(HANDLE hThread, SetThreadContext(IN HANDLE hThread,
CONST CONTEXT *lpContext) IN CONST CONTEXT *lpContext)
{ {
NTSTATUS Status; NTSTATUS Status;
@ -462,8 +503,8 @@ SetThreadContext(HANDLE hThread,
*/ */
BOOL BOOL
WINAPI WINAPI
GetExitCodeThread(HANDLE hThread, GetExitCodeThread(IN HANDLE hThread,
LPDWORD lpExitCode) OUT LPDWORD lpExitCode)
{ {
THREAD_BASIC_INFORMATION ThreadBasic; THREAD_BASIC_INFORMATION ThreadBasic;
NTSTATUS Status; NTSTATUS Status;
@ -476,7 +517,7 @@ GetExitCodeThread(HANDLE hThread,
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
BaseSetLastNTError(Status); BaseSetLastNTError(Status);
return(FALSE); return FALSE;
} }
*lpExitCode = ThreadBasic.ExitStatus; *lpExitCode = ThreadBasic.ExitStatus;
@ -488,7 +529,7 @@ GetExitCodeThread(HANDLE hThread,
*/ */
DWORD DWORD
WINAPI WINAPI
ResumeThread(HANDLE hThread) ResumeThread(IN HANDLE hThread)
{ {
ULONG PreviousResumeCount; ULONG PreviousResumeCount;
NTSTATUS Status; NTSTATUS Status;
@ -508,24 +549,49 @@ ResumeThread(HANDLE hThread)
*/ */
BOOL BOOL
WINAPI WINAPI
TerminateThread(HANDLE hThread, TerminateThread(IN HANDLE hThread,
DWORD dwExitCode) IN DWORD dwExitCode)
{ {
NTSTATUS Status; NTSTATUS Status;
PRTL_CRITICAL_SECTION LoaderLock;
THREAD_BASIC_INFORMATION ThreadInfo;
/* Check for invalid thread handle */
if (!hThread) if (!hThread)
{ {
/* Fail if one was passed */
SetLastError(ERROR_INVALID_HANDLE); SetLastError(ERROR_INVALID_HANDLE);
return FALSE; 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); Status = NtTerminateThread(hThread, dwExitCode);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
/* Fail */
BaseSetLastNTError(Status); BaseSetLastNTError(Status);
return FALSE; return FALSE;
} }
/* All done */
return TRUE; return TRUE;
} }
@ -534,7 +600,7 @@ TerminateThread(HANDLE hThread,
*/ */
DWORD DWORD
WINAPI WINAPI
SuspendThread(HANDLE hThread) SuspendThread(IN HANDLE hThread)
{ {
ULONG PreviousSuspendCount; ULONG PreviousSuspendCount;
NTSTATUS Status; NTSTATUS Status;
@ -554,8 +620,8 @@ SuspendThread(HANDLE hThread)
*/ */
DWORD_PTR DWORD_PTR
WINAPI WINAPI
SetThreadAffinityMask(HANDLE hThread, SetThreadAffinityMask(IN HANDLE hThread,
DWORD_PTR dwThreadAffinityMask) IN DWORD_PTR dwThreadAffinityMask)
{ {
THREAD_BASIC_INFORMATION ThreadBasic; THREAD_BASIC_INFORMATION ThreadBasic;
KAFFINITY AffinityMask; KAFFINITY AffinityMask;
@ -592,8 +658,8 @@ SetThreadAffinityMask(HANDLE hThread,
*/ */
BOOL BOOL
WINAPI WINAPI
SetThreadPriority(HANDLE hThread, SetThreadPriority(IN HANDLE hThread,
int nPriority) IN int nPriority)
{ {
LONG Prio = nPriority; LONG Prio = nPriority;
NTSTATUS Status; NTSTATUS Status;
@ -601,10 +667,12 @@ SetThreadPriority(HANDLE hThread,
/* Check if values forcing saturation should be used */ /* Check if values forcing saturation should be used */
if (Prio == THREAD_PRIORITY_TIME_CRITICAL) if (Prio == THREAD_PRIORITY_TIME_CRITICAL)
{ {
/* This is 16 */
Prio = (HIGH_PRIORITY + 1) / 2; Prio = (HIGH_PRIORITY + 1) / 2;
} }
else if (Prio == THREAD_PRIORITY_IDLE) else if (Prio == THREAD_PRIORITY_IDLE)
{ {
/* This is -16 */
Prio = -((HIGH_PRIORITY + 1) / 2); Prio = -((HIGH_PRIORITY + 1) / 2);
} }
@ -629,7 +697,7 @@ SetThreadPriority(HANDLE hThread,
*/ */
int int
WINAPI WINAPI
GetThreadPriority(HANDLE hThread) GetThreadPriority(IN HANDLE hThread)
{ {
THREAD_BASIC_INFORMATION ThreadBasic; THREAD_BASIC_INFORMATION ThreadBasic;
NTSTATUS Status; NTSTATUS Status;
@ -700,7 +768,7 @@ SetThreadPriorityBoost(IN HANDLE hThread,
ULONG PriorityBoost; ULONG PriorityBoost;
NTSTATUS Status; NTSTATUS Status;
PriorityBoost = (ULONG)bDisablePriorityBoost; PriorityBoost = bDisablePriorityBoost != FALSE;
Status = NtSetInformationThread(hThread, Status = NtSetInformationThread(hThread,
ThreadPriorityBoost, ThreadPriorityBoost,
@ -756,8 +824,8 @@ GetThreadSelectorEntry(IN HANDLE hThread,
*/ */
DWORD DWORD
WINAPI WINAPI
SetThreadIdealProcessor(HANDLE hThread, SetThreadIdealProcessor(IN HANDLE hThread,
DWORD dwIdealProcessor) IN DWORD dwIdealProcessor)
{ {
NTSTATUS Status; NTSTATUS Status;
@ -777,8 +845,9 @@ SetThreadIdealProcessor(HANDLE hThread,
/* /*
* @implemented * @implemented
*/ */
DWORD WINAPI DWORD
GetProcessIdOfThread(HANDLE Thread) WINAPI
GetProcessIdOfThread(IN HANDLE Thread)
{ {
THREAD_BASIC_INFORMATION ThreadBasic; THREAD_BASIC_INFORMATION ThreadBasic;
NTSTATUS Status; NTSTATUS Status;
@ -788,7 +857,7 @@ GetProcessIdOfThread(HANDLE Thread)
&ThreadBasic, &ThreadBasic,
sizeof(THREAD_BASIC_INFORMATION), sizeof(THREAD_BASIC_INFORMATION),
NULL); NULL);
if(!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
BaseSetLastNTError(Status); BaseSetLastNTError(Status);
return 0; return 0;
@ -800,8 +869,9 @@ GetProcessIdOfThread(HANDLE Thread)
/* /*
* @implemented * @implemented
*/ */
DWORD WINAPI DWORD
GetThreadId(HANDLE Thread) WINAPI
GetThreadId(IN HANDLE Thread)
{ {
THREAD_BASIC_INFORMATION ThreadBasic; THREAD_BASIC_INFORMATION ThreadBasic;
NTSTATUS Status; NTSTATUS Status;
@ -811,7 +881,7 @@ GetThreadId(HANDLE Thread)
&ThreadBasic, &ThreadBasic,
sizeof(THREAD_BASIC_INFORMATION), sizeof(THREAD_BASIC_INFORMATION),
NULL); NULL);
if(!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
BaseSetLastNTError(Status); BaseSetLastNTError(Status);
return 0; return 0;
@ -823,151 +893,123 @@ GetThreadId(HANDLE Thread)
/* /*
* @unimplemented * @unimplemented
*/ */
LANGID WINAPI LANGID
SetThreadUILanguage(LANGID LangId) WINAPI
SetThreadUILanguage(IN LANGID LangId)
{ {
DPRINT1("SetThreadUILanguage(0x%4x) unimplemented!\n", LangId); UNIMPLEMENTED;
return LangId; return NtCurrentTeb()->CurrentLocale;
}
static void CALLBACK
IntCallUserApc(PVOID Function, PVOID dwData, PVOID Argument3)
{
PAPCFUNC pfnAPC = (PAPCFUNC)Function;
pfnAPC((ULONG_PTR)dwData);
} }
/* /*
* @implemented * @implemented
*/ */
DWORD WINAPI DWORD
QueueUserAPC(PAPCFUNC pfnAPC, HANDLE hThread, ULONG_PTR dwData) WINAPI
QueueUserAPC(IN PAPCFUNC pfnAPC,
IN HANDLE hThread,
IN ULONG_PTR dwData)
{ {
NTSTATUS Status; NTSTATUS Status;
ACTIVATION_CONTEXT_BASIC_INFORMATION ActCtxInfo;
Status = NtQueueApcThread(hThread, IntCallUserApc, pfnAPC, /* Zero the activation context and query information on it */
(PVOID)dwData, NULL); 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;
}
/* Queue the APC */
Status = NtQueueApcThread(hThread,
(PKNORMAL_ROUTINE)BaseDispatchApc,
pfnAPC,
(PVOID)dwData,
(ActCtxInfo.dwFlags & 1) ?
INVALID_ACTIVATION_CONTEXT : ActCtxInfo.hActCtx);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
BaseSetLastNTError(Status); BaseSetLastNTError(Status);
return 0; return FALSE;
} }
return 1; /* All good */
return TRUE;
} }
/*
* @implemented
*/
BOOL BOOL
WINAPI WINAPI
SetThreadStackGuarantee(IN OUT PULONG StackSizeInBytes) SetThreadStackGuarantee(IN OUT PULONG StackSizeInBytes)
{ {
STUB; UNIMPLEMENTED;
return FALSE; 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)
{
QUEUE_USER_WORKITEM_CONTEXT Info;
ASSERT(Context);
/* Save the context to the stack */
Info = *(volatile QUEUE_USER_WORKITEM_CONTEXT *)Context;
/* Free the context before calling the callback. This avoids
a memory leak in case the thread dies... */
RtlFreeHeap(RtlGetProcessHeap(),
0,
Context);
/* Call the real callback */
Info.Function(Info.Context);
}
/* /*
* @implemented * @implemented
*/ */
BOOL BOOL
WINAPI WINAPI
QueueUserWorkItem( GetThreadIOPendingFlag(IN HANDLE hThread,
LPTHREAD_START_ROUTINE Function, OUT PBOOL lpIOIsPending)
PVOID Context,
ULONG Flags
)
{ {
PQUEUE_USER_WORKITEM_CONTEXT WorkItemContext; ULONG IoPending;
NTSTATUS Status; NTSTATUS Status;
/* Save the context for the trampoline function */ /* Query the flag */
WorkItemContext = RtlAllocateHeap(RtlGetProcessHeap(), Status = NtQueryInformationThread(hThread,
0, ThreadIsIoPending,
sizeof(*WorkItemContext)); &IoPending,
if (WorkItemContext == NULL) sizeof(IoPending),
NULL);
if (NT_SUCCESS(Status))
{ {
SetLastError(ERROR_NOT_ENOUGH_MEMORY); /* Return the flag */
return FALSE; *lpIOIsPending = IoPending ? TRUE : FALSE;
return TRUE;
} }
WorkItemContext->Function = Function; /* Fail */
WorkItemContext->Context = Context; BaseSetLastNTError(Status);
return FALSE;
}
/* NOTE: Don't use Function directly since the callback signature /*
differs. This might cause problems on certain platforms... */ * @implemented
Status = RtlQueueWorkItem(InternalWorkItemTrampoline, */
WorkItemContext, BOOL
Flags); WINAPI
QueueUserWorkItem(IN LPTHREAD_START_ROUTINE Function,
IN PVOID Context,
IN ULONG Flags)
{
NTSTATUS Status;
/* NOTE: Rtl needs to safely call the function using a trampoline */
Status = RtlQueueWorkItem((WORKERCALLBACKFUNC)Function, Context, Flags);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
/* Free the allocated context in case of failure */ /* Failed */
RtlFreeHeap(RtlGetProcessHeap(),
0,
WorkItemContext);
BaseSetLastNTError(Status); BaseSetLastNTError(Status);
return FALSE; return FALSE;
} }
/* All good */
return TRUE; return TRUE;
} }
@ -1207,5 +1249,4 @@ TlsSetValue(IN DWORD Index,
return TRUE; return TRUE;
} }
/* EOF */ /* EOF */