Fixed some warnings.
[reactos.git] / reactos / lib / kernel32 / thread / thread.c
1 /* $Id: thread.c,v 1.34 2003/01/22 02:24:36 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 <k32.h>
16
17 #define NDEBUG
18 #include <kernel32/kernel32.h>
19
20
21 //static VOID ThreadAttachDlls (VOID);
22
23 /* FUNCTIONS *****************************************************************/
24
25 static EXCEPTION_DISPOSITION __cdecl
26 _except_handler(struct _EXCEPTION_RECORD *ExceptionRecord,
27 void * EstablisherFrame,
28 struct _CONTEXT *ContextRecord,
29 void * DispatcherContext)
30 {
31 ExitThread(0);
32
33 /* We should not get to here */
34 return(ExceptionContinueSearch);
35 }
36
37
38 static VOID STDCALL
39 ThreadStartup(LPTHREAD_START_ROUTINE lpStartAddress,
40 LPVOID lpParameter)
41 {
42 UINT uExitCode;
43
44 __try1(_except_handler)
45 {
46 /* FIXME: notify csrss of thread creation ?? */
47 uExitCode = (lpStartAddress)(lpParameter);
48 }
49 __except1
50 {
51 }
52
53 ExitThread(uExitCode);
54 }
55
56
57 HANDLE STDCALL
58 CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,
59 DWORD dwStackSize,
60 LPTHREAD_START_ROUTINE lpStartAddress,
61 LPVOID lpParameter,
62 DWORD dwCreationFlags,
63 LPDWORD lpThreadId)
64 {
65 return(CreateRemoteThread(NtCurrentProcess(),
66 lpThreadAttributes,
67 dwStackSize,
68 lpStartAddress,
69 lpParameter,
70 dwCreationFlags,
71 lpThreadId));
72 }
73
74
75 HANDLE STDCALL
76 CreateRemoteThread(HANDLE hProcess,
77 LPSECURITY_ATTRIBUTES lpThreadAttributes,
78 DWORD dwStackSize,
79 LPTHREAD_START_ROUTINE lpStartAddress,
80 LPVOID lpParameter,
81 DWORD dwCreationFlags,
82 LPDWORD lpThreadId)
83 {
84 HANDLE ThreadHandle;
85 OBJECT_ATTRIBUTES ObjectAttributes;
86 CLIENT_ID ClientId;
87 CONTEXT ThreadContext;
88 INITIAL_TEB InitialTeb;
89 BOOLEAN CreateSuspended = FALSE;
90 PVOID BaseAddress;
91 ULONG OldPageProtection;
92 NTSTATUS Status;
93
94 ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES);
95 ObjectAttributes.RootDirectory = NULL;
96 ObjectAttributes.ObjectName = NULL;
97 ObjectAttributes.Attributes = 0;
98 if (lpThreadAttributes != NULL)
99 {
100 if (lpThreadAttributes->bInheritHandle)
101 ObjectAttributes.Attributes = OBJ_INHERIT;
102 ObjectAttributes.SecurityDescriptor =
103 lpThreadAttributes->lpSecurityDescriptor;
104 }
105 ObjectAttributes.SecurityQualityOfService = NULL;
106
107 if ((dwCreationFlags & CREATE_SUSPENDED) == CREATE_SUSPENDED)
108 CreateSuspended = TRUE;
109 else
110 CreateSuspended = FALSE;
111
112 InitialTeb.StackReserve = 0x100000; /* 1MByte */
113 /* FIXME: use correct commit size */
114 #if 0
115 InitialTeb.StackCommit = (dwStackSize == 0) ? PAGE_SIZE : dwStackSize;
116 #endif
117 InitialTeb.StackCommit = InitialTeb.StackReserve - PAGE_SIZE;
118
119 /* size of guard page */
120 InitialTeb.StackCommit += PAGE_SIZE;
121
122 /* Reserve stack */
123 InitialTeb.StackAllocate = NULL;
124 Status = NtAllocateVirtualMemory(hProcess,
125 &InitialTeb.StackAllocate,
126 0,
127 &InitialTeb.StackReserve,
128 MEM_RESERVE,
129 PAGE_READWRITE);
130 if (!NT_SUCCESS(Status))
131 {
132 DPRINT("Error reserving stack space!\n");
133 SetLastErrorByStatus(Status);
134 return(NULL);
135 }
136
137 DPRINT("StackDeallocation: %p ReserveSize: 0x%lX\n",
138 InitialTeb.StackDeallocation, InitialTeb.StackReserve);
139
140 InitialTeb.StackBase = (PVOID)((ULONG)InitialTeb.StackAllocate + InitialTeb.StackReserve);
141 InitialTeb.StackLimit = (PVOID)((ULONG)InitialTeb.StackBase - InitialTeb.StackCommit);
142
143 DPRINT("StackBase: %p\nStackCommit: 0x%lX\n",
144 InitialTeb.StackBase,
145 InitialTeb.StackCommit);
146
147 /* Commit stack pages */
148 Status = NtAllocateVirtualMemory(hProcess,
149 &InitialTeb.StackLimit,
150 0,
151 &InitialTeb.StackCommit,
152 MEM_COMMIT,
153 PAGE_READWRITE);
154 if (!NT_SUCCESS(Status))
155 {
156 /* release the stack space */
157 NtFreeVirtualMemory(hProcess,
158 InitialTeb.StackAllocate,
159 &InitialTeb.StackReserve,
160 MEM_RELEASE);
161
162 DPRINT("Error comitting stack page(s)!\n");
163 SetLastErrorByStatus(Status);
164 return(NULL);
165 }
166
167 DPRINT("StackLimit: %p\n",
168 InitialTeb.StackLimit);
169
170 /* Protect guard page */
171 Status = NtProtectVirtualMemory(hProcess,
172 InitialTeb.StackLimit,
173 PAGE_SIZE,
174 PAGE_GUARD | PAGE_READWRITE,
175 &OldPageProtection);
176 if (!NT_SUCCESS(Status))
177 {
178 /* release the stack space */
179 NtFreeVirtualMemory(hProcess,
180 InitialTeb.StackAllocate,
181 &InitialTeb.StackReserve,
182 MEM_RELEASE);
183
184 DPRINT("Error comitting guard page!\n");
185 SetLastErrorByStatus(Status);
186 return(NULL);
187 }
188
189 memset(&ThreadContext,0,sizeof(CONTEXT));
190 ThreadContext.Eip = (LONG)ThreadStartup;
191 ThreadContext.SegGs = USER_DS;
192 ThreadContext.SegFs = TEB_SELECTOR;
193 ThreadContext.SegEs = USER_DS;
194 ThreadContext.SegDs = USER_DS;
195 ThreadContext.SegCs = USER_CS;
196 ThreadContext.SegSs = USER_DS;
197 ThreadContext.Esp = (ULONG)InitialTeb.StackBase - 12;
198 ThreadContext.EFlags = (1<<1) + (1<<9);
199
200 /* initialize call stack */
201 *((PULONG)((ULONG)InitialTeb.StackBase - 4)) = (ULONG)lpParameter;
202 *((PULONG)((ULONG)InitialTeb.StackBase - 8)) = (ULONG)lpStartAddress;
203 *((PULONG)((ULONG)InitialTeb.StackBase - 12)) = 0xdeadbeef;
204
205 DPRINT("Esp: %p\n", ThreadContext.Esp);
206 DPRINT("Eip: %p\n", ThreadContext.Eip);
207
208 Status = NtCreateThread(&ThreadHandle,
209 THREAD_ALL_ACCESS,
210 &ObjectAttributes,
211 hProcess,
212 &ClientId,
213 &ThreadContext,
214 &InitialTeb,
215 CreateSuspended);
216 if (!NT_SUCCESS(Status))
217 {
218 NtFreeVirtualMemory(hProcess,
219 InitialTeb.StackAllocate,
220 &InitialTeb.StackReserve,
221 MEM_RELEASE);
222
223 DPRINT("NtCreateThread() failed!\n");
224 SetLastErrorByStatus(Status);
225 return(NULL);
226 }
227
228 if (lpThreadId != NULL)
229 memcpy(lpThreadId, &ClientId.UniqueThread,sizeof(ULONG));
230
231 return(ThreadHandle);
232 }
233
234
235 PTEB
236 GetTeb(VOID)
237 {
238 return(NtCurrentTeb());
239 }
240
241
242 WINBOOL STDCALL
243 SwitchToThread(VOID)
244 {
245 NTSTATUS errCode;
246 errCode = NtYieldExecution();
247 return TRUE;
248 }
249
250
251 DWORD STDCALL
252 GetCurrentThreadId(VOID)
253 {
254 return((DWORD)(NtCurrentTeb()->Cid).UniqueThread);
255 }
256
257
258 VOID STDCALL
259 ExitThread(DWORD uExitCode)
260 {
261 BOOLEAN LastThread;
262 NTSTATUS Status;
263
264 /*
265 * Terminate process if this is the last thread
266 * of the current process
267 */
268 Status = NtQueryInformationThread(NtCurrentThread(),
269 ThreadAmILastThread,
270 &LastThread,
271 sizeof(BOOLEAN),
272 NULL);
273 if (NT_SUCCESS(Status) && LastThread == TRUE)
274 {
275 ExitProcess(uExitCode);
276 }
277
278 /* FIXME: notify csrss of thread termination */
279
280 LdrShutdownThread();
281
282 Status = NtTerminateThread(NtCurrentThread(),
283 uExitCode);
284 if (!NT_SUCCESS(Status))
285 {
286 SetLastErrorByStatus(Status);
287 }
288 }
289
290
291 WINBOOL STDCALL
292 GetThreadTimes(HANDLE hThread,
293 LPFILETIME lpCreationTime,
294 LPFILETIME lpExitTime,
295 LPFILETIME lpKernelTime,
296 LPFILETIME lpUserTime)
297 {
298 KERNEL_USER_TIMES KernelUserTimes;
299 ULONG ReturnLength;
300 NTSTATUS Status;
301
302 Status = NtQueryInformationThread(hThread,
303 ThreadTimes,
304 &KernelUserTimes,
305 sizeof(KERNEL_USER_TIMES),
306 &ReturnLength);
307 if (!NT_SUCCESS(Status))
308 {
309 SetLastErrorByStatus(Status);
310 return(FALSE);
311 }
312
313 memcpy(lpCreationTime, &KernelUserTimes.CreateTime, sizeof(FILETIME));
314 memcpy(lpExitTime, &KernelUserTimes.ExitTime, sizeof(FILETIME));
315 memcpy(lpKernelTime, &KernelUserTimes.KernelTime, sizeof(FILETIME));
316 memcpy(lpUserTime, &KernelUserTimes.UserTime, sizeof(FILETIME));
317
318 return(TRUE);
319 }
320
321
322 WINBOOL STDCALL
323 GetThreadContext(HANDLE hThread,
324 LPCONTEXT lpContext)
325 {
326 NTSTATUS Status;
327
328 Status = NtGetContextThread(hThread,
329 lpContext);
330 if (!NT_SUCCESS(Status))
331 {
332 SetLastErrorByStatus(Status);
333 return(FALSE);
334 }
335
336 return(TRUE);
337 }
338
339
340 WINBOOL STDCALL
341 SetThreadContext(HANDLE hThread,
342 CONST CONTEXT *lpContext)
343 {
344 NTSTATUS Status;
345
346 Status = NtSetContextThread(hThread,
347 (void *)lpContext);
348 if (!NT_SUCCESS(Status))
349 {
350 SetLastErrorByStatus(Status);
351 return(FALSE);
352 }
353
354 return(TRUE);
355 }
356
357
358 WINBOOL STDCALL
359 GetExitCodeThread(HANDLE hThread,
360 LPDWORD lpExitCode)
361 {
362 THREAD_BASIC_INFORMATION ThreadBasic;
363 ULONG DataWritten;
364 NTSTATUS Status;
365
366 Status = NtQueryInformationThread(hThread,
367 ThreadBasicInformation,
368 &ThreadBasic,
369 sizeof(THREAD_BASIC_INFORMATION),
370 &DataWritten);
371 if (!NT_SUCCESS(Status))
372 {
373 SetLastErrorByStatus(Status);
374 return(FALSE);
375 }
376
377 memcpy(lpExitCode, &ThreadBasic.ExitStatus, sizeof(DWORD));
378
379 return(TRUE);
380 }
381
382
383 DWORD STDCALL
384 ResumeThread(HANDLE hThread)
385 {
386 ULONG PreviousResumeCount;
387 NTSTATUS Status;
388
389 Status = NtResumeThread(hThread,
390 &PreviousResumeCount);
391 if (!NT_SUCCESS(Status))
392 {
393 SetLastErrorByStatus(Status);
394 return(-1);
395 }
396
397 return(PreviousResumeCount);
398 }
399
400
401 WINBOOL STDCALL
402 TerminateThread(HANDLE hThread,
403 DWORD dwExitCode)
404 {
405 NTSTATUS Status;
406
407 if (0 == hThread)
408 {
409 SetLastError(ERROR_INVALID_HANDLE);
410 return(FALSE);
411 }
412
413 Status = NtTerminateThread(hThread,
414 dwExitCode);
415 if (!NT_SUCCESS(Status))
416 {
417 SetLastErrorByStatus(Status);
418 return(FALSE);
419 }
420
421 return(TRUE);
422 }
423
424
425 DWORD STDCALL
426 SuspendThread(HANDLE hThread)
427 {
428 ULONG PreviousSuspendCount;
429 NTSTATUS Status;
430
431 Status = NtSuspendThread(hThread,
432 &PreviousSuspendCount);
433 if (!NT_SUCCESS(Status))
434 {
435 SetLastErrorByStatus(Status);
436 return(-1);
437 }
438
439 return(PreviousSuspendCount);
440 }
441
442
443 DWORD STDCALL
444 SetThreadAffinityMask(HANDLE hThread,
445 DWORD dwThreadAffinityMask)
446 {
447 THREAD_BASIC_INFORMATION ThreadBasic;
448 KAFFINITY AffinityMask;
449 ULONG DataWritten;
450 NTSTATUS Status;
451
452 AffinityMask = (KAFFINITY)dwThreadAffinityMask;
453
454 Status = NtQueryInformationThread(hThread,
455 ThreadBasicInformation,
456 &ThreadBasic,
457 sizeof(THREAD_BASIC_INFORMATION),
458 &DataWritten);
459 if (!NT_SUCCESS(Status))
460 {
461 SetLastErrorByStatus(Status);
462 return(0);
463 }
464
465 Status = NtSetInformationThread(hThread,
466 ThreadAffinityMask,
467 &AffinityMask,
468 sizeof(KAFFINITY));
469 if (!NT_SUCCESS(Status))
470 SetLastErrorByStatus(Status);
471
472 return(ThreadBasic.AffinityMask);
473 }
474
475
476 WINBOOL STDCALL
477 SetThreadPriority(HANDLE hThread,
478 int nPriority)
479 {
480 THREAD_BASIC_INFORMATION ThreadBasic;
481 ULONG DataWritten;
482 NTSTATUS Status;
483
484 Status = NtQueryInformationThread(hThread,
485 ThreadBasicInformation,
486 &ThreadBasic,
487 sizeof(THREAD_BASIC_INFORMATION),
488 &DataWritten);
489 if (!NT_SUCCESS(Status))
490 {
491 SetLastErrorByStatus(Status);
492 return(FALSE);
493 }
494
495 ThreadBasic.BasePriority = nPriority;
496
497 Status = NtSetInformationThread(hThread,
498 ThreadBasicInformation,
499 &ThreadBasic,
500 sizeof(THREAD_BASIC_INFORMATION));
501 if (!NT_SUCCESS(Status))
502 {
503 SetLastErrorByStatus(Status);
504 return(FALSE);
505 }
506
507 return(TRUE);
508 }
509
510
511 int STDCALL
512 GetThreadPriority(HANDLE hThread)
513 {
514 THREAD_BASIC_INFORMATION ThreadBasic;
515 ULONG DataWritten;
516 NTSTATUS Status;
517
518 Status = NtQueryInformationThread(hThread,
519 ThreadBasicInformation,
520 &ThreadBasic,
521 sizeof(THREAD_BASIC_INFORMATION),
522 &DataWritten);
523 if (!NT_SUCCESS(Status))
524 {
525 SetLastErrorByStatus(Status);
526 return(THREAD_PRIORITY_ERROR_RETURN);
527 }
528
529 return(ThreadBasic.BasePriority);
530 }
531
532
533 WINBOOL STDCALL
534 GetThreadPriorityBoost(IN HANDLE hThread,
535 OUT PBOOL pDisablePriorityBoost)
536 {
537 ULONG PriorityBoost;
538 ULONG DataWritten;
539 NTSTATUS Status;
540
541 Status = NtQueryInformationThread(hThread,
542 ThreadPriorityBoost,
543 &PriorityBoost,
544 sizeof(ULONG),
545 &DataWritten);
546 if (!NT_SUCCESS(Status))
547 {
548 SetLastErrorByStatus(Status);
549 return(FALSE);
550 }
551
552 *pDisablePriorityBoost = !((WINBOOL)PriorityBoost);
553
554 return(TRUE);
555 }
556
557
558 WINBOOL STDCALL
559 SetThreadPriorityBoost(IN HANDLE hThread,
560 IN WINBOOL bDisablePriorityBoost)
561 {
562 ULONG PriorityBoost;
563 NTSTATUS Status;
564
565 PriorityBoost = (ULONG)!bDisablePriorityBoost;
566
567 Status = NtSetInformationThread(hThread,
568 ThreadPriorityBoost,
569 &PriorityBoost,
570 sizeof(ULONG));
571 if (!NT_SUCCESS(Status))
572 {
573 SetLastErrorByStatus(Status);
574 return(FALSE);
575 }
576
577 return(TRUE);
578 }
579
580
581 WINBOOL STDCALL
582 GetThreadSelectorEntry(IN HANDLE hThread,
583 IN DWORD dwSelector,
584 OUT LPLDT_ENTRY lpSelectorEntry)
585 {
586 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
587 return(FALSE);
588 }
589
590 /* EOF */