Move kernekl32-internal declarations from global include directory to local one.
[reactos.git] / reactos / lib / kernel32 / thread / thread.c
1 /* $Id: thread.c,v 1.49 2004/01/23 21:16:04 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
14 /* INCLUDES ******************************************************************/
15
16 #include <k32.h>
17
18 #define NDEBUG
19 #include "../include/debug.h"
20
21
22 /* FUNCTIONS *****************************************************************/
23
24 /* FIXME: please put this in some header */
25 static EXCEPTION_DISPOSITION __cdecl
26 _except_handler(EXCEPTION_RECORD *ExceptionRecord,
27 void * EstablisherFrame,
28 CONTEXT *ContextRecord,
29 void * DispatcherContext)
30 {
31 ExitThread(0);
32
33 /* We should not get to here */
34 return(ExceptionContinueSearch);
35 }
36
37
38 __declspec(noreturn) void STDCALL
39 ThreadStartup
40 (
41 LPTHREAD_START_ROUTINE lpStartAddress,
42 LPVOID lpParameter
43 )
44 {
45 volatile UINT uExitCode = 0;
46
47 __try1(_except_handler)
48 {
49 /* FIXME: notify csrss of thread creation ?? */
50 uExitCode = (lpStartAddress)(lpParameter);
51 }
52 __except1
53 {
54 }
55
56 ExitThread(uExitCode);
57 }
58
59
60 /*
61 * @implemented
62 */
63 HANDLE STDCALL
64 CreateThread
65 (
66 LPSECURITY_ATTRIBUTES lpThreadAttributes,
67 DWORD dwStackSize,
68 LPTHREAD_START_ROUTINE lpStartAddress,
69 LPVOID lpParameter,
70 DWORD dwCreationFlags,
71 LPDWORD lpThreadId
72 )
73 {
74 return CreateRemoteThread
75 (
76 NtCurrentProcess(),
77 lpThreadAttributes,
78 dwStackSize,
79 lpStartAddress,
80 lpParameter,
81 dwCreationFlags,
82 lpThreadId
83 );
84 }
85
86
87 /*
88 * @implemented
89 */
90 HANDLE STDCALL
91 CreateRemoteThread
92 (
93 HANDLE hProcess,
94 LPSECURITY_ATTRIBUTES lpThreadAttributes,
95 DWORD dwStackSize,
96 LPTHREAD_START_ROUTINE lpStartAddress,
97 LPVOID lpParameter,
98 DWORD dwCreationFlags,
99 LPDWORD lpThreadId
100 )
101 {
102 HANDLE hThread;
103 CLIENT_ID cidClientId;
104 NTSTATUS nErrCode;
105 ULONG_PTR nStackReserve;
106 ULONG_PTR nStackCommit;
107 OBJECT_ATTRIBUTES oaThreadAttribs;
108 PIMAGE_NT_HEADERS pinhHeader =
109 RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress);
110
111 DPRINT
112 (
113 "hProcess %08X\n"
114 "lpThreadAttributes %08X\n"
115 "dwStackSize %08X\n"
116 "lpStartAddress %08X\n"
117 "lpParameter %08X\n"
118 "dwCreationFlags %08X\n"
119 "lpThreadId %08X\n",
120 hProcess,
121 lpThreadAttributes,
122 dwStackSize,
123 lpStartAddress,
124 lpParameter,
125 dwCreationFlags,
126 lpThreadId
127 );
128
129 /* FIXME: do more checks - e.g. the image may not have an optional header */
130 if(pinhHeader == NULL)
131 {
132 nStackReserve = 0x100000;
133 nStackCommit = PAGE_SIZE;
134 }
135 else
136 {
137 nStackReserve = pinhHeader->OptionalHeader.SizeOfStackReserve;
138 nStackCommit = pinhHeader->OptionalHeader.SizeOfStackCommit;
139 }
140
141 /* FIXME: this should be defined in winbase.h */
142 #ifndef STACK_SIZE_PARAM_IS_A_RESERVATION
143 #define STACK_SIZE_PARAM_IS_A_RESERVATION 0x00010000
144 #endif
145
146 /* use defaults */
147 if(dwStackSize == 0);
148 /* dwStackSize specifies the size to reserve */
149 else if(dwCreationFlags & STACK_SIZE_PARAM_IS_A_RESERVATION)
150 nStackReserve = dwStackSize;
151 /* dwStackSize specifies the size to commit */
152 else
153 nStackCommit = dwStackSize;
154
155 /* fix the stack reserve size */
156 if(nStackCommit > nStackReserve)
157 nStackReserve = ROUNDUP(nStackCommit, 0x100000);
158
159 /* initialize the attributes for the thread object */
160 InitializeObjectAttributes
161 (
162 &oaThreadAttribs,
163 NULL,
164 0,
165 NULL,
166 NULL
167 );
168
169 if(lpThreadAttributes)
170 {
171 /* make the handle inheritable */
172 if(lpThreadAttributes->bInheritHandle)
173 oaThreadAttribs.Attributes |= OBJ_INHERIT;
174
175 /* user-defined security descriptor */
176 oaThreadAttribs.SecurityDescriptor = lpThreadAttributes->lpSecurityDescriptor;
177 }
178
179 DPRINT
180 (
181 "RtlRosCreateUserThreadVa\n"
182 "(\n"
183 " ProcessHandle %p,\n"
184 " ObjectAttributes %p,\n"
185 " CreateSuspended %d,\n"
186 " StackZeroBits %d,\n"
187 " StackReserve %lu,\n"
188 " StackCommit %lu,\n"
189 " StartAddress %p,\n"
190 " ThreadHandle %p,\n"
191 " ClientId %p,\n"
192 " ParameterCount %u,\n"
193 " Parameters[0] %p,\n"
194 " Parameters[1] %p\n"
195 ")\n",
196 hProcess,
197 &oaThreadAttribs,
198 dwCreationFlags & CREATE_SUSPENDED,
199 0,
200 nStackReserve,
201 nStackCommit,
202 ThreadStartup,
203 &hThread,
204 &cidClientId,
205 2,
206 lpStartAddress,
207 lpParameter
208 );
209
210 /* create the thread */
211 nErrCode = RtlRosCreateUserThreadVa
212 (
213 hProcess,
214 &oaThreadAttribs,
215 dwCreationFlags & CREATE_SUSPENDED,
216 0,
217 &nStackReserve,
218 &nStackCommit,
219 (PTHREAD_START_ROUTINE)ThreadStartup,
220 &hThread,
221 &cidClientId,
222 2,
223 lpStartAddress,
224 lpParameter
225 );
226
227 /* failure */
228 if(!NT_SUCCESS(nErrCode))
229 {
230 SetLastErrorByStatus(nErrCode);
231 return NULL;
232 }
233
234 DPRINT
235 (
236 "StackReserve %p\n"
237 "StackCommit %p\n"
238 "ThreadHandle %p\n"
239 "ClientId.UniqueThread %p\n",
240 nStackReserve,
241 nStackCommit,
242 hThread,
243 cidClientId.UniqueThread
244 );
245
246 /* success */
247 if(lpThreadId) *lpThreadId = (DWORD)cidClientId.UniqueThread;
248 return hThread;
249 }
250
251
252 /*
253 * @implemented
254 */
255 PTEB
256 GetTeb(VOID)
257 {
258 return(NtCurrentTeb());
259 }
260
261
262 /*
263 * @implemented
264 */
265 BOOL STDCALL
266 SwitchToThread(VOID)
267 {
268 NTSTATUS errCode;
269 errCode = NtYieldExecution();
270 return TRUE;
271 }
272
273
274 /*
275 * @implemented
276 */
277 DWORD STDCALL
278 GetCurrentThreadId(VOID)
279 {
280 return((DWORD)(NtCurrentTeb()->Cid).UniqueThread);
281 }
282
283 /*
284 * @implemented
285 */
286 VOID STDCALL
287 ExitThread(DWORD uExitCode)
288 {
289 NTSTATUS Status;
290 BOOLEAN LastThread;
291
292 /*
293 * Terminate process if this is the last thread
294 * of the current process
295 */
296 Status = NtQueryInformationThread(NtCurrentThread(),
297 ThreadAmILastThread,
298 &LastThread,
299 sizeof(BOOLEAN),
300 NULL);
301 if (NT_SUCCESS(Status) && LastThread == TRUE)
302 {
303 ExitProcess(uExitCode);
304 }
305
306 /* FIXME: notify csrss of thread termination */
307
308 LdrShutdownThread();
309
310 RtlRosExitUserThread(uExitCode);
311 }
312
313
314 /*
315 * @implemented
316 */
317 BOOL STDCALL
318 GetThreadTimes(HANDLE hThread,
319 LPFILETIME lpCreationTime,
320 LPFILETIME lpExitTime,
321 LPFILETIME lpKernelTime,
322 LPFILETIME lpUserTime)
323 {
324 KERNEL_USER_TIMES KernelUserTimes;
325 ULONG ReturnLength;
326 NTSTATUS Status;
327
328 Status = NtQueryInformationThread(hThread,
329 ThreadTimes,
330 &KernelUserTimes,
331 sizeof(KERNEL_USER_TIMES),
332 &ReturnLength);
333 if (!NT_SUCCESS(Status))
334 {
335 SetLastErrorByStatus(Status);
336 return(FALSE);
337 }
338
339 memcpy(lpCreationTime, &KernelUserTimes.CreateTime, sizeof(FILETIME));
340 memcpy(lpExitTime, &KernelUserTimes.ExitTime, sizeof(FILETIME));
341 memcpy(lpKernelTime, &KernelUserTimes.KernelTime, sizeof(FILETIME));
342 memcpy(lpUserTime, &KernelUserTimes.UserTime, sizeof(FILETIME));
343
344 return(TRUE);
345 }
346
347
348 /*
349 * @implemented
350 */
351 BOOL STDCALL
352 GetThreadContext(HANDLE hThread,
353 LPCONTEXT lpContext)
354 {
355 NTSTATUS Status;
356
357 Status = NtGetContextThread(hThread,
358 lpContext);
359 if (!NT_SUCCESS(Status))
360 {
361 SetLastErrorByStatus(Status);
362 return(FALSE);
363 }
364
365 return(TRUE);
366 }
367
368
369 /*
370 * @implemented
371 */
372 BOOL STDCALL
373 SetThreadContext(HANDLE hThread,
374 CONST CONTEXT *lpContext)
375 {
376 NTSTATUS Status;
377
378 Status = NtSetContextThread(hThread,
379 (void *)lpContext);
380 if (!NT_SUCCESS(Status))
381 {
382 SetLastErrorByStatus(Status);
383 return(FALSE);
384 }
385
386 return(TRUE);
387 }
388
389
390 /*
391 * @implemented
392 */
393 BOOL STDCALL
394 GetExitCodeThread(HANDLE hThread,
395 LPDWORD lpExitCode)
396 {
397 THREAD_BASIC_INFORMATION ThreadBasic;
398 ULONG DataWritten;
399 NTSTATUS Status;
400
401 Status = NtQueryInformationThread(hThread,
402 ThreadBasicInformation,
403 &ThreadBasic,
404 sizeof(THREAD_BASIC_INFORMATION),
405 &DataWritten);
406 if (!NT_SUCCESS(Status))
407 {
408 SetLastErrorByStatus(Status);
409 return(FALSE);
410 }
411
412 memcpy(lpExitCode, &ThreadBasic.ExitStatus, sizeof(DWORD));
413
414 return(TRUE);
415 }
416
417
418 /*
419 * @implemented
420 */
421 DWORD STDCALL
422 ResumeThread(HANDLE hThread)
423 {
424 ULONG PreviousResumeCount;
425 NTSTATUS Status;
426
427 Status = NtResumeThread(hThread,
428 &PreviousResumeCount);
429 if (!NT_SUCCESS(Status))
430 {
431 SetLastErrorByStatus(Status);
432 return(-1);
433 }
434
435 return(PreviousResumeCount);
436 }
437
438
439 /*
440 * @implemented
441 */
442 BOOL STDCALL
443 TerminateThread(HANDLE hThread,
444 DWORD dwExitCode)
445 {
446 NTSTATUS Status;
447
448 if (0 == hThread)
449 {
450 SetLastError(ERROR_INVALID_HANDLE);
451 return(FALSE);
452 }
453
454 Status = NtTerminateThread(hThread,
455 dwExitCode);
456 if (!NT_SUCCESS(Status))
457 {
458 SetLastErrorByStatus(Status);
459 return(FALSE);
460 }
461
462 return(TRUE);
463 }
464
465
466 /*
467 * @implemented
468 */
469 DWORD STDCALL
470 SuspendThread(HANDLE hThread)
471 {
472 ULONG PreviousSuspendCount;
473 NTSTATUS Status;
474
475 Status = NtSuspendThread(hThread,
476 &PreviousSuspendCount);
477 if (!NT_SUCCESS(Status))
478 {
479 SetLastErrorByStatus(Status);
480 return(-1);
481 }
482
483 return(PreviousSuspendCount);
484 }
485
486
487 /*
488 * @implemented
489 */
490 DWORD STDCALL
491 SetThreadAffinityMask(HANDLE hThread,
492 DWORD dwThreadAffinityMask)
493 {
494 THREAD_BASIC_INFORMATION ThreadBasic;
495 KAFFINITY AffinityMask;
496 ULONG DataWritten;
497 NTSTATUS Status;
498
499 AffinityMask = (KAFFINITY)dwThreadAffinityMask;
500
501 Status = NtQueryInformationThread(hThread,
502 ThreadBasicInformation,
503 &ThreadBasic,
504 sizeof(THREAD_BASIC_INFORMATION),
505 &DataWritten);
506 if (!NT_SUCCESS(Status))
507 {
508 SetLastErrorByStatus(Status);
509 return(0);
510 }
511
512 Status = NtSetInformationThread(hThread,
513 ThreadAffinityMask,
514 &AffinityMask,
515 sizeof(KAFFINITY));
516 if (!NT_SUCCESS(Status))
517 SetLastErrorByStatus(Status);
518
519 return(ThreadBasic.AffinityMask);
520 }
521
522
523 /*
524 * @implemented
525 */
526 BOOL STDCALL
527 SetThreadPriority(HANDLE hThread,
528 int nPriority)
529 {
530 ULONG Prio = nPriority;
531 NTSTATUS Status;
532
533 Status = NtSetInformationThread(hThread,
534 ThreadBasePriority,
535 &Prio,
536 sizeof(ULONG));
537
538 if (!NT_SUCCESS(Status))
539 {
540 SetLastErrorByStatus(Status);
541 return(FALSE);
542 }
543
544 return(TRUE);
545 }
546
547
548 /*
549 * @implemented
550 */
551 int STDCALL
552 GetThreadPriority(HANDLE hThread)
553 {
554 THREAD_BASIC_INFORMATION ThreadBasic;
555 ULONG DataWritten;
556 NTSTATUS Status;
557
558 Status = NtQueryInformationThread(hThread,
559 ThreadBasicInformation,
560 &ThreadBasic,
561 sizeof(THREAD_BASIC_INFORMATION),
562 &DataWritten);
563 if (!NT_SUCCESS(Status))
564 {
565 SetLastErrorByStatus(Status);
566 return(THREAD_PRIORITY_ERROR_RETURN);
567 }
568
569 return(ThreadBasic.BasePriority);
570 }
571
572
573 /*
574 * @implemented
575 */
576 BOOL STDCALL
577 GetThreadPriorityBoost(IN HANDLE hThread,
578 OUT PBOOL pDisablePriorityBoost)
579 {
580 ULONG PriorityBoost;
581 ULONG DataWritten;
582 NTSTATUS Status;
583
584 Status = NtQueryInformationThread(hThread,
585 ThreadPriorityBoost,
586 &PriorityBoost,
587 sizeof(ULONG),
588 &DataWritten);
589 if (!NT_SUCCESS(Status))
590 {
591 SetLastErrorByStatus(Status);
592 return(FALSE);
593 }
594
595 *pDisablePriorityBoost = !((BOOL)PriorityBoost);
596
597 return(TRUE);
598 }
599
600
601 /*
602 * @implemented
603 */
604 BOOL STDCALL
605 SetThreadPriorityBoost(IN HANDLE hThread,
606 IN BOOL bDisablePriorityBoost)
607 {
608 ULONG PriorityBoost;
609 NTSTATUS Status;
610
611 PriorityBoost = (ULONG)!bDisablePriorityBoost;
612
613 Status = NtSetInformationThread(hThread,
614 ThreadPriorityBoost,
615 &PriorityBoost,
616 sizeof(ULONG));
617 if (!NT_SUCCESS(Status))
618 {
619 SetLastErrorByStatus(Status);
620 return(FALSE);
621 }
622
623 return(TRUE);
624 }
625
626
627 /*
628 * @implemented
629 */
630 BOOL STDCALL
631 GetThreadSelectorEntry(IN HANDLE hThread,
632 IN DWORD dwSelector,
633 OUT LPLDT_ENTRY lpSelectorEntry)
634 {
635 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
636 return(FALSE);
637 }
638
639
640 /*
641 * @implemented
642 */
643 BOOL STDCALL
644 SetThreadIdealProcessor(HANDLE hThread,
645 DWORD dwIdealProcessor)
646 {
647 ULONG IdealProcessor;
648 NTSTATUS Status;
649
650 IdealProcessor = (ULONG)dwIdealProcessor;
651
652 Status = NtSetInformationThread(hThread,
653 ThreadIdealProcessor,
654 &IdealProcessor,
655 sizeof(ULONG));
656 if (!NT_SUCCESS(Status))
657 {
658 SetLastErrorByStatus(Status);
659 return(FALSE);
660 }
661
662 return(TRUE);
663 }
664
665 /* EOF */