1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS system libraries 4 * PURPOSE: Rtl user thread functions 5 * FILE: lib/rtl/thread.c 6 * PROGRAMERS: 7 * Alex Ionescu (alex@relsoft.net) 8 * Eric Kohl 9 * KJK::Hyperion 10 */ 11 12 /* INCLUDES *****************************************************************/ 13 14 #include <rtl.h> 15 16 #define NDEBUG 17 #include <debug.h> 18 19 /* PRIVATE FUNCTIONS *******************************************************/ 20 21 NTSTATUS 22 NTAPI 23 RtlpCreateUserStack(IN HANDLE hProcess, 24 IN SIZE_T StackReserve OPTIONAL, 25 IN SIZE_T StackCommit OPTIONAL, 26 IN ULONG StackZeroBits OPTIONAL, 27 OUT PINITIAL_TEB InitialTeb) 28 { 29 NTSTATUS Status; 30 SYSTEM_BASIC_INFORMATION SystemBasicInfo; 31 PIMAGE_NT_HEADERS Headers; 32 ULONG_PTR Stack = 0; 33 BOOLEAN UseGuard = FALSE; 34 ULONG Dummy; 35 SIZE_T GuardPageSize; 36 37 /* Get some memory information */ 38 Status = ZwQuerySystemInformation(SystemBasicInformation, 39 &SystemBasicInfo, 40 sizeof(SYSTEM_BASIC_INFORMATION), 41 NULL); 42 if (!NT_SUCCESS(Status)) return Status; 43 44 /* Use the Image Settings if we are dealing with the current Process */ 45 if (hProcess == NtCurrentProcess()) 46 { 47 /* Get the Image Headers */ 48 Headers = RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress); 49 if (!Headers) return STATUS_INVALID_IMAGE_FORMAT; 50 51 /* If we didn't get the parameters, find them ourselves */ 52 if (!StackReserve) StackReserve = Headers->OptionalHeader. 53 SizeOfStackReserve; 54 if (!StackCommit) StackCommit = Headers->OptionalHeader. 55 SizeOfStackCommit; 56 } 57 else 58 { 59 /* Use the System Settings if needed */ 60 if (!StackReserve) StackReserve = SystemBasicInfo.AllocationGranularity; 61 if (!StackCommit) StackCommit = SystemBasicInfo.PageSize; 62 } 63 64 /* Check if the commit is higher than the reserve*/ 65 if (StackCommit >= StackReserve) 66 { 67 /* Grow the reserve beyond the commit, up to 1MB alignment */ 68 StackReserve = ROUND_UP(StackCommit, 1024 * 1024); 69 } 70 71 /* Align everything to Page Size */ 72 StackReserve = ROUND_UP(StackReserve, SystemBasicInfo.AllocationGranularity); 73 StackCommit = ROUND_UP(StackCommit, SystemBasicInfo.PageSize); 74 75 /* Reserve memory for the stack */ 76 Status = ZwAllocateVirtualMemory(hProcess, 77 (PVOID*)&Stack, 78 StackZeroBits, 79 &StackReserve, 80 MEM_RESERVE, 81 PAGE_READWRITE); 82 if (!NT_SUCCESS(Status)) return Status; 83 84 /* Now set up some basic Initial TEB Parameters */ 85 InitialTeb->PreviousStackBase = NULL; 86 InitialTeb->PreviousStackLimit = NULL; 87 InitialTeb->AllocatedStackBase = (PVOID)Stack; 88 InitialTeb->StackBase = (PVOID)(Stack + StackReserve); 89 90 /* Update the Stack Position */ 91 Stack += StackReserve - StackCommit; 92 93 /* Check if we will need a guard page */ 94 if (StackReserve > StackCommit) 95 { 96 /* Remove a page to set as guard page */ 97 Stack -= SystemBasicInfo.PageSize; 98 StackCommit += SystemBasicInfo.PageSize; 99 UseGuard = TRUE; 100 } 101 102 /* Allocate memory for the stack */ 103 Status = ZwAllocateVirtualMemory(hProcess, 104 (PVOID*)&Stack, 105 0, 106 &StackCommit, 107 MEM_COMMIT, 108 PAGE_READWRITE); 109 if (!NT_SUCCESS(Status)) return Status; 110 111 /* Now set the current Stack Limit */ 112 InitialTeb->StackLimit = (PVOID)Stack; 113 114 /* Create a guard page */ 115 if (UseGuard) 116 { 117 /* Attempt maximum space possible */ 118 GuardPageSize = SystemBasicInfo.PageSize; 119 Status = ZwProtectVirtualMemory(hProcess, 120 (PVOID*)&Stack, 121 &GuardPageSize, 122 PAGE_GUARD | PAGE_READWRITE, 123 &Dummy); 124 if (!NT_SUCCESS(Status)) return Status; 125 126 /* Update the Stack Limit keeping in mind the Guard Page */ 127 InitialTeb->StackLimit = (PVOID)((ULONG_PTR)InitialTeb->StackLimit + 128 GuardPageSize); 129 } 130 131 /* We are done! */ 132 return STATUS_SUCCESS; 133 } 134 135 NTSTATUS 136 NTAPI 137 RtlpFreeUserStack(IN HANDLE Process, 138 IN PINITIAL_TEB InitialTeb) 139 { 140 SIZE_T Dummy = 0; 141 NTSTATUS Status; 142 143 /* Free the Stack */ 144 Status = ZwFreeVirtualMemory(Process, 145 &InitialTeb->AllocatedStackBase, 146 &Dummy, 147 MEM_RELEASE); 148 149 /* Clear the initial TEB */ 150 RtlZeroMemory(InitialTeb, sizeof(INITIAL_TEB)); 151 return Status; 152 } 153 154 /* FUNCTIONS ***************************************************************/ 155 156 157 /* 158 * @implemented 159 */ 160 NTSTATUS 161 __cdecl 162 RtlSetThreadIsCritical(IN BOOLEAN NewValue, 163 OUT PBOOLEAN OldValue OPTIONAL, 164 IN BOOLEAN NeedBreaks) 165 { 166 ULONG BreakOnTermination; 167 168 /* Initialize to FALSE */ 169 if (OldValue) *OldValue = FALSE; 170 171 /* Fail, if the critical breaks flag is required but is not set */ 172 if ((NeedBreaks) && 173 !(NtCurrentPeb()->NtGlobalFlag & FLG_ENABLE_SYSTEM_CRIT_BREAKS)) 174 { 175 return STATUS_UNSUCCESSFUL; 176 } 177 178 /* Check if the caller wants the old value */ 179 if (OldValue) 180 { 181 /* Query and return the old break on termination flag for the process */ 182 ZwQueryInformationThread(NtCurrentThread(), 183 ThreadBreakOnTermination, 184 &BreakOnTermination, 185 sizeof(ULONG), 186 NULL); 187 *OldValue = (BOOLEAN)BreakOnTermination; 188 } 189 190 /* Set the break on termination flag for the process */ 191 BreakOnTermination = NewValue; 192 return ZwSetInformationThread(NtCurrentThread(), 193 ThreadBreakOnTermination, 194 &BreakOnTermination, 195 sizeof(ULONG)); 196 } 197 198 /* 199 @implemented 200 */ 201 NTSTATUS 202 NTAPI 203 RtlCreateUserThread(IN HANDLE ProcessHandle, 204 IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL, 205 IN BOOLEAN CreateSuspended, 206 IN ULONG StackZeroBits OPTIONAL, 207 IN SIZE_T StackReserve OPTIONAL, 208 IN SIZE_T StackCommit OPTIONAL, 209 IN PTHREAD_START_ROUTINE StartAddress, 210 IN PVOID Parameter OPTIONAL, 211 OUT PHANDLE ThreadHandle OPTIONAL, 212 OUT PCLIENT_ID ClientId OPTIONAL) 213 { 214 NTSTATUS Status; 215 HANDLE Handle; 216 CLIENT_ID ThreadCid; 217 INITIAL_TEB InitialTeb; 218 OBJECT_ATTRIBUTES ObjectAttributes; 219 CONTEXT Context; 220 221 /* First, we'll create the Stack */ 222 Status = RtlpCreateUserStack(ProcessHandle, 223 StackReserve, 224 StackCommit, 225 StackZeroBits, 226 &InitialTeb); 227 if (!NT_SUCCESS(Status)) return Status; 228 229 /* Next, we'll set up the Initial Context */ 230 RtlInitializeContext(ProcessHandle, 231 &Context, 232 Parameter, 233 StartAddress, 234 InitialTeb.StackBase); 235 236 /* We are now ready to create the Kernel Thread Object */ 237 InitializeObjectAttributes(&ObjectAttributes, 238 NULL, 239 0, 240 NULL, 241 SecurityDescriptor); 242 Status = ZwCreateThread(&Handle, 243 THREAD_ALL_ACCESS, 244 &ObjectAttributes, 245 ProcessHandle, 246 &ThreadCid, 247 &Context, 248 &InitialTeb, 249 CreateSuspended); 250 if (!NT_SUCCESS(Status)) 251 { 252 /* Free the stack */ 253 RtlpFreeUserStack(ProcessHandle, &InitialTeb); 254 } 255 else 256 { 257 /* Return thread data */ 258 if (ThreadHandle) 259 *ThreadHandle = Handle; 260 else 261 NtClose(Handle); 262 if (ClientId) *ClientId = ThreadCid; 263 } 264 265 /* Return success or the previous failure */ 266 return Status; 267 } 268 269 /* 270 * @implemented 271 */ 272 VOID 273 NTAPI 274 RtlExitUserThread(NTSTATUS Status) 275 { 276 /* Call the Loader and tell him to notify the DLLs */ 277 LdrShutdownThread(); 278 279 /* Shut us down */ 280 NtCurrentTeb()->FreeStackOnTermination = TRUE; 281 NtTerminateThread(NtCurrentThread(), Status); 282 } 283 284 /* 285 @implemented 286 */ 287 VOID 288 NTAPI 289 RtlFreeUserThreadStack(HANDLE ProcessHandle, 290 HANDLE ThreadHandle) 291 { 292 NTSTATUS Status; 293 THREAD_BASIC_INFORMATION ThreadBasicInfo; 294 SIZE_T Dummy, Size = 0; 295 PVOID StackLocation; 296 297 /* Query the Basic Info */ 298 Status = NtQueryInformationThread(ThreadHandle, 299 ThreadBasicInformation, 300 &ThreadBasicInfo, 301 sizeof(THREAD_BASIC_INFORMATION), 302 NULL); 303 if (!NT_SUCCESS(Status) || !ThreadBasicInfo.TebBaseAddress) return; 304 305 /* Get the deallocation stack */ 306 Status = NtReadVirtualMemory(ProcessHandle, 307 &((PTEB)ThreadBasicInfo.TebBaseAddress)-> 308 DeallocationStack, 309 &StackLocation, 310 sizeof(PVOID), 311 &Dummy); 312 if (!NT_SUCCESS(Status) || !StackLocation) return; 313 314 /* Free it */ 315 NtFreeVirtualMemory(ProcessHandle, &StackLocation, &Size, MEM_RELEASE); 316 } 317 318 PTEB 319 NTAPI 320 _NtCurrentTeb(VOID) 321 { 322 /* Return the TEB */ 323 return NtCurrentTeb(); 324 } 325 326 NTSTATUS 327 NTAPI 328 RtlRemoteCall(IN HANDLE Process, 329 IN HANDLE Thread, 330 IN PVOID CallSite, 331 IN ULONG ArgumentCount, 332 IN PULONG Arguments, 333 IN BOOLEAN PassContext, 334 IN BOOLEAN AlreadySuspended) 335 { 336 UNIMPLEMENTED; 337 return STATUS_NOT_IMPLEMENTED; 338 } 339