- Remove deprecated CHECKPOINT/CHECKPOINT1 macros which basically translated into...
[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, GuardPageSize;
35
36 /* Get some memory information */
37 Status = ZwQuerySystemInformation(SystemBasicInformation,
38 &SystemBasicInfo,
39 sizeof(SYSTEM_BASIC_INFORMATION),
40 NULL);
41 if (!NT_SUCCESS(Status)) return Status;
42
43 /* Use the Image Settings if we are dealing with the current Process */
44 if (hProcess == NtCurrentProcess())
45 {
46 /* Get the Image Headers */
47 Headers = RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress);
48
49 /* If we didn't get the parameters, find them ourselves */
50 if (!StackReserve) StackReserve = Headers->OptionalHeader.
51 SizeOfStackReserve;
52 if (!StackCommit) StackCommit = Headers->OptionalHeader.
53 SizeOfStackCommit;
54 }
55 else
56 {
57 /* Use the System Settings if needed */
58 if (!StackReserve) StackReserve = SystemBasicInfo.AllocationGranularity;
59 if (!StackCommit) StackCommit = SystemBasicInfo.PageSize;
60 }
61
62 /* Align everything to Page Size */
63 StackReserve = ROUND_UP(StackReserve, SystemBasicInfo.AllocationGranularity);
64 StackCommit = ROUND_UP(StackCommit, SystemBasicInfo.PageSize);
65
66 // FIXME: Remove once Guard Page support is here
67 #if 1
68 StackCommit = StackReserve;
69 #endif
70
71 /* Reserve memory for the stack */
72 Status = ZwAllocateVirtualMemory(hProcess,
73 (PVOID*)&Stack,
74 StackZeroBits,
75 &StackReserve,
76 MEM_RESERVE,
77 PAGE_READWRITE);
78 if (!NT_SUCCESS(Status)) return Status;
79
80 /* Now set up some basic Initial TEB Parameters */
81 InitialTeb->PreviousStackBase = NULL;
82 InitialTeb->PreviousStackLimit = NULL;
83 InitialTeb->AllocatedStackBase = (PVOID)Stack;
84 InitialTeb->StackBase = (PVOID)(Stack + StackReserve);
85
86 /* Update the Stack Position */
87 Stack += StackReserve - StackCommit;
88
89 /* Check if we will need a guard page */
90 if (StackReserve > StackCommit)
91 {
92 /* Remove a page to set as guard page */
93 Stack -= SystemBasicInfo.PageSize;
94 StackCommit += SystemBasicInfo.PageSize;
95 UseGuard = TRUE;
96 }
97
98 /* Allocate memory for the stack */
99 Status = ZwAllocateVirtualMemory(hProcess,
100 (PVOID*)&Stack,
101 0,
102 &StackCommit,
103 MEM_COMMIT,
104 PAGE_READWRITE);
105 if (!NT_SUCCESS(Status)) return Status;
106
107 /* Now set the current Stack Limit */
108 InitialTeb->StackLimit = (PVOID)Stack;
109
110 /* Create a guard page */
111 if (UseGuard)
112 {
113 /* Attempt maximum space possible */
114 GuardPageSize = SystemBasicInfo.PageSize;
115 Status = ZwProtectVirtualMemory(hProcess,
116 (PVOID*)&Stack,
117 &GuardPageSize,
118 PAGE_GUARD | PAGE_READWRITE,
119 &Dummy);
120 if (!NT_SUCCESS(Status)) return Status;
121
122 /* Update the Stack Limit keeping in mind the Guard Page */
123 InitialTeb->StackLimit = (PVOID)((ULONG_PTR)InitialTeb->StackLimit -
124 GuardPageSize);
125 }
126
127 /* We are done! */
128 return STATUS_SUCCESS;
129 }
130
131 NTSTATUS
132 NTAPI
133 RtlpFreeUserStack(IN HANDLE Process,
134 IN PINITIAL_TEB InitialTeb)
135 {
136 SIZE_T Dummy = 0;
137 NTSTATUS Status;
138
139 /* Free the Stack */
140 Status = ZwFreeVirtualMemory(Process,
141 &InitialTeb->AllocatedStackBase,
142 &Dummy,
143 MEM_RELEASE);
144
145 /* Clear the initial TEB */
146 RtlZeroMemory(InitialTeb, sizeof(INITIAL_TEB));
147 return Status;
148 }
149
150 /* FUNCTIONS ***************************************************************/
151
152 /*
153 @implemented
154 */
155 NTSTATUS
156 NTAPI
157 RtlCreateUserThread(IN HANDLE ProcessHandle,
158 IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL,
159 IN BOOLEAN CreateSuspended,
160 IN ULONG StackZeroBits OPTIONAL,
161 IN SIZE_T StackReserve OPTIONAL,
162 IN SIZE_T StackCommit OPTIONAL,
163 IN PTHREAD_START_ROUTINE StartAddress,
164 IN PVOID Parameter OPTIONAL,
165 OUT PHANDLE ThreadHandle OPTIONAL,
166 OUT PCLIENT_ID ClientId OPTIONAL)
167 {
168 NTSTATUS Status;
169 HANDLE Handle;
170 CLIENT_ID ThreadCid;
171 INITIAL_TEB InitialTeb;
172 OBJECT_ATTRIBUTES ObjectAttributes;
173 CONTEXT Context;
174
175 /* First, we'll create the Stack */
176 Status = RtlpCreateUserStack(ProcessHandle,
177 StackReserve,
178 StackCommit,
179 StackZeroBits,
180 &InitialTeb);
181 if (!NT_SUCCESS(Status)) return Status;
182
183 /* Next, we'll set up the Initial Context */
184 RtlInitializeContext(ProcessHandle,
185 &Context,
186 Parameter,
187 StartAddress,
188 InitialTeb.StackBase);
189
190 /* We are now ready to create the Kernel Thread Object */
191 InitializeObjectAttributes(&ObjectAttributes,
192 NULL,
193 0,
194 NULL,
195 SecurityDescriptor);
196 Status = ZwCreateThread(&Handle,
197 THREAD_ALL_ACCESS,
198 &ObjectAttributes,
199 ProcessHandle,
200 &ThreadCid,
201 &Context,
202 &InitialTeb,
203 CreateSuspended);
204 if (!NT_SUCCESS(Status))
205 {
206 /* Free the stack */
207 RtlpFreeUserStack(ProcessHandle, &InitialTeb);
208 }
209 else
210 {
211 /* Return thread data */
212 if (ThreadHandle)
213 *ThreadHandle = Handle;
214 else
215 NtClose(Handle);
216 if (ClientId) *ClientId = ThreadCid;
217 }
218
219 /* Return success or the previous failure */
220 return Status;
221 }
222
223 /*
224 * @implemented
225 */
226 VOID
227 NTAPI
228 RtlExitUserThread(NTSTATUS Status)
229 {
230 /* Call the Loader and tell him to notify the DLLs */
231 LdrShutdownThread();
232
233 /* Shut us down */
234 NtCurrentTeb()->FreeStackOnTermination = TRUE;
235 NtTerminateThread(NtCurrentThread(), Status);
236 }
237
238 /*
239 @implemented
240 */
241 VOID
242 NTAPI
243 RtlFreeUserThreadStack(HANDLE ProcessHandle,
244 HANDLE ThreadHandle)
245 {
246 NTSTATUS Status;
247 THREAD_BASIC_INFORMATION ThreadBasicInfo;
248 SIZE_T Dummy, Size = 0;
249 PVOID StackLocation;
250
251 /* Query the Basic Info */
252 Status = NtQueryInformationThread(ThreadHandle,
253 ThreadBasicInformation,
254 &ThreadBasicInfo,
255 sizeof(THREAD_BASIC_INFORMATION),
256 NULL);
257 if (!NT_SUCCESS(Status) || !ThreadBasicInfo.TebBaseAddress) return;
258
259 /* Get the deallocation stack */
260 Status = NtReadVirtualMemory(ProcessHandle,
261 &((PTEB)ThreadBasicInfo.TebBaseAddress)->
262 DeallocationStack,
263 &StackLocation,
264 sizeof(PVOID),
265 &Dummy);
266 if (!NT_SUCCESS(Status) || !StackLocation) return;
267
268 /* Free it */
269 NtFreeVirtualMemory(ProcessHandle, &StackLocation, &Size, MEM_RELEASE);
270 }
271
272 PTEB
273 NTAPI
274 _NtCurrentTeb(VOID)
275 {
276 /* Return the TEB */
277 return NtCurrentTeb();
278 }
279
280
281 /* EOF */