Rewrote stack allocation.
[reactos.git] / reactos / lib / ntdll / rtl / thread.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Rtl user thread functions
5 * FILE: lib/ntdll/rtl/thread.c
6 * PROGRAMER: Eric Kohl
7 * REVISION HISTORY:
8 * 09/07/99: Created
9 * 09/10/99: Cleanup and full stack support.
10 */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <ddk/ntddk.h>
15 #include <napi/i386/segment.h>
16 #include <napi/teb.h>
17 #include <ntdll/rtl.h>
18
19 #define NDEBUG
20 #include <ntdll/ntdll.h>
21
22
23 /* FUNCTIONS ***************************************************************/
24
25
26 NTSTATUS STDCALL
27 RtlCreateUserThread(HANDLE ProcessHandle,
28 PSECURITY_DESCRIPTOR SecurityDescriptor,
29 BOOLEAN CreateSuspended,
30 LONG StackZeroBits,
31 PULONG StackReserve,
32 PULONG StackCommit,
33 PTHREAD_START_ROUTINE StartAddress,
34 PVOID Parameter,
35 PHANDLE ThreadHandle,
36 PCLIENT_ID ClientId)
37 {
38 HANDLE LocalThreadHandle;
39 CLIENT_ID LocalClientId;
40 OBJECT_ATTRIBUTES ObjectAttributes;
41 INITIAL_TEB InitialTeb;
42 CONTEXT ThreadContext;
43 ULONG OldPageProtection;
44 NTSTATUS Status;
45
46 /* initialize initial teb */
47 if ((StackCommit != NULL) && (*StackCommit > PAGESIZE))
48 InitialTeb.StackCommit = *StackCommit;
49 else
50 InitialTeb.StackCommit = PAGESIZE;
51
52 if ((StackReserve != NULL) && (*StackReserve > 0x100000))
53 InitialTeb.StackReserve = *StackReserve;
54 else
55 InitialTeb.StackReserve = 0x100000; /* 1MByte */
56
57 /* add size of guard page */
58 InitialTeb.StackCommit += PAGESIZE;
59
60 /* Reserve stack */
61 InitialTeb.StackAllocate = NULL;
62 Status = NtAllocateVirtualMemory(ProcessHandle,
63 &InitialTeb.StackAllocate,
64 0,
65 &InitialTeb.StackReserve,
66 MEM_COMMIT, //MEM_RESERVE,
67 PAGE_READWRITE);
68 if (!NT_SUCCESS(Status))
69 {
70 DPRINT("Error reserving stack space!\n");
71 return Status;
72 }
73
74 DPRINT("StackAllocate: %p ReserveSize: 0x%lX\n",
75 InitialTeb.StackAllocate, InitialTeb.StackReserve);
76
77 InitialTeb.StackBase = (PVOID)((ULONG)InitialTeb.StackAllocate + InitialTeb.StackReserve);
78 InitialTeb.StackLimit = (PVOID)((ULONG)InitialTeb.StackBase - InitialTeb.StackCommit);
79
80 DPRINT("StackBase: %p StackCommit: 0x%lX\n",
81 InitialTeb.StackBase, InitialTeb.StackCommit);
82 #if 0
83 /* Commit stack */
84 Status = NtAllocateVirtualMemory(ProcessHandle,
85 &InitialTeb.StackLimit,
86 0,
87 &InitialTeb.StackCommit,
88 MEM_COMMIT,
89 PAGE_READWRITE);
90 if (!NT_SUCCESS(Status))
91 {
92 /* release the stack space */
93 NtFreeVirtualMemory(ProcessHandle,
94 InitialTeb.StackAllocate,
95 &InitialTeb.StackReserve,
96 MEM_RELEASE);
97
98 DPRINT("Error comitting stack page!\n");
99 return Status;
100 }
101
102 DPRINT("StackLimit: %p\nStackCommit: 0x%lX\n",
103 InitialTeb.StackLimit,
104 InitialTeb.StackCommit);
105
106 /* Protect guard page */
107 Status = NtProtectVirtualMemory(ProcessHandle,
108 InitialTeb.StackLimit,
109 PAGESIZE,
110 PAGE_GUARD | PAGE_READWRITE,
111 &OldPageProtection);
112 if (!NT_SUCCESS(Status))
113 {
114 /* release the stack space */
115 NtFreeVirtualMemory(ProcessHandle,
116 InitialTeb.StackAllocate,
117 &InitialTeb.StackReserve,
118 MEM_RELEASE);
119
120 DPRINT("Error protecting guard page!\n");
121 return(Status);
122 }
123 #endif
124 /* initialize thread context */
125 RtlInitializeContext (ProcessHandle,
126 &ThreadContext,
127 Parameter,
128 StartAddress,
129 &InitialTeb);
130
131 /* create the thread */
132 ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES);
133 ObjectAttributes.RootDirectory = NULL;
134 ObjectAttributes.ObjectName = NULL;
135 ObjectAttributes.Attributes = OBJ_INHERIT;
136 ObjectAttributes.SecurityDescriptor = SecurityDescriptor;
137 ObjectAttributes.SecurityQualityOfService = NULL;
138
139 Status = NtCreateThread(&LocalThreadHandle,
140 THREAD_ALL_ACCESS,
141 &ObjectAttributes,
142 ProcessHandle,
143 &LocalClientId,
144 &ThreadContext,
145 &InitialTeb,
146 CreateSuspended);
147
148 if (!NT_SUCCESS(Status))
149 {
150 /* release the stack space */
151 NtFreeVirtualMemory(ProcessHandle,
152 InitialTeb.StackAllocate,
153 &InitialTeb.StackReserve,
154 MEM_RELEASE);
155
156 DPRINT("Error creating thread!\n");
157 return Status;
158 }
159
160 /* return committed stack size */
161 if (StackCommit)
162 *StackCommit = InitialTeb.StackCommit;
163
164 /* return reserved stack size */
165 if (StackReserve)
166 *StackReserve = InitialTeb.StackReserve;
167
168 /* return thread handle */
169 if (ThreadHandle)
170 *ThreadHandle = LocalThreadHandle;
171
172 /* return client id */
173 if (ClientId)
174 {
175 ClientId->UniqueProcess = LocalClientId.UniqueProcess;
176 ClientId->UniqueThread = LocalClientId.UniqueThread;
177 }
178
179 return(STATUS_SUCCESS);
180 }
181
182
183 NTSTATUS STDCALL
184 RtlInitializeContext(HANDLE ProcessHandle,
185 PCONTEXT Context,
186 PVOID Parameter,
187 PTHREAD_START_ROUTINE StartAddress,
188 PINITIAL_TEB InitialTeb)
189 {
190 ULONG Buffer[2];
191 ULONG BytesWritten;
192 NTSTATUS Status;
193
194 memset (Context, 0, sizeof(CONTEXT));
195 Context->Eip = (LONG)StartAddress;
196 Context->SegGs = USER_DS;
197 Context->SegFs = TEB_SELECTOR;
198 Context->SegEs = USER_DS;
199 Context->SegDs = USER_DS;
200 Context->SegCs = USER_CS;
201 Context->SegSs = USER_DS;
202 Context->Esp = (ULONG)InitialTeb->StackBase - 8;
203 Context->EFlags = (1<<1) + (1<<9);
204
205 /* prepare the thread stack for execution */
206 if (ProcessHandle == NtCurrentProcess())
207 {
208 *((PULONG)(InitialTeb->StackBase - 4)) = (ULONG)Parameter;
209 *((PULONG)(InitialTeb->StackBase - 8)) = 0xdeadbeef;
210 }
211 else
212 {
213 Buffer[0] = (ULONG)Parameter;
214 Buffer[1] = 0xdeadbeef;
215
216 Status = NtWriteVirtualMemory(ProcessHandle,
217 (PVOID)((ULONG)InitialTeb->StackBase - 8),
218 Buffer,
219 2 * sizeof(ULONG),
220 &BytesWritten);
221 return Status;
222 }
223
224 return STATUS_SUCCESS;
225 }
226
227
228 NTSTATUS STDCALL
229 RtlFreeUserThreadStack(HANDLE ProcessHandle,
230 HANDLE ThreadHandle)
231 {
232 THREAD_BASIC_INFORMATION ThreadInfo;
233 NTSTATUS Status;
234 ULONG BytesRead;
235 ULONG RegionSize;
236 PVOID StackBase;
237 PTEB Teb;
238
239 Status = NtQueryInformationThread(ThreadHandle,
240 ThreadBasicInformation,
241 &ThreadInfo,
242 sizeof(THREAD_BASIC_INFORMATION),
243 NULL);
244 if (!NT_SUCCESS(Status))
245 return(Status);
246
247 if (ThreadInfo.TebBaseAddress == NULL)
248 return(Status);
249
250 Teb = (PTEB)ThreadInfo.TebBaseAddress;
251 Status = NtReadVirtualMemory(ProcessHandle,
252 &Teb->DeallocationStack,
253 &StackBase,
254 sizeof(PVOID),
255 &BytesRead);
256 if (!NT_SUCCESS(Status))
257 return(Status);
258
259 if (StackBase == NULL)
260 return(Status);
261
262 RegionSize = 0;
263 Status = NtFreeVirtualMemory(ProcessHandle,
264 StackBase,
265 &RegionSize,
266 MEM_RELEASE);
267 return(Status);
268 }
269
270 /* EOF */