Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332/* * 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);
/* FUNCTIONS ******************************************************************/
NTSTATUSWINAPIBasepNotifyCsrOfThread(IN HANDLE ThreadHandle, IN PCLIENT_ID ClientId){ BASE_API_MESSAGE ApiMessage; PBASE_CREATE_THREAD CreateThreadRequest = &ApiMessage.Data.CreateThreadRequest;
DPRINT("BasepNotifyCsrOfThread: Thread: %p, Handle %p\n", ClientId->UniqueThread, ThreadHandle);
/* Fill out the request */ CreateThreadRequest->ClientId = *ClientId; CreateThreadRequest->ThreadHandle = ThreadHandle;
/* Call CSR */ CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage, NULL, CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepCreateThread), sizeof(*CreateThreadRequest)); if (!NT_SUCCESS(ApiMessage.Status)) { DPRINT1("Failed to tell CSRSS about new thread: %lx\n", ApiMessage.Status); return ApiMessage.Status; }
/* Return Success */ return STATUS_SUCCESS;}
DECLSPEC_NORETURNVOIDWINAPIBaseThreadStartup( _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(lpParameter)); } _SEH2_EXCEPT(UnhandledExceptionFilter(_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;}
VOIDNTAPIBaseDispatchApc(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 */HANDLEWINAPIDECLSPEC_HOTPATCHCreateThread(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 */HANDLEWINAPICreateRemoteThread(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; SIZE_T ReturnSize;
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, (dwCreationFlags & STACK_SIZE_PARAM_IS_A_RESERVATION) ? 0 : dwStackSize, (dwCreationFlags & STACK_SIZE_PARAM_IS_A_RESERVATION) ? dwStackSize : 0, &InitialTeb); if (!NT_SUCCESS(Status)) { BaseSetLastNTError(Status); return NULL; }
/* Create the 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 */ DPRINT1("SXS: %s - Failing thread create because " "NtQueryInformationThread() failed with status %08lx\n", __FUNCTION__, Status); goto Quit; }
/* Allocate the Activation Context Stack */ Status = RtlAllocateActivationContextStack(&ActivationContextStack); if (!NT_SUCCESS(Status)) { /* Fail */ DPRINT1("SXS: %s - Failing thread create because " "RtlAllocateActivationContextStack() failed with status %08lx\n", __FUNCTION__, Status); goto Quit; }
/* 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), &ReturnSize); if (!NT_SUCCESS(Status)) { /* Fail */ DPRINT1("SXS: %s - Failing thread create because " "RtlQueryInformationActivationContext() failed with status %08lx\n", __FUNCTION__, Status); goto Quit; }
/* 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 */ DPRINT1("SXS: %s - Failing thread create because " "RtlActivateActivationContextEx() failed with status %08lx\n", __FUNCTION__, Status); goto Quit; } }
/* Sync the service tag with the parent thread's one */ Teb->SubProcessTag = NtCurrentTeb()->SubProcessTag; }
/* Notify CSR */ if (!BaseRunningInServerProcess) { Status = BasepNotifyCsrOfThread(hThread, &ClientId); } 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); } } }
Quit: if (!NT_SUCCESS(Status)) { /* Failed to create the thread */
/* Free the activation context stack */ if (ActivationContextStack) RtlFreeActivationContextStack(ActivationContextStack);
NtTerminateThread(hThread, Status); // FIXME: Wait for the thread to terminate? BaseFreeThreadStack(hProcess, &InitialTeb); NtClose(hThread);
BaseSetLastNTError(Status); return NULL; }
/* Success */ if (lpThreadId) *lpThreadId = HandleToUlong(ClientId.UniqueThread);
/* Resume the thread if asked */ if (!(dwCreationFlags & CREATE_SUSPENDED)) NtResumeThread(hThread, &Dummy);
/* Return handle to thread */ return hThread;}
/* * @implemented */VOIDWINAPIExitThread(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 */HANDLEWINAPIOpenThread(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 */PTEBGetTeb(VOID){ return NtCurrentTeb();}
/* * @implemented */BOOLWINAPISwitchToThread(VOID){ return NtYieldExecution() != STATUS_NO_YIELD_PERFORMED;}
/* * @implemented */DWORDWINAPIGetCurrentThreadId(VOID){ return HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread);}
/* * @implemented */BOOLNTAPIGetThreadTimes(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 */BOOLWINAPIGetThreadContext(IN HANDLE hThread, OUT LPCONTEXT lpContext){ NTSTATUS Status;
Status = NtGetContextThread(hThread, lpContext); if (!NT_SUCCESS(Status)) { BaseSetLastNTError(Status); return FALSE; }
return TRUE;}
/* * @implemented */BOOLWINAPISetThreadContext(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 */BOOLWINAPIGetExitCodeThread(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 */DWORDWINAPIResumeThread(IN HANDLE hThread){ ULONG PreviousResumeCount; NTSTATUS Status;
Status = NtResumeThread(hThread, &PreviousResumeCount); if (!NT_SUCCESS(Status)) { BaseSetLastNTError(Status); return -1; }
return PreviousResumeCount;}
/* * @implemented */BOOLWINAPITerminateThread(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 */DWORDWINAPISuspendThread(IN HANDLE hThread){ ULONG PreviousSuspendCount; NTSTATUS Status;
Status = NtSuspendThread(hThread, &PreviousSuspendCount); if (!NT_SUCCESS(Status)) { BaseSetLastNTError(Status); return -1; }
return PreviousSuspendCount;}
/* * @implemented */DWORD_PTRWINAPISetThreadAffinityMask(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 */BOOLWINAPISetThreadPriority(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 */intWINAPIGetThreadPriority(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 */BOOLWINAPIGetThreadPriorityBoost(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 */BOOLNTAPISetThreadPriorityBoost(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 */BOOLWINAPIGetThreadSelectorEntry(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 */DWORDWINAPISetThreadIdealProcessor(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 */DWORDWINAPIGetProcessIdOfThread(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 */DWORDWINAPIGetThreadId(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 */LANGIDWINAPISetThreadUILanguage(IN LANGID LangId){#if (NTDDI_VERSION < NTDDI_LONGHORN) /* We only support LangId == 0, for selecting a language * identifier that best supports the NT Console. */ if (LangId != 0) { BaseSetLastNTError(STATUS_NOT_SUPPORTED); return 0; }#endif
UNIMPLEMENTED;
return LANGIDFROMLCID(NtCurrentTeb()->CurrentLocale);}
/* * @implemented */DWORDWINAPIQueueUserAPC(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;}
/* * @unimplemented */BOOLWINAPISetThreadStackGuarantee(IN OUT PULONG StackSizeInBytes){ PTEB Teb = NtCurrentTeb(); ULONG GuaranteedStackBytes; ULONG AllocationSize;
if (!StackSizeInBytes) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; }
AllocationSize = *StackSizeInBytes;
/* Retrieve the current stack size */ GuaranteedStackBytes = Teb->GuaranteedStackBytes;
/* Return the size of the previous stack */ *StackSizeInBytes = GuaranteedStackBytes;
/* * If the new stack size is either zero or is less than the current size, * the previous stack size is returned and we return success. */ if ((AllocationSize == 0) || (AllocationSize < GuaranteedStackBytes)) { return TRUE; }
// FIXME: Unimplemented! UNIMPLEMENTED_ONCE;
// Temporary HACK for supporting applications! return TRUE; // FALSE;}
/* * @implemented */BOOLWINAPIGetThreadIOPendingFlag(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 */BOOLWINAPIQueueUserWorkItem(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 */DWORDWINAPITlsAlloc(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 */BOOLWINAPITlsFree(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 */LPVOIDWINAPITlsGetValue(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 */BOOLWINAPITlsSetValue(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 */