Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS system libraries * PURPOSE: Rtl user thread functions * FILE: lib/rtl/thread.c * PROGRAMERS: * Alex Ionescu (alex@relsoft.net) * Eric Kohl * KJK::Hyperion */
/* INCLUDES *****************************************************************/
#include <rtl.h>
#define NDEBUG#include <debug.h>
/* PRIVATE FUNCTIONS *******************************************************/
NTSTATUSNTAPIRtlpCreateUserStack(IN HANDLE ProcessHandle, IN SIZE_T StackReserve OPTIONAL, IN SIZE_T StackCommit OPTIONAL, IN ULONG StackZeroBits OPTIONAL, OUT PINITIAL_TEB InitialTeb){ NTSTATUS Status; SYSTEM_BASIC_INFORMATION SystemBasicInfo; PIMAGE_NT_HEADERS Headers; ULONG_PTR Stack; BOOLEAN UseGuard; ULONG Dummy; SIZE_T MinimumStackCommit, GuardPageSize;
/* Get some memory information */ Status = ZwQuerySystemInformation(SystemBasicInformation, &SystemBasicInfo, sizeof(SYSTEM_BASIC_INFORMATION), NULL); if (!NT_SUCCESS(Status)) return Status;
/* Use the Image Settings if we are dealing with the current Process */ if (ProcessHandle == NtCurrentProcess()) { /* Get the Image Headers */ Headers = RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress); if (!Headers) return STATUS_INVALID_IMAGE_FORMAT;
/* If we didn't get the parameters, find them ourselves */ if (StackReserve == 0) StackReserve = Headers->OptionalHeader.SizeOfStackReserve; if (StackCommit == 0) StackCommit = Headers->OptionalHeader.SizeOfStackCommit;
MinimumStackCommit = NtCurrentPeb()->MinimumStackCommit; if ((MinimumStackCommit != 0) && (StackCommit < MinimumStackCommit)) { StackCommit = MinimumStackCommit; } } else { /* Use the System Settings if needed */ if (StackReserve == 0) StackReserve = SystemBasicInfo.AllocationGranularity; if (StackCommit == 0) StackCommit = SystemBasicInfo.PageSize; }
/* Check if the commit is higher than the reserve */ if (StackCommit >= StackReserve) { /* Grow the reserve beyond the commit, up to 1MB alignment */ StackReserve = ROUND_UP(StackCommit, 1024 * 1024); }
/* Align everything to Page Size */ StackCommit = ROUND_UP(StackCommit, SystemBasicInfo.PageSize); StackReserve = ROUND_UP(StackReserve, SystemBasicInfo.AllocationGranularity);
/* Reserve memory for the stack */ Stack = 0; Status = ZwAllocateVirtualMemory(ProcessHandle, (PVOID*)&Stack, StackZeroBits, &StackReserve, MEM_RESERVE, PAGE_READWRITE); if (!NT_SUCCESS(Status)) return Status;
/* Now set up some basic Initial TEB Parameters */ InitialTeb->AllocatedStackBase = (PVOID)Stack; InitialTeb->StackBase = (PVOID)(Stack + StackReserve); InitialTeb->PreviousStackBase = NULL; InitialTeb->PreviousStackLimit = NULL;
/* Update the stack position */ Stack += StackReserve - StackCommit;
/* Check if we can add a guard page */ if (StackReserve >= StackCommit + SystemBasicInfo.PageSize) { Stack -= SystemBasicInfo.PageSize; StackCommit += SystemBasicInfo.PageSize; UseGuard = TRUE; } else { UseGuard = FALSE; }
/* Allocate memory for the stack */ Status = ZwAllocateVirtualMemory(ProcessHandle, (PVOID*)&Stack, 0, &StackCommit, MEM_COMMIT, PAGE_READWRITE); if (!NT_SUCCESS(Status)) { GuardPageSize = 0; ZwFreeVirtualMemory(ProcessHandle, (PVOID*)&Stack, &GuardPageSize, MEM_RELEASE); return Status; }
/* Now set the current Stack Limit */ InitialTeb->StackLimit = (PVOID)Stack;
/* Create a guard page if needed */ if (UseGuard) { GuardPageSize = SystemBasicInfo.PageSize; Status = ZwProtectVirtualMemory(ProcessHandle, (PVOID*)&Stack, &GuardPageSize, PAGE_GUARD | PAGE_READWRITE, &Dummy); if (!NT_SUCCESS(Status)) return Status;
/* Update the Stack Limit keeping in mind the Guard Page */ InitialTeb->StackLimit = (PVOID)((ULONG_PTR)InitialTeb->StackLimit + GuardPageSize); }
/* We are done! */ return STATUS_SUCCESS;}
VOIDNTAPIRtlpFreeUserStack(IN HANDLE ProcessHandle, IN PINITIAL_TEB InitialTeb){ SIZE_T Dummy = 0;
/* Free the Stack */ ZwFreeVirtualMemory(ProcessHandle, &InitialTeb->AllocatedStackBase, &Dummy, MEM_RELEASE);
/* Clear the initial TEB */ RtlZeroMemory(InitialTeb, sizeof(*InitialTeb));}
/* FUNCTIONS ***************************************************************/
/* * @implemented */NTSTATUS__cdeclRtlSetThreadIsCritical(IN BOOLEAN NewValue, OUT PBOOLEAN OldValue OPTIONAL, IN BOOLEAN NeedBreaks){ ULONG BreakOnTermination;
/* Initialize to FALSE */ if (OldValue) *OldValue = FALSE;
/* Fail, if the critical breaks flag is required but is not set */ if ((NeedBreaks) && !(NtCurrentPeb()->NtGlobalFlag & FLG_ENABLE_SYSTEM_CRIT_BREAKS)) { return STATUS_UNSUCCESSFUL; }
/* Check if the caller wants the old value */ if (OldValue) { /* Query and return the old break on termination flag for the process */ ZwQueryInformationThread(NtCurrentThread(), ThreadBreakOnTermination, &BreakOnTermination, sizeof(ULONG), NULL); *OldValue = (BOOLEAN)BreakOnTermination; }
/* Set the break on termination flag for the process */ BreakOnTermination = NewValue; return ZwSetInformationThread(NtCurrentThread(), ThreadBreakOnTermination, &BreakOnTermination, sizeof(ULONG));}
/* @implemented*/NTSTATUSNTAPIRtlCreateUserThread(IN HANDLE ProcessHandle, IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL, IN BOOLEAN CreateSuspended, IN ULONG StackZeroBits OPTIONAL, IN SIZE_T StackReserve OPTIONAL, IN SIZE_T StackCommit OPTIONAL, IN PTHREAD_START_ROUTINE StartAddress, IN PVOID Parameter OPTIONAL, OUT PHANDLE ThreadHandle OPTIONAL, OUT PCLIENT_ID ClientId OPTIONAL){ NTSTATUS Status; HANDLE Handle; CLIENT_ID ThreadCid; INITIAL_TEB InitialTeb; OBJECT_ATTRIBUTES ObjectAttributes; CONTEXT Context;
/* First, we'll create the Stack */ Status = RtlpCreateUserStack(ProcessHandle, StackReserve, StackCommit, StackZeroBits, &InitialTeb); if (!NT_SUCCESS(Status)) return Status;
/* Next, we'll set up the Initial Context */ RtlInitializeContext(ProcessHandle, &Context, Parameter, StartAddress, InitialTeb.StackBase);
/* We are now ready to create the Kernel Thread Object */ InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, SecurityDescriptor); Status = ZwCreateThread(&Handle, THREAD_ALL_ACCESS, &ObjectAttributes, ProcessHandle, &ThreadCid, &Context, &InitialTeb, CreateSuspended); if (!NT_SUCCESS(Status)) { /* Free the stack */ RtlpFreeUserStack(ProcessHandle, &InitialTeb); } else { /* Return thread data */ if (ThreadHandle) *ThreadHandle = Handle; else NtClose(Handle); if (ClientId) *ClientId = ThreadCid; }
/* Return success or the previous failure */ return Status;}
/* * @implemented */VOIDNTAPIRtlExitUserThread(NTSTATUS Status){ /* Call the Loader and tell him to notify the DLLs */ LdrShutdownThread();
/* Shut us down */ NtCurrentTeb()->FreeStackOnTermination = TRUE; NtTerminateThread(NtCurrentThread(), Status);}
/* @implemented*/VOIDNTAPIRtlFreeUserThreadStack(HANDLE ProcessHandle, HANDLE ThreadHandle){ NTSTATUS Status; THREAD_BASIC_INFORMATION ThreadBasicInfo; SIZE_T Dummy, Size = 0; PVOID StackLocation;
/* Query the Basic Info */ Status = NtQueryInformationThread(ThreadHandle, ThreadBasicInformation, &ThreadBasicInfo, sizeof(THREAD_BASIC_INFORMATION), NULL); if (!NT_SUCCESS(Status) || !ThreadBasicInfo.TebBaseAddress) return;
/* Get the deallocation stack */ Status = NtReadVirtualMemory(ProcessHandle, &((PTEB)ThreadBasicInfo.TebBaseAddress)-> DeallocationStack, &StackLocation, sizeof(PVOID), &Dummy); if (!NT_SUCCESS(Status) || !StackLocation) return;
/* Free it */ NtFreeVirtualMemory(ProcessHandle, &StackLocation, &Size, MEM_RELEASE);}
PTEBNTAPI_NtCurrentTeb(VOID){ /* Return the TEB */ return NtCurrentTeb();}
NTSTATUSNTAPIRtlRemoteCall(IN HANDLE Process, IN HANDLE Thread, IN PVOID CallSite, IN ULONG ArgumentCount, IN PULONG Arguments, IN BOOLEAN PassContext, IN BOOLEAN AlreadySuspended){ UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED;}