+++ /dev/null
-/*
- * COPYRIGHT: See COPYING in the top level directory
- * PROJECT: ReactOS system libraries
- * FILE: dll/win32/kernel32/client/thread.c
- * PURPOSE: Thread functions
- * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
- * Ariadne (ariadne@xs4all.nl)
- *
- */
-
-/* INCLUDES *******************************************************************/
-
-#include <k32.h>
-
-#define NDEBUG
-#include <debug.h>
-
-#define SXS_SUPPORT_FIXME
-
-typedef NTSTATUS (NTAPI *PCSR_CREATE_REMOTE_THREAD)(IN HANDLE ThreadHandle, IN PCLIENT_ID ClientId);
-
-NTSTATUS
-WINAPI
-BasepNotifyCsrOfThread(IN HANDLE ThreadHandle,
- IN PCLIENT_ID ClientId);
-
-/* 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
- {
- ExceptionDisposition = RealFilter(ExceptionInfo);
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- ExceptionDisposition = UnhandledExceptionFilter(ExceptionInfo);
- }
- _SEH2_END;
- }
-
- return ExceptionDisposition;
-}
-
-__declspec(noreturn)
-VOID
-WINAPI
-BaseThreadStartup(IN LPTHREAD_START_ROUTINE lpStartAddress,
- IN LPVOID lpParameter)
-{
- /* Attempt to call the Thread Start Address */
- _SEH2_TRY
- {
- /* Legacy check which is still used today for Win32 threads */
- if (NtCurrentTeb()->NtTib.Version == (30 << 8)) // OS/2 V3.0 ("Cruiser")
- {
- /* This registers the termination port with CSRSS */
- if (!BaseRunningInServerProcess) CsrNewThread();
- }
-
- /* Get the exit code from the Thread Start */
- ExitThread((lpStartAddress)((PVOID)lpParameter));
- }
- _SEH2_EXCEPT(BaseThreadExceptionFilter(_SEH2_GetExceptionInformation()))
- {
- /* Get the Exit code from the SEH Handler */
- if (!BaseRunningInServerProcess)
- {
- /* Kill the whole process, usually */
- ExitProcess(_SEH2_GetExceptionCode());
- }
- else
- {
- /* If running inside CSRSS, kill just this thread */
- ExitThread(_SEH2_GetExceptionCode());
- }
- }
- _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
-DECLSPEC_HOTPATCH
-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(),
- lpThreadAttributes,
- dwStackSize,
- lpStartAddress,
- lpParameter,
- dwCreationFlags,
- lpThreadId);
-}
-
-/*
- * @implemented
- */
-HANDLE
-WINAPI
-CreateRemoteThread(IN HANDLE hProcess,
- IN LPSECURITY_ATTRIBUTES lpThreadAttributes,
- IN DWORD dwStackSize,
- IN LPTHREAD_START_ROUTINE lpStartAddress,
- IN LPVOID lpParameter,
- IN DWORD dwCreationFlags,
- OUT LPDWORD lpThreadId)
-{
- NTSTATUS Status;
- INITIAL_TEB InitialTeb;
- CONTEXT Context;
- CLIENT_ID ClientId;
- OBJECT_ATTRIBUTES LocalObjectAttributes;
- POBJECT_ATTRIBUTES ObjectAttributes;
- HANDLE hThread;
- ULONG Dummy;
- PTEB Teb;
- THREAD_BASIC_INFORMATION ThreadBasicInfo;
- PACTIVATION_CONTEXT_STACK ActivationContextStack = NULL;
- ACTIVATION_CONTEXT_BASIC_INFORMATION ActCtxInfo;
- ULONG_PTR Cookie;
- ULONG ReturnLength;
- DPRINT("CreateRemoteThread: hProcess: %p dwStackSize: %lu lpStartAddress"
- ": %p lpParameter: %p, dwCreationFlags: %lx\n", hProcess,
- dwStackSize, lpStartAddress, lpParameter, dwCreationFlags);
-
- /* Clear the Context */
- RtlZeroMemory(&Context, sizeof(CONTEXT));
-
- /* Write PID */
- ClientId.UniqueProcess = hProcess;
-
- /* Create the Stack */
- Status = BaseCreateStack(hProcess,
- dwStackSize,
- dwCreationFlags & STACK_SIZE_PARAM_IS_A_RESERVATION ?
- dwStackSize : 0,
- &InitialTeb);
- if (!NT_SUCCESS(Status))
- {
- BaseSetLastNTError(Status);
- return NULL;
- }
-
- /* Create Initial Context */
- BaseInitializeContext(&Context,
- lpParameter,
- lpStartAddress,
- InitialTeb.StackBase,
- 1);
-
- /* initialize the attributes for the thread object */
- ObjectAttributes = BaseFormatObjectAttributes(&LocalObjectAttributes,
- lpThreadAttributes,
- NULL);
-
- /* Create the Kernel Thread Object */
- Status = NtCreateThread(&hThread,
- THREAD_ALL_ACCESS,
- ObjectAttributes,
- hProcess,
- &ClientId,
- &Context,
- &InitialTeb,
- TRUE);
- if (!NT_SUCCESS(Status))
- {
- /* Fail the kernel create */
- BaseFreeThreadStack(hProcess, &InitialTeb);
- BaseSetLastNTError(Status);
- return NULL;
- }
-
- /* Are we in the same process? */
- if (hProcess == NtCurrentProcess())
- {
- /* Get the TEB */
- Status = NtQueryInformationThread(hThread,
- ThreadBasicInformation,
- &ThreadBasicInfo,
- sizeof(ThreadBasicInfo),
- &ReturnLength);
- if (!NT_SUCCESS(Status))
- {
- /* Fail */
- ERROR_DBGBREAK("SXS: %s - Failing thread create because "
- "NtQueryInformationThread() failed with status %08lx\n",
- __FUNCTION__, Status);
- return NULL;
- }
-
- /* Allocate the Activation Context Stack */
- Status = RtlAllocateActivationContextStack(&ActivationContextStack);
- if (!NT_SUCCESS(Status))
- {
- /* Fail */
- ERROR_DBGBREAK("SXS: %s - Failing thread create because "
- "RtlAllocateActivationContextStack() failed with status %08lx\n",
- __FUNCTION__, Status);
- return NULL;
- }
-
- /* Save it */
- Teb = ThreadBasicInfo.TebBaseAddress;
- Teb->ActivationContextStackPointer = ActivationContextStack;
-
- /* Query the Context */
- Status = RtlQueryInformationActivationContext(RTL_QUERY_ACTIVATION_CONTEXT_FLAG_USE_ACTIVE_ACTIVATION_CONTEXT,
- NULL,
- 0,
- ActivationContextBasicInformation,
- &ActCtxInfo,
- sizeof(ActCtxInfo),
- &ReturnLength);
- if (!NT_SUCCESS(Status))
- {
- /* Fail */
- ERROR_DBGBREAK("SXS: %s - Failing thread create because "
- "RtlQueryInformationActivationContext() failed with status %08lx\n",
- __FUNCTION__, Status);
-
- /* Free the activation context stack */
- // RtlFreeThreadActivationContextStack();
- RtlFreeActivationContextStack(Teb->ActivationContextStackPointer);
-
- return NULL;
- }
-
- /* Does it need to be activated? */
- if ((ActCtxInfo.hActCtx) && !(ActCtxInfo.dwFlags & 1))
- {
- /* Activate it */
- Status = RtlActivateActivationContextEx(RTL_ACTIVATE_ACTIVATION_CONTEXT_EX_FLAG_RELEASE_ON_STACK_DEALLOCATION,
- Teb,
- ActCtxInfo.hActCtx,
- &Cookie);
- if (!NT_SUCCESS(Status))
- {
- /* Fail */
- ERROR_DBGBREAK("SXS: %s - Failing thread create because "
- "RtlActivateActivationContextEx() failed with status %08lx\n",
- __FUNCTION__, Status);
-
- /* Free the activation context stack */
- // RtlFreeThreadActivationContextStack();
- RtlFreeActivationContextStack(Teb->ActivationContextStackPointer);
-
- return NULL;
- }
- }
- }
-
- /* Notify CSR */
- if (!BaseRunningInServerProcess)
- {
- Status = BasepNotifyCsrOfThread(hThread, &ClientId);
- ASSERT(NT_SUCCESS(Status));
- }
- else
- {
- if (hProcess != NtCurrentProcess())
- {
- PCSR_CREATE_REMOTE_THREAD CsrCreateRemoteThread;
-
- /* Get the direct CSRSRV export */
- CsrCreateRemoteThread = (PCSR_CREATE_REMOTE_THREAD)
- GetProcAddress(GetModuleHandleA("csrsrv"),
- "CsrCreateRemoteThread");
- if (CsrCreateRemoteThread)
- {
- /* Call it instead of going through LPC */
- Status = CsrCreateRemoteThread(hThread, &ClientId);
- ASSERT(NT_SUCCESS(Status));
- }
- }
- }
-
- /* Success */
- if (lpThreadId) *lpThreadId = HandleToUlong(ClientId.UniqueThread);
-
- /* Resume it if asked */
- if (!(dwCreationFlags & CREATE_SUSPENDED)) NtResumeThread(hThread, &Dummy);
-
- /* Return handle to thread */
- return hThread;
-}
-
-/*
- * @implemented
- */
-VOID
-WINAPI
-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
- * of the current process
- */
- Status = NtQueryInformationThread(NtCurrentThread(),
- ThreadAmILastThread,
- &LastThread,
- sizeof(LastThread),
- NULL);
- if ((NT_SUCCESS(Status)) && (LastThread)) ExitProcess(uExitCode);
-
- /* Notify DLLs and TLS Callbacks of termination */
- LdrShutdownThread();
-
- /* Tell the Kernel to free the Stack */
- NtCurrentTeb()->FreeStackOnTermination = TRUE;
- NtTerminateThread(NULL, uExitCode);
-
- /* We should never reach this place */
- ERROR_FATAL("It should not happen\n");
- while (TRUE); /* 'noreturn' function */
-}
-
-/*
- * @implemented
- */
-HANDLE
-WINAPI
-OpenThread(IN DWORD dwDesiredAccess,
- IN BOOL bInheritHandle,
- IN DWORD dwThreadId)
-{
- NTSTATUS Status;
- HANDLE ThreadHandle;
- OBJECT_ATTRIBUTES ObjectAttributes;
- CLIENT_ID ClientId;
-
- ClientId.UniqueProcess = 0;
- ClientId.UniqueThread = ULongToHandle(dwThreadId);
-
- InitializeObjectAttributes(&ObjectAttributes,
- NULL,
- (bInheritHandle ? OBJ_INHERIT : 0),
- NULL,
- NULL);
-
- Status = NtOpenThread(&ThreadHandle,
- dwDesiredAccess,
- &ObjectAttributes,
- &ClientId);
- if (!NT_SUCCESS(Status))
- {
- BaseSetLastNTError(Status);
- return NULL;
- }
-
- return ThreadHandle;
-}
-
-/*
- * @implemented
- */
-PTEB
-GetTeb(VOID)
-{
- return NtCurrentTeb();
-}
-
-/*
- * @implemented
- */
-BOOL
-WINAPI
-SwitchToThread(VOID)
-{
- return NtYieldExecution() != STATUS_NO_YIELD_PERFORMED;
-}
-
-
-/*
- * @implemented
- */
-DWORD
-WINAPI
-GetCurrentThreadId(VOID)
-{
- return HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread);
-}
-
-/*
- * @implemented
- */
-BOOL
-NTAPI
-GetThreadTimes(IN HANDLE hThread,
- OUT LPFILETIME lpCreationTime,
- OUT LPFILETIME lpExitTime,
- OUT LPFILETIME lpKernelTime,
- OUT LPFILETIME lpUserTime)
-{
- KERNEL_USER_TIMES KernelUserTimes;
- NTSTATUS Status;
-
- Status = NtQueryInformationThread(hThread,
- ThreadTimes,
- &KernelUserTimes,
- sizeof(KERNEL_USER_TIMES),
- NULL);
- if (!NT_SUCCESS(Status))
- {
- BaseSetLastNTError(Status);
- return FALSE;
- }
-
- *lpCreationTime = *(LPFILETIME)&KernelUserTimes.CreateTime;
- *lpExitTime = *(LPFILETIME)&KernelUserTimes.ExitTime;
- *lpKernelTime = *(LPFILETIME)&KernelUserTimes.KernelTime;
- *lpUserTime = *(LPFILETIME)&KernelUserTimes.UserTime;
- return TRUE;
-}
-
-/*
- * @implemented
- */
-BOOL
-WINAPI
-GetThreadContext(IN HANDLE hThread,
- OUT LPCONTEXT lpContext)
-{
- NTSTATUS Status;
-
- Status = NtGetContextThread(hThread, lpContext);
- if (!NT_SUCCESS(Status))
- {
- BaseSetLastNTError(Status);
- return FALSE;
- }
-
- return TRUE;
-}
-
-/*
- * @implemented
- */
-BOOL
-WINAPI
-SetThreadContext(IN HANDLE hThread,
- IN CONST CONTEXT *lpContext)
-{
- NTSTATUS Status;
-
- Status = NtSetContextThread(hThread, (PCONTEXT)lpContext);
- if (!NT_SUCCESS(Status))
- {
- BaseSetLastNTError(Status);
- return FALSE;
- }
-
- return TRUE;
-}
-
-/*
- * @implemented
- */
-BOOL
-WINAPI
-GetExitCodeThread(IN HANDLE hThread,
- OUT LPDWORD lpExitCode)
-{
- THREAD_BASIC_INFORMATION ThreadBasic;
- NTSTATUS Status;
-
- Status = NtQueryInformationThread(hThread,
- ThreadBasicInformation,
- &ThreadBasic,
- sizeof(THREAD_BASIC_INFORMATION),
- NULL);
- if (!NT_SUCCESS(Status))
- {
- BaseSetLastNTError(Status);
- return FALSE;
- }
-
- *lpExitCode = ThreadBasic.ExitStatus;
- return TRUE;
-}
-
-/*
- * @implemented
- */
-DWORD
-WINAPI
-ResumeThread(IN HANDLE hThread)
-{
- ULONG PreviousResumeCount;
- NTSTATUS Status;
-
- Status = NtResumeThread(hThread, &PreviousResumeCount);
- if (!NT_SUCCESS(Status))
- {
- BaseSetLastNTError(Status);
- return -1;
- }
-
- return PreviousResumeCount;
-}
-
-/*
- * @implemented
- */
-BOOL
-WINAPI
-TerminateThread(IN HANDLE hThread,
- IN DWORD dwExitCode)
-{
- NTSTATUS Status;
-#if DBG
- PRTL_CRITICAL_SECTION LoaderLock;
- THREAD_BASIC_INFORMATION ThreadInfo;
-#endif /* DBG */
-
- /* Check for invalid thread handle */
- if (!hThread)
- {
- /* Fail if one was passed */
- SetLastError(ERROR_INVALID_HANDLE);
- return FALSE;
- }
-
-#if DBG
- /* Get the loader lock */
- LoaderLock = NtCurrentPeb()->LoaderLock;
- if (LoaderLock)
- {
- /* Get our TID */
- Status = NtQueryInformationThread(hThread,
- ThreadBasicInformation,
- &ThreadInfo,
- sizeof(ThreadInfo),
- NULL);
- if (NT_SUCCESS(Status))
- {
- /* If terminating the current thread, we must not hold the loader lock */
- if (NtCurrentTeb()->ClientId.UniqueThread == ThreadInfo.ClientId.UniqueThread)
- ASSERT(NtCurrentTeb()->ClientId.UniqueThread != LoaderLock->OwningThread);
- }
- }
-#endif /* DBG */
-
- /* Now terminate the thread */
- Status = NtTerminateThread(hThread, dwExitCode);
- if (!NT_SUCCESS(Status))
- {
- /* Fail */
- BaseSetLastNTError(Status);
- return FALSE;
- }
-
- /* All done */
- return TRUE;
-}
-
-/*
- * @implemented
- */
-DWORD
-WINAPI
-SuspendThread(IN HANDLE hThread)
-{
- ULONG PreviousSuspendCount;
- NTSTATUS Status;
-
- Status = NtSuspendThread(hThread, &PreviousSuspendCount);
- if (!NT_SUCCESS(Status))
- {
- BaseSetLastNTError(Status);
- return -1;
- }
-
- return PreviousSuspendCount;
-}
-
-/*
- * @implemented
- */
-DWORD_PTR
-WINAPI
-SetThreadAffinityMask(IN HANDLE hThread,
- IN DWORD_PTR dwThreadAffinityMask)
-{
- THREAD_BASIC_INFORMATION ThreadBasic;
- KAFFINITY AffinityMask;
- NTSTATUS Status;
-
- AffinityMask = (KAFFINITY)dwThreadAffinityMask;
-
- Status = NtQueryInformationThread(hThread,
- ThreadBasicInformation,
- &ThreadBasic,
- sizeof(THREAD_BASIC_INFORMATION),
- NULL);
- if (!NT_SUCCESS(Status))
- {
- BaseSetLastNTError(Status);
- return 0;
- }
-
- Status = NtSetInformationThread(hThread,
- ThreadAffinityMask,
- &AffinityMask,
- sizeof(KAFFINITY));
- if (!NT_SUCCESS(Status))
- {
- BaseSetLastNTError(Status);
- ThreadBasic.AffinityMask = 0;
- }
-
- return ThreadBasic.AffinityMask;
-}
-
-/*
- * @implemented
- */
-BOOL
-WINAPI
-SetThreadPriority(IN HANDLE hThread,
- IN int nPriority)
-{
- LONG Prio = nPriority;
- NTSTATUS Status;
-
- /* 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);
- }
-
- /* Set the Base Priority */
- Status = NtSetInformationThread(hThread,
- ThreadBasePriority,
- &Prio,
- sizeof(LONG));
- if (!NT_SUCCESS(Status))
- {
- /* Failure */
- BaseSetLastNTError(Status);
- return FALSE;
- }
-
- /* Return */
- return TRUE;
-}
-
-/*
- * @implemented
- */
-int
-WINAPI
-GetThreadPriority(IN HANDLE hThread)
-{
- THREAD_BASIC_INFORMATION ThreadBasic;
- NTSTATUS Status;
-
- /* Query the Base Priority Increment */
- Status = NtQueryInformationThread(hThread,
- ThreadBasicInformation,
- &ThreadBasic,
- sizeof(THREAD_BASIC_INFORMATION),
- NULL);
- if (!NT_SUCCESS(Status))
- {
- /* Failure */
- BaseSetLastNTError(Status);
- return THREAD_PRIORITY_ERROR_RETURN;
- }
-
- /* Do some conversions for saturation values */
- if (ThreadBasic.BasePriority == ((HIGH_PRIORITY + 1) / 2))
- {
- /* Win32 calls this "time critical" */
- ThreadBasic.BasePriority = THREAD_PRIORITY_TIME_CRITICAL;
- }
- else if (ThreadBasic.BasePriority == -((HIGH_PRIORITY + 1) / 2))
- {
- /* Win32 calls this "idle" */
- ThreadBasic.BasePriority = THREAD_PRIORITY_IDLE;
- }
-
- /* Return the final result */
- return ThreadBasic.BasePriority;
-}
-
-/*
- * @implemented
- */
-BOOL
-WINAPI
-GetThreadPriorityBoost(IN HANDLE hThread,
- OUT PBOOL pDisablePriorityBoost)
-{
- ULONG PriorityBoost;
- NTSTATUS Status;
-
- Status = NtQueryInformationThread(hThread,
- ThreadPriorityBoost,
- &PriorityBoost,
- sizeof(ULONG),
- NULL);
- if (!NT_SUCCESS(Status))
- {
- BaseSetLastNTError(Status);
- return FALSE;
- }
-
- *pDisablePriorityBoost = PriorityBoost;
- return TRUE;
-}
-
-/*
- * @implemented
- */
-BOOL
-NTAPI
-SetThreadPriorityBoost(IN HANDLE hThread,
- IN BOOL bDisablePriorityBoost)
-{
- ULONG PriorityBoost;
- NTSTATUS Status;
-
- PriorityBoost = bDisablePriorityBoost != FALSE;
-
- Status = NtSetInformationThread(hThread,
- ThreadPriorityBoost,
- &PriorityBoost,
- sizeof(ULONG));
- if (!NT_SUCCESS(Status))
- {
- BaseSetLastNTError(Status);
- return FALSE;
- }
-
- return TRUE;
-}
-
-/*
- * @implemented
- */
-BOOL
-WINAPI
-GetThreadSelectorEntry(IN HANDLE hThread,
- IN DWORD dwSelector,
- OUT LPLDT_ENTRY lpSelectorEntry)
-{
-#ifdef _M_IX86
- DESCRIPTOR_TABLE_ENTRY DescriptionTableEntry;
- NTSTATUS Status;
-
- /* Set the selector and do the query */
- DescriptionTableEntry.Selector = dwSelector;
- Status = NtQueryInformationThread(hThread,
- ThreadDescriptorTableEntry,
- &DescriptionTableEntry,
- sizeof(DESCRIPTOR_TABLE_ENTRY),
- NULL);
- if (!NT_SUCCESS(Status))
- {
- /* Fail */
- BaseSetLastNTError(Status);
- return FALSE;
- }
-
- /* Success, return the selector */
- *lpSelectorEntry = DescriptionTableEntry.Descriptor;
- return TRUE;
-#else
- DPRINT1("Calling GetThreadSelectorEntry!\n");
- return FALSE;
-#endif
-}
-
-/*
- * @implemented
- */
-DWORD
-WINAPI
-SetThreadIdealProcessor(IN HANDLE hThread,
- IN DWORD dwIdealProcessor)
-{
- NTSTATUS Status;
-
- Status = NtSetInformationThread(hThread,
- ThreadIdealProcessor,
- &dwIdealProcessor,
- sizeof(ULONG));
- if (!NT_SUCCESS(Status))
- {
- BaseSetLastNTError(Status);
- return -1;
- }
-
- return (DWORD)Status;
-}
-
-/*
- * @implemented
- */
-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;
- }
-
- return HandleToUlong(ThreadBasic.ClientId.UniqueProcess);
-}
-
-/*
- * @implemented
- */
-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;
- }
-
- return HandleToUlong(ThreadBasic.ClientId.UniqueThread);
-}
-
-/*
- * @unimplemented
- */
-LANGID
-WINAPI
-SetThreadUILanguage(IN LANGID LangId)
-{
- UNIMPLEMENTED;
- return (LANGID)NtCurrentTeb()->CurrentLocale;
-}
-
-/*
- * @implemented
- */
-DWORD
-WINAPI
-QueueUserAPC(IN PAPCFUNC pfnAPC,
- IN HANDLE hThread,
- IN ULONG_PTR dwData)
-{
- NTSTATUS Status;
- ACTIVATION_CONTEXT_BASIC_INFORMATION ActCtxInfo;
-
- /* Zero the activation context and query information on it */
- RtlZeroMemory(&ActCtxInfo, sizeof(ActCtxInfo));
- Status = RtlQueryInformationActivationContext(RTL_QUERY_ACTIVATION_CONTEXT_FLAG_USE_ACTIVE_ACTIVATION_CONTEXT,
- 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))
- {
- BaseSetLastNTError(Status);
- return FALSE;
- }
-
- /* All good */
- return TRUE;
-}
-
-/*
- * @implemented
- */
-BOOL
-WINAPI
-SetThreadStackGuarantee(IN OUT PULONG StackSizeInBytes)
-{
- static int once;
- if (once++ == 0)
- DPRINT1("SetThreadStackGuarantee(%p): stub\n", StackSizeInBytes);
- return TRUE;
-}
-
-/*
- * @implemented
- */
-BOOL
-WINAPI
-GetThreadIOPendingFlag(IN HANDLE hThread,
- OUT PBOOL lpIOIsPending)
-{
- ULONG IoPending;
- NTSTATUS Status;
-
- /* Query the flag */
- Status = NtQueryInformationThread(hThread,
- ThreadIsIoPending,
- &IoPending,
- sizeof(IoPending),
- NULL);
- if (NT_SUCCESS(Status))
- {
- /* Return the flag */
- *lpIOIsPending = IoPending ? TRUE : FALSE;
- return TRUE;
- }
-
- /* Fail */
- BaseSetLastNTError(Status);
- return FALSE;
-}
-
-/*
- * @implemented
- */
-BOOL
-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))
- {
- /* Failed */
- BaseSetLastNTError(Status);
- return FALSE;
- }
-
- /* All good */
- return TRUE;
-}
-
-/*
- * @implemented
- */
-DWORD
-WINAPI
-TlsAlloc(VOID)
-{
- ULONG Index;
- PTEB Teb;
- PPEB Peb;
-
- /* Get the PEB and TEB, lock the PEB */
- Teb = NtCurrentTeb();
- Peb = Teb->ProcessEnvironmentBlock;
- RtlAcquirePebLock();
-
- /* Try to get regular TEB slot */
- Index = RtlFindClearBitsAndSet(Peb->TlsBitmap, 1, 0);
- if (Index != 0xFFFFFFFF)
- {
- /* Clear the value. */
- Teb->TlsSlots[Index] = 0;
- RtlReleasePebLock();
- return Index;
- }
-
- /* If it fails, try to find expansion TEB slot. */
- Index = RtlFindClearBitsAndSet(Peb->TlsExpansionBitmap, 1, 0);
- if (Index != 0xFFFFFFFF)
- {
- /* Is there no expansion slot yet? */
- if (!Teb->TlsExpansionSlots)
- {
- /* Allocate an array */
- Teb->TlsExpansionSlots = RtlAllocateHeap(RtlGetProcessHeap(),
- HEAP_ZERO_MEMORY,
- TLS_EXPANSION_SLOTS *
- sizeof(PVOID));
- }
-
- /* Did we get an array? */
- if (!Teb->TlsExpansionSlots)
- {
- /* Fail */
- RtlClearBits(Peb->TlsExpansionBitmap, Index, 1);
- Index = 0xFFFFFFFF;
- BaseSetLastNTError(STATUS_NO_MEMORY);
- }
- else
- {
- /* Clear the value. */
- Teb->TlsExpansionSlots[Index] = 0;
- Index += TLS_MINIMUM_AVAILABLE;
- }
- }
- else
- {
- /* Fail */
- BaseSetLastNTError(STATUS_NO_MEMORY);
- }
-
- /* Release the lock and return */
- RtlReleasePebLock();
- return Index;
-}
-
-/*
- * @implemented
- */
-BOOL
-WINAPI
-TlsFree(IN DWORD Index)
-{
- BOOL BitSet;
- PPEB Peb;
- ULONG TlsIndex;
- PVOID TlsBitmap;
- NTSTATUS Status;
-
- /* Acquire the PEB lock and grab the PEB */
- Peb = NtCurrentPeb();
- RtlAcquirePebLock();
-
- /* Check if the index is too high */
- if (Index >= TLS_MINIMUM_AVAILABLE)
- {
- /* Check if it can fit in the expansion slots */
- TlsIndex = Index - TLS_MINIMUM_AVAILABLE;
- if (TlsIndex >= TLS_EXPANSION_SLOTS)
- {
- /* It's invalid */
- BaseSetLastNTError(STATUS_INVALID_PARAMETER);
- RtlReleasePebLock();
- return FALSE;
- }
- else
- {
- /* Use the expansion bitmap */
- TlsBitmap = Peb->TlsExpansionBitmap;
- Index = TlsIndex;
- }
- }
- else
- {
- /* Use the normal bitmap */
- TlsBitmap = Peb->TlsBitmap;
- }
-
- /* Check if the index was set */
- BitSet = RtlAreBitsSet(TlsBitmap, Index, 1);
- if (BitSet)
- {
- /* Tell the kernel to free the TLS cells */
- Status = NtSetInformationThread(NtCurrentThread(),
- ThreadZeroTlsCell,
- &Index,
- sizeof(DWORD));
- if (!NT_SUCCESS(Status))
- {
- BaseSetLastNTError(STATUS_INVALID_PARAMETER);
- RtlReleasePebLock();
- return FALSE;
- }
-
- /* Clear the bit */
- RtlClearBits(TlsBitmap, Index, 1);
- }
- else
- {
- /* Fail */
- BaseSetLastNTError(STATUS_INVALID_PARAMETER);
- RtlReleasePebLock();
- return FALSE;
- }
-
- /* Done! */
- RtlReleasePebLock();
- return TRUE;
-}
-
-/*
- * @implemented
- */
-LPVOID
-WINAPI
-TlsGetValue(IN DWORD Index)
-{
- PTEB Teb;
-
- /* Get the TEB and clear the last error */
- Teb = NtCurrentTeb();
- Teb->LastErrorValue = 0;
-
- /* Check for simple TLS index */
- if (Index < TLS_MINIMUM_AVAILABLE)
- {
- /* Return it */
- return Teb->TlsSlots[Index];
- }
-
- /* Check for valid index */
- if (Index >= TLS_EXPANSION_SLOTS + TLS_MINIMUM_AVAILABLE)
- {
- /* Fail */
- BaseSetLastNTError(STATUS_INVALID_PARAMETER);
- return NULL;
- }
-
- /* The expansion slots are allocated on demand, so check for it. */
- Teb->LastErrorValue = 0;
- if (!Teb->TlsExpansionSlots) return NULL;
-
- /* Return the value from the expansion slots */
- return Teb->TlsExpansionSlots[Index - TLS_MINIMUM_AVAILABLE];
-}
-
-/*
- * @implemented
- */
-BOOL
-WINAPI
-TlsSetValue(IN DWORD Index,
- IN LPVOID Value)
-{
- DWORD TlsIndex;
- PTEB Teb = NtCurrentTeb();
-
- /* Check for simple TLS index */
- if (Index < TLS_MINIMUM_AVAILABLE)
- {
- /* Return it */
- Teb->TlsSlots[Index] = Value;
- return TRUE;
- }
-
- /* Check if this is an expansion slot */
- TlsIndex = Index - TLS_MINIMUM_AVAILABLE;
- if (TlsIndex >= TLS_EXPANSION_SLOTS)
- {
- /* Fail */
- BaseSetLastNTError(STATUS_INVALID_PARAMETER);
- return FALSE;
- }
-
- /* Do we not have expansion slots? */
- if (!Teb->TlsExpansionSlots)
- {
- /* Get the PEB lock to see if we still need them */
- RtlAcquirePebLock();
- if (!Teb->TlsExpansionSlots)
- {
- /* Allocate them */
- Teb->TlsExpansionSlots = RtlAllocateHeap(RtlGetProcessHeap(),
- HEAP_ZERO_MEMORY,
- TLS_EXPANSION_SLOTS *
- sizeof(PVOID));
- if (!Teb->TlsExpansionSlots)
- {
- /* Fail */
- RtlReleasePebLock();
- BaseSetLastNTError(STATUS_NO_MEMORY);
- return FALSE;
- }
- }
-
- /* Release the lock */
- RtlReleasePebLock();
- }
-
- /* Write the value */
- Teb->TlsExpansionSlots[TlsIndex] = Value;
-
- /* Success */
- return TRUE;
-}
-
-/* EOF */