717cdb2e45c19b8775af08d8dc198bb5f167a8fe
[reactos.git] / reactos / lib / rtl / thread.c
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
50 /* If we didn't get the parameters, find them ourselves */
51 if (!StackReserve) StackReserve = Headers->OptionalHeader.
52 SizeOfStackReserve;
53 if (!StackCommit) StackCommit = Headers->OptionalHeader.
54 SizeOfStackCommit;
55 }
56 else
57 {
58 /* Use the System Settings if needed */
59 if (!StackReserve) StackReserve = SystemBasicInfo.AllocationGranularity;
60 if (!StackCommit) StackCommit = SystemBasicInfo.PageSize;
61 }
62
63 /* Align everything to Page Size */
64 StackReserve = ROUND_UP(StackReserve, SystemBasicInfo.AllocationGranularity);
65 StackCommit = ROUND_UP(StackCommit, SystemBasicInfo.PageSize);
66
67 // FIXME: Remove once Guard Page support is here
68 #if 1
69 StackCommit = StackReserve;
70 #endif
71
72 /* Reserve memory for the stack */
73 Status = ZwAllocateVirtualMemory(hProcess,
74 (PVOID*)&Stack,
75 StackZeroBits,
76 &StackReserve,
77 MEM_RESERVE,
78 PAGE_READWRITE);
79 if (!NT_SUCCESS(Status)) return Status;
80
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);
86
87 /* Update the Stack Position */
88 Stack += StackReserve - StackCommit;
89
90 /* Check if we will need a guard page */
91 if (StackReserve > StackCommit)
92 {
93 /* Remove a page to set as guard page */
94 Stack -= SystemBasicInfo.PageSize;
95 StackCommit += SystemBasicInfo.PageSize;
96 UseGuard = TRUE;
97 }
98
99 /* Allocate memory for the stack */
100 Status = ZwAllocateVirtualMemory(hProcess,
101 (PVOID*)&Stack,
102 0,
103 &StackCommit,
104 MEM_COMMIT,
105 PAGE_READWRITE);
106 if (!NT_SUCCESS(Status)) return Status;
107
108 /* Now set the current Stack Limit */
109 InitialTeb->StackLimit = (PVOID)Stack;
110
111 /* Create a guard page */
112 if (UseGuard)
113 {
114 /* Attempt maximum space possible */
115 GuardPageSize = SystemBasicInfo.PageSize;
116 Status = ZwProtectVirtualMemory(hProcess,
117 (PVOID*)&Stack,
118 &GuardPageSize,
119 PAGE_GUARD | PAGE_READWRITE,
120 &Dummy);
121 if (!NT_SUCCESS(Status)) return Status;
122
123 /* Update the Stack Limit keeping in mind the Guard Page */
124 InitialTeb->StackLimit = (PVOID)((ULONG_PTR)InitialTeb->StackLimit -
125 GuardPageSize);
126 }
127
128 /* We are done! */
129 return STATUS_SUCCESS;
130 }
131
132 NTSTATUS
133 NTAPI
134 RtlpFreeUserStack(IN HANDLE Process,
135 IN PINITIAL_TEB InitialTeb)
136 {
137 SIZE_T Dummy = 0;
138 NTSTATUS Status;
139
140 /* Free the Stack */
141 Status = ZwFreeVirtualMemory(Process,
142 &InitialTeb->AllocatedStackBase,
143 &Dummy,
144 MEM_RELEASE);
145
146 /* Clear the initial TEB */
147 RtlZeroMemory(InitialTeb, sizeof(INITIAL_TEB));
148 return Status;
149 }
150
151 /* FUNCTIONS ***************************************************************/
152
153
154 /*
155 * @implemented
156 */
157 NTSTATUS
158 NTAPI
159 RtlSetThreadIsCritical(IN BOOLEAN NewValue,
160 OUT PBOOLEAN OldValue OPTIONAL,
161 IN BOOLEAN NeedBreaks)
162 {
163 ULONG BreakOnTermination;
164
165 /* Initialize to FALSE */
166 if (OldValue) *OldValue = FALSE;
167
168 /* Fail, if the critical breaks flag is required but is not set */
169 if ((NeedBreaks) &&
170 !(NtCurrentPeb()->NtGlobalFlag & FLG_ENABLE_SYSTEM_CRIT_BREAKS))
171 {
172 return STATUS_UNSUCCESSFUL;
173 }
174
175 /* Check if the caller wants the old value */
176 if (OldValue)
177 {
178 /* Query and return the old break on termination flag for the process */
179 ZwQueryInformationThread(NtCurrentThread(),
180 ThreadBreakOnTermination,
181 &BreakOnTermination,
182 sizeof(ULONG),
183 NULL);
184 *OldValue = (BOOLEAN)BreakOnTermination;
185 }
186
187 /* Set the break on termination flag for the process */
188 BreakOnTermination = NewValue;
189 return ZwSetInformationThread(NtCurrentThread(),
190 ThreadBreakOnTermination,
191 &BreakOnTermination,
192 sizeof(ULONG));
193 }
194
195 /*
196 @implemented
197 */
198 NTSTATUS
199 NTAPI
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)
210 {
211 NTSTATUS Status;
212 HANDLE Handle;
213 CLIENT_ID ThreadCid;
214 INITIAL_TEB InitialTeb;
215 OBJECT_ATTRIBUTES ObjectAttributes;
216 CONTEXT Context;
217
218 /* First, we'll create the Stack */
219 Status = RtlpCreateUserStack(ProcessHandle,
220 StackReserve,
221 StackCommit,
222 StackZeroBits,
223 &InitialTeb);
224 if (!NT_SUCCESS(Status)) return Status;
225
226 /* Next, we'll set up the Initial Context */
227 RtlInitializeContext(ProcessHandle,
228 &Context,
229 Parameter,
230 StartAddress,
231 InitialTeb.StackBase);
232
233 /* We are now ready to create the Kernel Thread Object */
234 InitializeObjectAttributes(&ObjectAttributes,
235 NULL,
236 0,
237 NULL,
238 SecurityDescriptor);
239 Status = ZwCreateThread(&Handle,
240 THREAD_ALL_ACCESS,
241 &ObjectAttributes,
242 ProcessHandle,
243 &ThreadCid,
244 &Context,
245 &InitialTeb,
246 CreateSuspended);
247 if (!NT_SUCCESS(Status))
248 {
249 /* Free the stack */
250 RtlpFreeUserStack(ProcessHandle, &InitialTeb);
251 }
252 else
253 {
254 /* Return thread data */
255 if (ThreadHandle)
256 *ThreadHandle = Handle;
257 else
258 NtClose(Handle);
259 if (ClientId) *ClientId = ThreadCid;
260 }
261
262 /* Return success or the previous failure */
263 return Status;
264 }
265
266 /*
267 * @implemented
268 */
269 VOID
270 NTAPI
271 RtlExitUserThread(NTSTATUS Status)
272 {
273 /* Call the Loader and tell him to notify the DLLs */
274 LdrShutdownThread();
275
276 /* Shut us down */
277 NtCurrentTeb()->FreeStackOnTermination = TRUE;
278 NtTerminateThread(NtCurrentThread(), Status);
279 }
280
281 /*
282 @implemented
283 */
284 VOID
285 NTAPI
286 RtlFreeUserThreadStack(HANDLE ProcessHandle,
287 HANDLE ThreadHandle)
288 {
289 NTSTATUS Status;
290 THREAD_BASIC_INFORMATION ThreadBasicInfo;
291 SIZE_T Dummy, Size = 0;
292 PVOID StackLocation;
293
294 /* Query the Basic Info */
295 Status = NtQueryInformationThread(ThreadHandle,
296 ThreadBasicInformation,
297 &ThreadBasicInfo,
298 sizeof(THREAD_BASIC_INFORMATION),
299 NULL);
300 if (!NT_SUCCESS(Status) || !ThreadBasicInfo.TebBaseAddress) return;
301
302 /* Get the deallocation stack */
303 Status = NtReadVirtualMemory(ProcessHandle,
304 &((PTEB)ThreadBasicInfo.TebBaseAddress)->
305 DeallocationStack,
306 &StackLocation,
307 sizeof(PVOID),
308 &Dummy);
309 if (!NT_SUCCESS(Status) || !StackLocation) return;
310
311 /* Free it */
312 NtFreeVirtualMemory(ProcessHandle, &StackLocation, &Size, MEM_RELEASE);
313 }
314
315 PTEB
316 NTAPI
317 _NtCurrentTeb(VOID)
318 {
319 /* Return the TEB */
320 return NtCurrentTeb();
321 }
322
323 NTSTATUS
324 NTAPI
325 RtlRemoteCall(IN HANDLE Process,
326 IN HANDLE Thread,
327 IN PVOID CallSite,
328 IN ULONG ArgumentCount,
329 IN PULONG Arguments,
330 IN BOOLEAN PassContext,
331 IN BOOLEAN AlreadySuspended)
332 {
333 UNIMPLEMENTED;
334 return STATUS_NOT_IMPLEMENTED;
335 }