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
7 * Alex Ionescu (alex@relsoft.net)
12 /* INCLUDES *****************************************************************/
19 /* PRIVATE FUNCTIONS *******************************************************/
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
)
30 SYSTEM_BASIC_INFORMATION SystemBasicInfo
;
31 PIMAGE_NT_HEADERS Headers
;
33 BOOLEAN UseGuard
= FALSE
;
37 /* Get some memory information */
38 Status
= ZwQuerySystemInformation(SystemBasicInformation
,
40 sizeof(SYSTEM_BASIC_INFORMATION
),
42 if (!NT_SUCCESS(Status
)) return Status
;
44 /* Use the Image Settings if we are dealing with the current Process */
45 if (hProcess
== NtCurrentProcess())
47 /* Get the Image Headers */
48 Headers
= RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress
);
50 /* If we didn't get the parameters, find them ourselves */
51 if (!StackReserve
) StackReserve
= Headers
->OptionalHeader
.
53 if (!StackCommit
) StackCommit
= Headers
->OptionalHeader
.
58 /* Use the System Settings if needed */
59 if (!StackReserve
) StackReserve
= SystemBasicInfo
.AllocationGranularity
;
60 if (!StackCommit
) StackCommit
= SystemBasicInfo
.PageSize
;
63 /* Align everything to Page Size */
64 StackReserve
= ROUND_UP(StackReserve
, SystemBasicInfo
.AllocationGranularity
);
65 StackCommit
= ROUND_UP(StackCommit
, SystemBasicInfo
.PageSize
);
67 // FIXME: Remove once Guard Page support is here
69 StackCommit
= StackReserve
;
72 /* Reserve memory for the stack */
73 Status
= ZwAllocateVirtualMemory(hProcess
,
79 if (!NT_SUCCESS(Status
)) return Status
;
81 /* Now set up some basic Initial TEB Parameters */
82 InitialTeb
->PreviousStackBase
= NULL
;
83 InitialTeb
->PreviousStackLimit
= NULL
;
84 InitialTeb
->AllocatedStackBase
= (PVOID
)Stack
;
85 InitialTeb
->StackBase
= (PVOID
)(Stack
+ StackReserve
);
87 /* Update the Stack Position */
88 Stack
+= StackReserve
- StackCommit
;
90 /* Check if we will need a guard page */
91 if (StackReserve
> StackCommit
)
93 /* Remove a page to set as guard page */
94 Stack
-= SystemBasicInfo
.PageSize
;
95 StackCommit
+= SystemBasicInfo
.PageSize
;
99 /* Allocate memory for the stack */
100 Status
= ZwAllocateVirtualMemory(hProcess
,
106 if (!NT_SUCCESS(Status
)) return Status
;
108 /* Now set the current Stack Limit */
109 InitialTeb
->StackLimit
= (PVOID
)Stack
;
111 /* Create a guard page */
114 /* Attempt maximum space possible */
115 GuardPageSize
= SystemBasicInfo
.PageSize
;
116 Status
= ZwProtectVirtualMemory(hProcess
,
119 PAGE_GUARD
| PAGE_READWRITE
,
121 if (!NT_SUCCESS(Status
)) return Status
;
123 /* Update the Stack Limit keeping in mind the Guard Page */
124 InitialTeb
->StackLimit
= (PVOID
)((ULONG_PTR
)InitialTeb
->StackLimit
-
129 return STATUS_SUCCESS
;
134 RtlpFreeUserStack(IN HANDLE Process
,
135 IN PINITIAL_TEB InitialTeb
)
141 Status
= ZwFreeVirtualMemory(Process
,
142 &InitialTeb
->AllocatedStackBase
,
146 /* Clear the initial TEB */
147 RtlZeroMemory(InitialTeb
, sizeof(INITIAL_TEB
));
151 /* FUNCTIONS ***************************************************************/
159 RtlSetThreadIsCritical(IN BOOLEAN NewValue
,
160 OUT PBOOLEAN OldValue OPTIONAL
,
161 IN BOOLEAN NeedBreaks
)
163 ULONG BreakOnTermination
;
165 /* Initialize to FALSE */
166 if (OldValue
) *OldValue
= FALSE
;
168 /* Fail, if the critical breaks flag is required but is not set */
170 !(NtCurrentPeb()->NtGlobalFlag
& FLG_ENABLE_SYSTEM_CRIT_BREAKS
))
172 return STATUS_UNSUCCESSFUL
;
175 /* Check if the caller wants the old value */
178 /* Query and return the old break on termination flag for the process */
179 ZwQueryInformationThread(NtCurrentThread(),
180 ThreadBreakOnTermination
,
184 *OldValue
= (BOOLEAN
)BreakOnTermination
;
187 /* Set the break on termination flag for the process */
188 BreakOnTermination
= NewValue
;
189 return ZwSetInformationThread(NtCurrentThread(),
190 ThreadBreakOnTermination
,
200 RtlCreateUserThread(IN HANDLE ProcessHandle
,
201 IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL
,
202 IN BOOLEAN CreateSuspended
,
203 IN ULONG StackZeroBits OPTIONAL
,
204 IN SIZE_T StackReserve OPTIONAL
,
205 IN SIZE_T StackCommit OPTIONAL
,
206 IN PTHREAD_START_ROUTINE StartAddress
,
207 IN PVOID Parameter OPTIONAL
,
208 OUT PHANDLE ThreadHandle OPTIONAL
,
209 OUT PCLIENT_ID ClientId OPTIONAL
)
214 INITIAL_TEB InitialTeb
;
215 OBJECT_ATTRIBUTES ObjectAttributes
;
218 /* First, we'll create the Stack */
219 Status
= RtlpCreateUserStack(ProcessHandle
,
224 if (!NT_SUCCESS(Status
)) return Status
;
226 /* Next, we'll set up the Initial Context */
227 RtlInitializeContext(ProcessHandle
,
231 InitialTeb
.StackBase
);
233 /* We are now ready to create the Kernel Thread Object */
234 InitializeObjectAttributes(&ObjectAttributes
,
239 Status
= ZwCreateThread(&Handle
,
247 if (!NT_SUCCESS(Status
))
250 RtlpFreeUserStack(ProcessHandle
, &InitialTeb
);
254 /* Return thread data */
256 *ThreadHandle
= Handle
;
259 if (ClientId
) *ClientId
= ThreadCid
;
262 /* Return success or the previous failure */
271 RtlExitUserThread(NTSTATUS Status
)
273 /* Call the Loader and tell him to notify the DLLs */
277 NtCurrentTeb()->FreeStackOnTermination
= TRUE
;
278 NtTerminateThread(NtCurrentThread(), Status
);
286 RtlFreeUserThreadStack(HANDLE ProcessHandle
,
290 THREAD_BASIC_INFORMATION ThreadBasicInfo
;
291 SIZE_T Dummy
, Size
= 0;
294 /* Query the Basic Info */
295 Status
= NtQueryInformationThread(ThreadHandle
,
296 ThreadBasicInformation
,
298 sizeof(THREAD_BASIC_INFORMATION
),
300 if (!NT_SUCCESS(Status
) || !ThreadBasicInfo
.TebBaseAddress
) return;
302 /* Get the deallocation stack */
303 Status
= NtReadVirtualMemory(ProcessHandle
,
304 &((PTEB
)ThreadBasicInfo
.TebBaseAddress
)->
309 if (!NT_SUCCESS(Status
) || !StackLocation
) return;
312 NtFreeVirtualMemory(ProcessHandle
, &StackLocation
, &Size
, MEM_RELEASE
);
320 return NtCurrentTeb();
325 RtlRemoteCall(IN HANDLE Process
,
328 IN ULONG ArgumentCount
,
330 IN BOOLEAN PassContext
,
331 IN BOOLEAN AlreadySuspended
)
334 return STATUS_NOT_IMPLEMENTED
;