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