* 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
*/
#include <rtl.h>
#define NDEBUG
#include <debug.h>
NTSTATUS
NTAPI
RtlpCreateUserStack(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;
Status = ZwQuerySystemInformation(SystemBasicInformation,
&SystemBasicInfo,
sizeof(SYSTEM_BASIC_INFORMATION),
NULL);
if (!NT_SUCCESS(Status)) return Status;
if (ProcessHandle == NtCurrentProcess())
{
Headers = RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress);
if (!Headers) return STATUS_INVALID_IMAGE_FORMAT;
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
{
if (StackReserve == 0)
StackReserve = SystemBasicInfo.AllocationGranularity;
if (StackCommit == 0)
StackCommit = SystemBasicInfo.PageSize;
}
if (StackCommit >= StackReserve)
{
StackReserve = ROUND_UP(StackCommit, 1024 * 1024);
}
StackCommit = ROUND_UP(StackCommit, SystemBasicInfo.PageSize);
StackReserve = ROUND_UP(StackReserve, SystemBasicInfo.AllocationGranularity);
Stack = 0;
Status = ZwAllocateVirtualMemory(ProcessHandle,
(PVOID*)&Stack,
StackZeroBits,
&StackReserve,
MEM_RESERVE,
PAGE_READWRITE);
if (!NT_SUCCESS(Status)) return Status;
InitialTeb->AllocatedStackBase = (PVOID)Stack;
InitialTeb->StackBase = (PVOID)(Stack + StackReserve);
InitialTeb->PreviousStackBase = NULL;
InitialTeb->PreviousStackLimit = NULL;
Stack += StackReserve - StackCommit;
if (StackReserve >= StackCommit + SystemBasicInfo.PageSize)
{
Stack -= SystemBasicInfo.PageSize;
StackCommit += SystemBasicInfo.PageSize;
UseGuard = TRUE;
}
else
{
UseGuard = FALSE;
}
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;
}
InitialTeb->StackLimit = (PVOID)Stack;
if (UseGuard)
{
GuardPageSize = SystemBasicInfo.PageSize;
Status = ZwProtectVirtualMemory(ProcessHandle,
(PVOID*)&Stack,
&GuardPageSize,
PAGE_GUARD | PAGE_READWRITE,
&Dummy);
if (!NT_SUCCESS(Status)) return Status;
InitialTeb->StackLimit = (PVOID)((ULONG_PTR)InitialTeb->StackLimit +
GuardPageSize);
}
return STATUS_SUCCESS;
}
VOID
NTAPI
RtlpFreeUserStack(IN HANDLE ProcessHandle,
IN PINITIAL_TEB InitialTeb)
{
SIZE_T Dummy = 0;
ZwFreeVirtualMemory(ProcessHandle,
&InitialTeb->AllocatedStackBase,
&Dummy,
MEM_RELEASE);
RtlZeroMemory(InitialTeb, sizeof(*InitialTeb));
}
* @implemented
*/
NTSTATUS
__cdecl
RtlSetThreadIsCritical(IN BOOLEAN NewValue,
OUT PBOOLEAN OldValue OPTIONAL,
IN BOOLEAN NeedBreaks)
{
ULONG BreakOnTermination;
if (OldValue) *OldValue = FALSE;
if ((NeedBreaks) &&
!(NtCurrentPeb()->NtGlobalFlag & FLG_ENABLE_SYSTEM_CRIT_BREAKS))
{
return STATUS_UNSUCCESSFUL;
}
if (OldValue)
{
ZwQueryInformationThread(NtCurrentThread(),
ThreadBreakOnTermination,
&BreakOnTermination,
sizeof(ULONG),
NULL);
*OldValue = (BOOLEAN)BreakOnTermination;
}
BreakOnTermination = NewValue;
return ZwSetInformationThread(NtCurrentThread(),
ThreadBreakOnTermination,
&BreakOnTermination,
sizeof(ULONG));
}
@implemented
*/
NTSTATUS
NTAPI
RtlCreateUserThread(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;
Status = RtlpCreateUserStack(ProcessHandle,
StackReserve,
StackCommit,
StackZeroBits,
&InitialTeb);
if (!NT_SUCCESS(Status)) return Status;
RtlInitializeContext(ProcessHandle,
&Context,
Parameter,
StartAddress,
InitialTeb.StackBase);
InitializeObjectAttributes(&ObjectAttributes,
NULL,
0,
NULL,
SecurityDescriptor);
Status = ZwCreateThread(&Handle,
THREAD_ALL_ACCESS,
&ObjectAttributes,
ProcessHandle,
&ThreadCid,
&Context,
&InitialTeb,
CreateSuspended);
if (!NT_SUCCESS(Status))
{
RtlpFreeUserStack(ProcessHandle, &InitialTeb);
}
else
{
if (ThreadHandle)
*ThreadHandle = Handle;
else
NtClose(Handle);
if (ClientId) *ClientId = ThreadCid;
}
return Status;
}
* @implemented
*/
VOID
NTAPI
RtlExitUserThread(NTSTATUS Status)
{
LdrShutdownThread();
#if (NTDDI_VERSION < NTDDI_LONGHORN)
NtCurrentTeb()->FreeStackOnTermination = TRUE;
#endif
NtTerminateThread(NtCurrentThread(), Status);
}
@implemented
*/
VOID
NTAPI
RtlFreeUserThreadStack(HANDLE ProcessHandle,
HANDLE ThreadHandle)
{
NTSTATUS Status;
THREAD_BASIC_INFORMATION ThreadBasicInfo;
SIZE_T Dummy, Size = 0;
PVOID StackLocation;
Status = NtQueryInformationThread(ThreadHandle,
ThreadBasicInformation,
&ThreadBasicInfo,
sizeof(THREAD_BASIC_INFORMATION),
NULL);
if (!NT_SUCCESS(Status) || !ThreadBasicInfo.TebBaseAddress) return;
Status = NtReadVirtualMemory(ProcessHandle,
&((PTEB)ThreadBasicInfo.TebBaseAddress)->
DeallocationStack,
&StackLocation,
sizeof(PVOID),
&Dummy);
if (!NT_SUCCESS(Status) || !StackLocation) return;
NtFreeVirtualMemory(ProcessHandle, &StackLocation, &Size, MEM_RELEASE);
}
PTEB
NTAPI
_NtCurrentTeb(VOID)
{
return NtCurrentTeb();
}
NTSTATUS
NTAPI
RtlRemoteCall(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;
}