Registry fixes (not usable yet)
[reactos.git] / reactos / lib / kernel32 / thread / thread.c
1 /* $Id: thread.c,v 1.20 2000/09/05 23:01:07 ekohl Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: lib/kernel32/thread/thread.c
6 * PURPOSE: Thread functions
7 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
8 * Tls functions are modified from WINE
9 * UPDATE HISTORY:
10 * Created 01/11/98
11 */
12
13 /* INCLUDES ******************************************************************/
14
15 #include <ddk/ntddk.h>
16 #include <windows.h>
17 #include <kernel32/thread.h>
18 #include <ntdll/ldr.h>
19 #include <string.h>
20 #include <napi/i386/segment.h>
21
22 #define NDEBUG
23 #include <kernel32/kernel32.h>
24 #include <kernel32/error.h>
25
26
27 static VOID ThreadAttachDlls (VOID);
28
29 /* Type for a DLL's entry point */
30 typedef
31 WINBOOL
32 STDCALL
33 (* PDLLMAIN_FUNC) (
34 HANDLE hInst,
35 ULONG ul_reason_for_call,
36 LPVOID lpReserved
37 );
38
39 /* FUNCTIONS *****************************************************************/
40
41 static VOID STDCALL
42 ThreadStartup (LPTHREAD_START_ROUTINE lpStartAddress,
43 LPVOID lpParameter)
44 {
45 UINT uExitCode;
46
47 ThreadAttachDlls ();
48
49 /* FIXME: notify csrss of thread creation ?? */
50
51 uExitCode = (lpStartAddress)(lpParameter);
52
53 ExitThread(uExitCode);
54 }
55
56 static VOID
57 ThreadAttachDlls (VOID)
58 {
59 PLIST_ENTRY ModuleListHead;
60 PLIST_ENTRY Entry;
61 PLDR_MODULE Module;
62
63 DPRINT("ThreadAttachDlls() called\n");
64
65 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
66
67 ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
68 Entry = ModuleListHead->Blink;
69
70 while (Entry != ModuleListHead)
71 {
72 Module = CONTAINING_RECORD(Entry, LDR_MODULE, InInitializationOrderModuleList);
73
74 if (Module->EntryPoint != 0)
75 {
76 PDLLMAIN_FUNC Entrypoint = (PDLLMAIN_FUNC)Module->EntryPoint;
77
78 DPRINT("Calling entry point at 0x%08x\n", Entrypoint);
79 Entrypoint (Module->BaseAddress,
80 DLL_THREAD_ATTACH,
81 NULL);
82 }
83
84 Entry = Entry->Blink;
85 }
86
87 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
88
89 DPRINT("ThreadAttachDlls() done\n");
90 }
91
92 HANDLE STDCALL CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,
93 DWORD dwStackSize,
94 LPTHREAD_START_ROUTINE lpStartAddress,
95 LPVOID lpParameter,
96 DWORD dwCreationFlags,
97 LPDWORD lpThreadId)
98 {
99 return(CreateRemoteThread(NtCurrentProcess(),
100 lpThreadAttributes,
101 dwStackSize,
102 lpStartAddress,
103 lpParameter,
104 dwCreationFlags,
105 lpThreadId));
106 }
107
108 HANDLE STDCALL CreateRemoteThread(HANDLE hProcess,
109 LPSECURITY_ATTRIBUTES lpThreadAttributes,
110 DWORD dwStackSize,
111 LPTHREAD_START_ROUTINE lpStartAddress,
112 LPVOID lpParameter,
113 DWORD dwCreationFlags,
114 LPDWORD lpThreadId)
115 {
116 HANDLE ThreadHandle;
117 OBJECT_ATTRIBUTES ObjectAttributes;
118 CLIENT_ID ClientId;
119 CONTEXT ThreadContext;
120 INITIAL_TEB InitialTeb;
121 BOOLEAN CreateSuspended = FALSE;
122 PVOID BaseAddress;
123 DWORD StackSize;
124 NTSTATUS Status;
125
126 ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES);
127 ObjectAttributes.RootDirectory = NULL;
128 ObjectAttributes.ObjectName = NULL;
129 ObjectAttributes.Attributes = 0;
130 if (lpThreadAttributes != NULL)
131 {
132 if (lpThreadAttributes->bInheritHandle)
133 ObjectAttributes.Attributes = OBJ_INHERIT;
134 ObjectAttributes.SecurityDescriptor =
135 lpThreadAttributes->lpSecurityDescriptor;
136 }
137 ObjectAttributes.SecurityQualityOfService = NULL;
138
139 if ((dwCreationFlags & CREATE_SUSPENDED) == CREATE_SUSPENDED)
140 CreateSuspended = TRUE;
141 else
142 CreateSuspended = FALSE;
143
144 StackSize = (dwStackSize == 0) ? 4096 : dwStackSize;
145
146 BaseAddress = 0;
147
148 Status = NtAllocateVirtualMemory(hProcess,
149 &BaseAddress,
150 0,
151 (PULONG)&StackSize,
152 MEM_COMMIT,
153 PAGE_READWRITE);
154 if (!NT_SUCCESS(Status))
155 {
156 DPRINT("Could not allocate stack space!\n");
157 return NULL;
158 }
159
160
161 DPRINT("Stack base address: %p\n", BaseAddress);
162
163 memset(&ThreadContext,0,sizeof(CONTEXT));
164 ThreadContext.Eip = (LONG)ThreadStartup;
165 ThreadContext.SegGs = USER_DS;
166 ThreadContext.SegFs = USER_DS;
167 ThreadContext.SegEs = USER_DS;
168 ThreadContext.SegDs = USER_DS;
169 ThreadContext.SegCs = USER_CS;
170 ThreadContext.SegSs = USER_DS;
171 ThreadContext.Esp = (ULONG)(BaseAddress + StackSize - 12);
172 ThreadContext.EFlags = (1<<1) + (1<<9);
173
174 /* initialize call stack */
175 *((PULONG)(BaseAddress + StackSize - 4)) = (ULONG)lpParameter;
176 *((PULONG)(BaseAddress + StackSize - 8)) = (ULONG)lpStartAddress;
177 *((PULONG)(BaseAddress + StackSize - 12)) = 0xdeadbeef;
178
179 DPRINT("Esp: %p\n", ThreadContext.Esp);
180 DPRINT("Eip: %p\n", ThreadContext.Eip);
181
182 Status = NtCreateThread(&ThreadHandle,
183 THREAD_ALL_ACCESS,
184 &ObjectAttributes,
185 hProcess,
186 &ClientId,
187 &ThreadContext,
188 &InitialTeb,
189 CreateSuspended);
190
191 if (!NT_SUCCESS(Status))
192 {
193 DPRINT("NtCreateThread() failed!\n");
194 return NULL;
195 }
196
197 if ( lpThreadId != NULL )
198 memcpy(lpThreadId, &ClientId.UniqueThread,sizeof(ULONG));
199
200 return ThreadHandle;
201 }
202
203 NT_TEB *GetTeb(VOID)
204 {
205 return NtCurrentTeb();
206 }
207
208 WINBOOL STDCALL SwitchToThread(VOID)
209 {
210 NTSTATUS errCode;
211 errCode = NtYieldExecution();
212 return TRUE;
213 }
214
215 DWORD STDCALL GetCurrentThreadId()
216 {
217 return((DWORD)(NtCurrentTeb()->Cid).UniqueThread);
218 }
219
220 VOID STDCALL ExitThread(UINT uExitCode)
221 {
222 NTSTATUS errCode;
223 BOOLEAN LastThread;
224 NTSTATUS Status;
225
226 /*
227 * Terminate process if this is the last thread
228 * of the current process
229 */
230 Status = NtQueryInformationThread(NtCurrentThread(),
231 ThreadAmILastThread,
232 &LastThread,
233 sizeof(BOOLEAN),
234 NULL);
235 if (NT_SUCCESS(Status) && LastThread == TRUE)
236 {
237 ExitProcess (uExitCode);
238 }
239
240 /* FIXME: notify csrss of thread termination */
241
242 LdrShutdownThread();
243
244 errCode = NtTerminateThread(NtCurrentThread(),
245 uExitCode);
246 if (!NT_SUCCESS(errCode))
247 {
248 SetLastErrorByStatus(errCode);
249 }
250 }
251
252 WINBOOL STDCALL GetThreadTimes(HANDLE hThread,
253 LPFILETIME lpCreationTime,
254 LPFILETIME lpExitTime,
255 LPFILETIME lpKernelTime,
256 LPFILETIME lpUserTime)
257 {
258 NTSTATUS errCode;
259 KERNEL_USER_TIMES KernelUserTimes;
260 ULONG ReturnLength;
261
262 errCode = NtQueryInformationThread(hThread,
263 ThreadTimes,
264 &KernelUserTimes,
265 sizeof(KERNEL_USER_TIMES),
266 &ReturnLength);
267 if (!NT_SUCCESS(errCode))
268 {
269 SetLastErrorByStatus(errCode);
270 return FALSE;
271 }
272 memcpy(lpCreationTime, &KernelUserTimes.CreateTime, sizeof(FILETIME));
273 memcpy(lpExitTime, &KernelUserTimes.ExitTime, sizeof(FILETIME));
274 memcpy(lpKernelTime, &KernelUserTimes.KernelTime, sizeof(FILETIME));
275 memcpy(lpUserTime, &KernelUserTimes.UserTime, sizeof(FILETIME));
276 return TRUE;
277 }
278
279
280 WINBOOL STDCALL GetThreadContext(HANDLE hThread,
281 LPCONTEXT lpContext)
282 {
283 NTSTATUS errCode;
284
285 errCode = NtGetContextThread(hThread,
286 lpContext);
287 if (!NT_SUCCESS(errCode))
288 {
289 SetLastErrorByStatus(errCode);
290 return FALSE;
291 }
292 return TRUE;
293 }
294
295 WINBOOL STDCALL SetThreadContext(HANDLE hThread,
296 CONST CONTEXT *lpContext)
297 {
298 NTSTATUS errCode;
299
300 errCode = NtSetContextThread(hThread,
301 (void *)lpContext);
302 if (!NT_SUCCESS(errCode))
303 {
304 SetLastErrorByStatus(errCode);
305 return FALSE;
306 }
307 return TRUE;
308 }
309
310 WINBOOL STDCALL GetExitCodeThread(HANDLE hThread,
311 LPDWORD lpExitCode)
312 {
313 NTSTATUS errCode;
314 THREAD_BASIC_INFORMATION ThreadBasic;
315 ULONG DataWritten;
316
317 errCode = NtQueryInformationThread(hThread,
318 ThreadBasicInformation,
319 &ThreadBasic,
320 sizeof(THREAD_BASIC_INFORMATION),
321 &DataWritten);
322 if (!NT_SUCCESS(errCode))
323 {
324 SetLastErrorByStatus(errCode);
325 return FALSE;
326 }
327 memcpy(lpExitCode, &ThreadBasic.ExitStatus, sizeof(DWORD));
328 return TRUE;
329 }
330
331 DWORD STDCALL ResumeThread(HANDLE hThread)
332 {
333 NTSTATUS errCode;
334 ULONG PreviousResumeCount;
335
336 errCode = NtResumeThread(hThread,
337 &PreviousResumeCount);
338 if (!NT_SUCCESS(errCode))
339 {
340 SetLastErrorByStatus(errCode);
341 return -1;
342 }
343 return PreviousResumeCount;
344 }
345
346
347 WINBOOL
348 STDCALL
349 TerminateThread (
350 HANDLE hThread,
351 DWORD dwExitCode
352 )
353 {
354 NTSTATUS errCode;
355
356 errCode = NtTerminateThread(hThread,
357 dwExitCode);
358 if (!NT_SUCCESS(errCode))
359 {
360 SetLastErrorByStatus(errCode);
361 return FALSE;
362 }
363 return TRUE;
364 }
365
366
367 DWORD STDCALL SuspendThread(HANDLE hThread)
368 {
369 NTSTATUS errCode;
370 ULONG PreviousSuspendCount;
371
372 errCode = NtSuspendThread(hThread,
373 &PreviousSuspendCount);
374 if (!NT_SUCCESS(errCode))
375 {
376 SetLastErrorByStatus(errCode);
377 return -1;
378 }
379 return PreviousSuspendCount;
380 }
381
382 DWORD STDCALL SetThreadAffinityMask(HANDLE hThread,
383 DWORD dwThreadAffinityMask)
384 {
385 return 0;
386 }
387
388 WINBOOL STDCALL SetThreadPriority(HANDLE hThread,
389 int nPriority)
390 {
391 NTSTATUS errCode;
392 THREAD_BASIC_INFORMATION ThreadBasic;
393 ULONG DataWritten;
394
395 errCode = NtQueryInformationThread(hThread,
396 ThreadBasicInformation,
397 &ThreadBasic,
398 sizeof(THREAD_BASIC_INFORMATION),
399 &DataWritten);
400 if (!NT_SUCCESS(errCode))
401 {
402 SetLastErrorByStatus(errCode);
403 return FALSE;
404 }
405 ThreadBasic.BasePriority = nPriority;
406 errCode = NtSetInformationThread(hThread,
407 ThreadBasicInformation,
408 &ThreadBasic,
409 sizeof(THREAD_BASIC_INFORMATION));
410 if (!NT_SUCCESS(errCode))
411 {
412 SetLastErrorByStatus(errCode);
413 return FALSE;
414 }
415 return TRUE;
416 }
417
418 int STDCALL GetThreadPriority(HANDLE hThread)
419 {
420 NTSTATUS errCode;
421 THREAD_BASIC_INFORMATION ThreadBasic;
422 ULONG DataWritten;
423
424 errCode = NtQueryInformationThread(hThread,
425 ThreadBasicInformation,
426 &ThreadBasic,
427 sizeof(THREAD_BASIC_INFORMATION),
428 &DataWritten);
429 if (!NT_SUCCESS(errCode))
430 {
431 SetLastErrorByStatus(errCode);
432 return THREAD_PRIORITY_ERROR_RETURN;
433 }
434 return ThreadBasic.BasePriority;
435 }
436
437 /* EOF */