0eef3e50477b6b999e9f677291c8fd192ce34f67
[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 ReserveSize;
44 ULONG CommitSize;
45 ULONG GuardSize;
46 ULONG RegionSize;
47 NTSTATUS Status;
48
49 /* initialize initial teb */
50 if ((StackCommit != NULL) && (*StackCommit > PAGESIZE))
51 CommitSize = *StackCommit;
52 else
53 CommitSize = PAGESIZE;
54
55 if ((StackReserve != NULL) && (*StackReserve > 0x100000))
56 ReserveSize = *StackReserve;
57 else
58 ReserveSize = 0x100000; /* 1MByte */
59
60 GuardSize = PAGESIZE;
61
62 RegionSize = 0;
63
64 /* Reserve stack */
65 InitialTeb.StackReserve = NULL;
66 Status = NtAllocateVirtualMemory(ProcessHandle,
67 &InitialTeb.StackReserve,
68 0,
69 &ReserveSize,
70 MEM_RESERVE,
71 PAGE_READWRITE);
72
73 if (!NT_SUCCESS(Status))
74 {
75 DPRINT("Error reserving stack space!\n");
76 return Status;
77 }
78
79 DPRINT("StackReserved: %p ReservedSize: 0x%lx\n",
80 InitialTeb.StackReserve, ReserveSize);
81
82 InitialTeb.StackBase = (PVOID)(InitialTeb.StackReserve + ReserveSize);
83 InitialTeb.StackCommit = (PVOID)(InitialTeb.StackBase - CommitSize);
84 InitialTeb.StackLimit = (PVOID)(InitialTeb.StackCommit - PAGESIZE);
85 InitialTeb.StackCommitMax = (PVOID)(InitialTeb.StackReserve + PAGESIZE);
86
87 DPRINT("StackBase: %p\n",
88 InitialTeb.StackBase);
89
90 /* Commit stack page */
91 Status = NtAllocateVirtualMemory(ProcessHandle,
92 &InitialTeb.StackCommit,
93 0,
94 &CommitSize,
95 MEM_COMMIT,
96 PAGE_READWRITE);
97
98 if (!NT_SUCCESS(Status))
99 {
100 /* release the stack space */
101 NtFreeVirtualMemory(ProcessHandle,
102 InitialTeb.StackReserve,
103 &RegionSize,
104 MEM_RELEASE);
105
106 DPRINT("Error comitting stack page!\n");
107 return Status;
108 }
109
110 DPRINT("StackCommit: %p CommitSize: 0x%lx\n",
111 InitialTeb.StackCommit, CommitSize);
112
113 /* Commit guard page */
114 Status = NtAllocateVirtualMemory(ProcessHandle,
115 &InitialTeb.StackLimit,
116 0,
117 &GuardSize,
118 MEM_COMMIT,
119 PAGE_GUARD);
120
121 if (!NT_SUCCESS(Status))
122 {
123 /* release the stack space */
124 NtFreeVirtualMemory(ProcessHandle,
125 InitialTeb.StackReserve,
126 &RegionSize,
127 MEM_RELEASE);
128
129 DPRINT("Error comitting guard page!\n");
130 return Status;
131 }
132
133 DPRINT("StackLimit: %p GuardSize: 0x%lx\n",
134 InitialTeb.StackLimit, GuardSize);
135
136 /* initialize thread context */
137 RtlInitializeContext (ProcessHandle,
138 &ThreadContext,
139 Parameter,
140 StartAddress,
141 &InitialTeb);
142
143 /* create the thread */
144 ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES);
145 ObjectAttributes.RootDirectory = NULL;
146 ObjectAttributes.ObjectName = NULL;
147 // ObjectAttributes.Attributes = 0;
148 ObjectAttributes.Attributes = OBJ_INHERIT;
149 ObjectAttributes.SecurityDescriptor = SecurityDescriptor;
150 ObjectAttributes.SecurityQualityOfService = NULL;
151
152 Status = NtCreateThread(&LocalThreadHandle,
153 THREAD_ALL_ACCESS,
154 &ObjectAttributes,
155 ProcessHandle,
156 &LocalClientId,
157 &ThreadContext,
158 &InitialTeb,
159 CreateSuspended);
160
161 if (!NT_SUCCESS(Status))
162 {
163 /* release the stack space */
164 NtFreeVirtualMemory(ProcessHandle,
165 InitialTeb.StackReserve,
166 &RegionSize,
167 MEM_RELEASE);
168
169 DPRINT("Error creating thread!\n");
170 return Status;
171 }
172
173 /* return committed stack size */
174 if (StackCommit)
175 *StackCommit = CommitSize;
176
177 /* return reserved stack size */
178 if (StackReserve)
179 *StackReserve = ReserveSize;
180
181 /* return thread handle */
182 if (ThreadHandle)
183 *ThreadHandle = LocalThreadHandle;
184
185 /* return client id */
186 if (ClientId)
187 {
188 ClientId->UniqueProcess = LocalClientId.UniqueProcess;
189 ClientId->UniqueThread = LocalClientId.UniqueThread;
190 }
191
192 return Status;
193 }
194
195
196 NTSTATUS STDCALL
197 RtlInitializeContext(HANDLE ProcessHandle,
198 PCONTEXT Context,
199 PVOID Parameter,
200 PTHREAD_START_ROUTINE StartAddress,
201 PINITIAL_TEB InitialTeb)
202 {
203 ULONG Buffer[2];
204 ULONG BytesWritten;
205 NTSTATUS Status;
206
207 memset (Context, 0, sizeof(CONTEXT));
208
209 Context->Eip = (LONG)StartAddress;
210 Context->SegGs = USER_DS;
211 Context->SegFs = TEB_SELECTOR;
212 Context->SegEs = USER_DS;
213 Context->SegDs = USER_DS;
214 Context->SegCs = USER_CS;
215 Context->SegSs = USER_DS;
216 Context->Esp = (ULONG)InitialTeb->StackBase - 8;
217 Context->EFlags = (1<<1) + (1<<9);
218
219 /* prepare the thread stack for execution */
220 if (ProcessHandle == NtCurrentProcess())
221 {
222 *((PULONG)(InitialTeb->StackBase - 4)) = (ULONG)Parameter;
223 *((PULONG)(InitialTeb->StackBase - 8)) = 0xdeadbeef;
224 }
225 else
226 {
227 Buffer[0] = (ULONG)Parameter;
228 Buffer[1] = 0xdeadbeef;
229
230 Status = NtWriteVirtualMemory(ProcessHandle,
231 (PVOID)(InitialTeb->StackBase - 4),
232 Buffer,
233 2 * sizeof(ULONG),
234 &BytesWritten);
235 return Status;
236 }
237
238 return STATUS_SUCCESS;
239 }
240
241
242 NTSTATUS STDCALL
243 RtlFreeUserThreadStack (HANDLE ProcessHandle, HANDLE ThreadHandle)
244 {
245 THREAD_BASIC_INFORMATION ThreadInfo;
246 NTSTATUS Status;
247 ULONG BytesRead;
248 ULONG RegionSize;
249 PVOID StackBase;
250 PNT_TEB Teb;
251
252 Status = NtQueryInformationThread (ThreadHandle,
253 ThreadBasicInformation,
254 &ThreadInfo,
255 sizeof(THREAD_BASIC_INFORMATION),
256 NULL);
257 if (!NT_SUCCESS(Status))
258 return Status;
259
260 if (ThreadInfo.TebBaseAddress == NULL)
261 return Status;
262
263 Teb = (PNT_TEB)ThreadInfo.TebBaseAddress;
264 Status = NtReadVirtualMemory (ProcessHandle,
265 &Teb->DeallocationStack,
266 &StackBase,
267 sizeof(PVOID),
268 &BytesRead);
269 if (!NT_SUCCESS(Status))
270 return Status;
271
272 if (StackBase == NULL)
273 return Status;
274
275 RegionSize = 0;
276 Status = NtFreeVirtualMemory (ProcessHandle,
277 StackBase,
278 &RegionSize,
279 MEM_RELEASE);
280
281 return Status;
282 }
283
284 /* EOF */