[KS]
[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 @implemented
155 */
156 NTSTATUS
157 NTAPI
158 RtlCreateUserThread(IN HANDLE ProcessHandle,
159 IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL,
160 IN BOOLEAN CreateSuspended,
161 IN ULONG StackZeroBits OPTIONAL,
162 IN SIZE_T StackReserve OPTIONAL,
163 IN SIZE_T StackCommit OPTIONAL,
164 IN PTHREAD_START_ROUTINE StartAddress,
165 IN PVOID Parameter OPTIONAL,
166 OUT PHANDLE ThreadHandle OPTIONAL,
167 OUT PCLIENT_ID ClientId OPTIONAL)
168 {
169 NTSTATUS Status;
170 HANDLE Handle;
171 CLIENT_ID ThreadCid;
172 INITIAL_TEB InitialTeb;
173 OBJECT_ATTRIBUTES ObjectAttributes;
174 CONTEXT Context;
175
176 /* First, we'll create the Stack */
177 Status = RtlpCreateUserStack(ProcessHandle,
178 StackReserve,
179 StackCommit,
180 StackZeroBits,
181 &InitialTeb);
182 if (!NT_SUCCESS(Status)) return Status;
183
184 /* Next, we'll set up the Initial Context */
185 RtlInitializeContext(ProcessHandle,
186 &Context,
187 Parameter,
188 StartAddress,
189 InitialTeb.StackBase);
190
191 /* We are now ready to create the Kernel Thread Object */
192 InitializeObjectAttributes(&ObjectAttributes,
193 NULL,
194 0,
195 NULL,
196 SecurityDescriptor);
197 Status = ZwCreateThread(&Handle,
198 THREAD_ALL_ACCESS,
199 &ObjectAttributes,
200 ProcessHandle,
201 &ThreadCid,
202 &Context,
203 &InitialTeb,
204 CreateSuspended);
205 if (!NT_SUCCESS(Status))
206 {
207 /* Free the stack */
208 RtlpFreeUserStack(ProcessHandle, &InitialTeb);
209 }
210 else
211 {
212 /* Return thread data */
213 if (ThreadHandle)
214 *ThreadHandle = Handle;
215 else
216 NtClose(Handle);
217 if (ClientId) *ClientId = ThreadCid;
218 }
219
220 /* Return success or the previous failure */
221 return Status;
222 }
223
224 /*
225 * @implemented
226 */
227 VOID
228 NTAPI
229 RtlExitUserThread(NTSTATUS Status)
230 {
231 /* Call the Loader and tell him to notify the DLLs */
232 LdrShutdownThread();
233
234 /* Shut us down */
235 NtCurrentTeb()->FreeStackOnTermination = TRUE;
236 NtTerminateThread(NtCurrentThread(), Status);
237 }
238
239 /*
240 @implemented
241 */
242 VOID
243 NTAPI
244 RtlFreeUserThreadStack(HANDLE ProcessHandle,
245 HANDLE ThreadHandle)
246 {
247 NTSTATUS Status;
248 THREAD_BASIC_INFORMATION ThreadBasicInfo;
249 SIZE_T Dummy, Size = 0;
250 PVOID StackLocation;
251
252 /* Query the Basic Info */
253 Status = NtQueryInformationThread(ThreadHandle,
254 ThreadBasicInformation,
255 &ThreadBasicInfo,
256 sizeof(THREAD_BASIC_INFORMATION),
257 NULL);
258 if (!NT_SUCCESS(Status) || !ThreadBasicInfo.TebBaseAddress) return;
259
260 /* Get the deallocation stack */
261 Status = NtReadVirtualMemory(ProcessHandle,
262 &((PTEB)ThreadBasicInfo.TebBaseAddress)->
263 DeallocationStack,
264 &StackLocation,
265 sizeof(PVOID),
266 &Dummy);
267 if (!NT_SUCCESS(Status) || !StackLocation) return;
268
269 /* Free it */
270 NtFreeVirtualMemory(ProcessHandle, &StackLocation, &Size, MEM_RELEASE);
271 }
272
273 PTEB
274 NTAPI
275 _NtCurrentTeb(VOID)
276 {
277 /* Return the TEB */
278 return NtCurrentTeb();
279 }
280
281 NTSTATUS
282 NTAPI
283 RtlRemoteCall(IN HANDLE Process,
284 IN HANDLE Thread,
285 IN PVOID CallSite,
286 IN ULONG ArgumentCount,
287 IN PULONG Arguments,
288 IN BOOLEAN PassContext,
289 IN BOOLEAN AlreadySuspended)
290 {
291 UNIMPLEMENTED;
292 return STATUS_NOT_IMPLEMENTED;
293 }