Miscellaneous implementation of kernel32 stubs.
[reactos.git] / reactos / lib / kernel32 / thread / thread.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/kernel32/thread/thread.c
5 * PURPOSE: Thread functions
6 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
7 * Tls functions are modified from WINE
8 * UPDATE HISTORY:
9 * Created 01/11/98
10 */
11
12 /* INCLUDES ******************************************************************/
13
14 #include <windows.h>
15 #include <kernel32/thread.h>
16 #include <ddk/ntddk.h>
17 #include <string.h>
18 #include <internal/i386/segment.h>
19
20 //#define NDEBUG
21 #include <kernel32/kernel32.h>
22
23
24 /* FUNCTIONS *****************************************************************/
25
26 static VOID STDCALL
27 ThreadStartup (LPTHREAD_START_ROUTINE lpStartAddress,
28 LPVOID lpParameter)
29 {
30 UINT uExitCode;
31
32 uExitCode = (lpStartAddress)(lpParameter);
33
34 NtTerminateThread(NtCurrentThread(),
35 uExitCode);
36 }
37
38
39 HANDLE STDCALL CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,
40 DWORD dwStackSize,
41 LPTHREAD_START_ROUTINE lpStartAddress,
42 LPVOID lpParameter,
43 DWORD dwCreationFlags,
44 LPDWORD lpThreadId)
45 {
46 return(CreateRemoteThread(NtCurrentProcess(),
47 lpThreadAttributes,
48 dwStackSize,
49 lpStartAddress,
50 lpParameter,
51 dwCreationFlags,
52 lpThreadId));
53 }
54
55 HANDLE STDCALL CreateRemoteThread(HANDLE hProcess,
56 LPSECURITY_ATTRIBUTES lpThreadAttributes,
57 DWORD dwStackSize,
58 LPTHREAD_START_ROUTINE lpStartAddress,
59 LPVOID lpParameter,
60 DWORD dwCreationFlags,
61 LPDWORD lpThreadId)
62 {
63 HANDLE ThreadHandle;
64 OBJECT_ATTRIBUTES ObjectAttributes;
65 CLIENT_ID ClientId;
66 CONTEXT ThreadContext;
67 INITIAL_TEB InitialTeb;
68 BOOLEAN CreateSuspended = FALSE;
69 PVOID BaseAddress;
70 DWORD StackSize;
71 NTSTATUS Status;
72
73 ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES);
74 ObjectAttributes.RootDirectory = NULL;
75 ObjectAttributes.ObjectName = NULL;
76 ObjectAttributes.Attributes = 0;
77 if (lpThreadAttributes != NULL)
78 {
79 if (lpThreadAttributes->bInheritHandle)
80 ObjectAttributes.Attributes = OBJ_INHERIT;
81 ObjectAttributes.SecurityDescriptor =
82 lpThreadAttributes->lpSecurityDescriptor;
83 }
84 ObjectAttributes.SecurityQualityOfService = NULL;
85
86 if ((dwCreationFlags & CREATE_SUSPENDED) == CREATE_SUSPENDED)
87 CreateSuspended = TRUE;
88 else
89 CreateSuspended = FALSE;
90
91 StackSize = (dwStackSize == 0) ? 4096 : dwStackSize;
92
93 BaseAddress = 0;
94 Status = NtAllocateVirtualMemory(hProcess,
95 &BaseAddress,
96 0,
97 (PULONG)&StackSize,
98 MEM_COMMIT,
99 PAGE_READWRITE);
100 if (!NT_SUCCESS(Status))
101 {
102 DPRINT("Could not allocate stack space!\n");
103 return NULL;
104 }
105
106 DPRINT("Stack base address: %p\n", BaseAddress);
107
108 memset(&ThreadContext,0,sizeof(CONTEXT));
109 // ThreadContext.Eip = (LONG)lpStartAddress;
110 ThreadContext.Eip = (LONG)ThreadStartup;
111 ThreadContext.SegGs = USER_DS;
112 ThreadContext.SegFs = USER_DS;
113 ThreadContext.SegEs = USER_DS;
114 ThreadContext.SegDs = USER_DS;
115 ThreadContext.SegCs = USER_CS;
116 ThreadContext.SegSs = USER_DS;
117 ThreadContext.Esp = (ULONG)(BaseAddress + StackSize - 12);
118 ThreadContext.EFlags = (1<<1) + (1<<9);
119
120 /* initialize call stack */
121 *((PULONG)(BaseAddress + StackSize - 4)) = (ULONG)lpParameter;
122 *((PULONG)(BaseAddress + StackSize - 8)) = (ULONG)lpStartAddress;
123 *((PULONG)(BaseAddress + StackSize - 12)) = 0xdeadbeef;
124
125 DPRINT("Esp: %p\n", ThreadContext.Esp);
126 DPRINT("Eip: %p\n", ThreadContext.Eip);
127
128 Status = NtCreateThread(&ThreadHandle,
129 THREAD_ALL_ACCESS,
130 &ObjectAttributes,
131 hProcess,
132 &ClientId,
133 &ThreadContext,
134 &InitialTeb,
135 CreateSuspended);
136
137 if (!NT_SUCCESS(Status))
138 {
139 DPRINT("NtCreateThread() failed!\n");
140 return NULL;
141 }
142
143 if ( lpThreadId != NULL )
144 memcpy(lpThreadId, &ClientId.UniqueThread,sizeof(ULONG));
145
146 return ThreadHandle;
147 }
148
149 NT_TEB *GetTeb(VOID)
150 {
151 return NULL;
152 }
153
154 WINBOOL STDCALL SwitchToThread(VOID)
155 {
156 NTSTATUS errCode;
157 errCode = NtYieldExecution();
158 return TRUE;
159 }
160
161 DWORD STDCALL GetCurrentThreadId()
162 {
163 return((DWORD)(GetTeb()->Cid).UniqueThread);
164 }
165
166 VOID STDCALL ExitThread(UINT uExitCode)
167 {
168 NTSTATUS errCode;
169
170 errCode = NtTerminateThread(NtCurrentThread(),
171 uExitCode);
172 if (!NT_SUCCESS(errCode))
173 {
174 SetLastError(RtlNtStatusToDosError(errCode));
175 }
176 }
177
178 WINBOOL STDCALL GetThreadTimes(HANDLE hThread,
179 LPFILETIME lpCreationTime,
180 LPFILETIME lpExitTime,
181 LPFILETIME lpKernelTime,
182 LPFILETIME lpUserTime)
183 {
184 NTSTATUS errCode;
185 KERNEL_USER_TIMES KernelUserTimes;
186 ULONG ReturnLength;
187
188 errCode = NtQueryInformationThread(hThread,
189 ThreadTimes,
190 &KernelUserTimes,
191 sizeof(KERNEL_USER_TIMES),
192 &ReturnLength);
193 if (!NT_SUCCESS(errCode))
194 {
195 SetLastError(RtlNtStatusToDosError(errCode));
196 return FALSE;
197 }
198 memcpy(lpCreationTime, &KernelUserTimes.CreateTime, sizeof(FILETIME));
199 memcpy(lpExitTime, &KernelUserTimes.ExitTime, sizeof(FILETIME));
200 memcpy(lpKernelTime, &KernelUserTimes.KernelTime, sizeof(FILETIME));
201 memcpy(lpUserTime, &KernelUserTimes.UserTime, sizeof(FILETIME));
202 return TRUE;
203 }
204
205
206 WINBOOL STDCALL GetThreadContext(HANDLE hThread,
207 LPCONTEXT lpContext)
208 {
209 NTSTATUS errCode;
210
211 errCode = NtGetContextThread(hThread,
212 lpContext);
213 if (!NT_SUCCESS(errCode))
214 {
215 SetLastError(RtlNtStatusToDosError(errCode));
216 return FALSE;
217 }
218 return TRUE;
219 }
220
221 WINBOOL STDCALL SetThreadContext(HANDLE hThread,
222 CONST CONTEXT *lpContext)
223 {
224 NTSTATUS errCode;
225
226 errCode = NtSetContextThread(hThread,
227 (void *)lpContext);
228 if (!NT_SUCCESS(errCode))
229 {
230 SetLastError(RtlNtStatusToDosError(errCode));
231 return FALSE;
232 }
233 return TRUE;
234 }
235
236 WINBOOL STDCALL GetExitCodeThread(HANDLE hThread,
237 LPDWORD lpExitCode)
238 {
239 NTSTATUS errCode;
240 THREAD_BASIC_INFORMATION ThreadBasic;
241 ULONG DataWritten;
242
243 errCode = NtQueryInformationThread(hThread,
244 ThreadBasicInformation,
245 &ThreadBasic,
246 sizeof(THREAD_BASIC_INFORMATION),
247 &DataWritten);
248 if (!NT_SUCCESS(errCode))
249 {
250 SetLastError(RtlNtStatusToDosError(errCode));
251 return FALSE;
252 }
253 memcpy(lpExitCode, &ThreadBasic.ExitStatus, sizeof(DWORD));
254 return TRUE;
255 }
256
257 DWORD STDCALL ResumeThread(HANDLE hThread)
258 {
259 NTSTATUS errCode;
260 ULONG PreviousResumeCount;
261
262 errCode = NtResumeThread(hThread,
263 &PreviousResumeCount);
264 if (!NT_SUCCESS(errCode))
265 {
266 SetLastError(RtlNtStatusToDosError(errCode));
267 return -1;
268 }
269 return PreviousResumeCount;
270 }
271
272
273 WINBOOL
274 STDCALL
275 TerminateThread (
276 HANDLE hThread,
277 DWORD dwExitCode
278 )
279 {
280 NTSTATUS errCode;
281
282 errCode = NtTerminateThread(hThread,
283 dwExitCode);
284 if (!NT_SUCCESS(errCode))
285 {
286 SetLastError(RtlNtStatusToDosError(errCode));
287 return FALSE;
288 }
289 return TRUE;
290 }
291
292
293 DWORD STDCALL SuspendThread(HANDLE hThread)
294 {
295 NTSTATUS errCode;
296 ULONG PreviousSuspendCount;
297
298 errCode = NtSuspendThread(hThread,
299 &PreviousSuspendCount);
300 if (!NT_SUCCESS(errCode))
301 {
302 SetLastError(RtlNtStatusToDosError(errCode));
303 return -1;
304 }
305 return PreviousSuspendCount;
306 }
307
308 DWORD STDCALL SetThreadAffinityMask(HANDLE hThread,
309 DWORD dwThreadAffinityMask)
310 {
311 return 0;
312 }
313
314 WINBOOL STDCALL SetThreadPriority(HANDLE hThread,
315 int nPriority)
316 {
317 NTSTATUS errCode;
318 THREAD_BASIC_INFORMATION ThreadBasic;
319 ULONG DataWritten;
320
321 errCode = NtQueryInformationThread(hThread,
322 ThreadBasicInformation,
323 &ThreadBasic,
324 sizeof(THREAD_BASIC_INFORMATION),
325 &DataWritten);
326 if (!NT_SUCCESS(errCode))
327 {
328 SetLastError(RtlNtStatusToDosError(errCode));
329 return FALSE;
330 }
331 ThreadBasic.BasePriority = nPriority;
332 errCode = NtSetInformationThread(hThread,
333 ThreadBasicInformation,
334 &ThreadBasic,
335 sizeof(THREAD_BASIC_INFORMATION));
336 if (!NT_SUCCESS(errCode))
337 {
338 SetLastError(RtlNtStatusToDosError(errCode));
339 return FALSE;
340 }
341 return TRUE;
342 }
343
344 int STDCALL GetThreadPriority(HANDLE hThread)
345 {
346 NTSTATUS errCode;
347 THREAD_BASIC_INFORMATION ThreadBasic;
348 ULONG DataWritten;
349
350 errCode = NtQueryInformationThread(hThread,
351 ThreadBasicInformation,
352 &ThreadBasic,
353 sizeof(THREAD_BASIC_INFORMATION),
354 &DataWritten);
355 if (!NT_SUCCESS(errCode))
356 {
357 SetLastError(RtlNtStatusToDosError(errCode));
358 return THREAD_PRIORITY_ERROR_RETURN;
359 }
360 return ThreadBasic.BasePriority;
361 }