Copy msimg32
[reactos.git] / reactos / lib / kernel32 / thread / thread.c
1 /* $Id$
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 EXCEPTION_POINTERS ExceptionInfo;
32 EXCEPTION_DISPOSITION ExceptionDisposition;
33
34 ExceptionInfo.ExceptionRecord = ExceptionRecord;
35 ExceptionInfo.ContextRecord = ContextRecord;
36
37 if (GlobalTopLevelExceptionFilter != NULL)
38 {
39 _SEH_TRY
40 {
41 ExceptionDisposition = GlobalTopLevelExceptionFilter(&ExceptionInfo);
42 }
43 _SEH_HANDLE
44 {
45 ExceptionDisposition = UnhandledExceptionFilter(&ExceptionInfo);
46 }
47 _SEH_END;
48 }
49 else
50 {
51 ExceptionDisposition = EXCEPTION_EXECUTE_HANDLER;
52 }
53
54 if (ExceptionDisposition == EXCEPTION_EXECUTE_HANDLER)
55 ExitThread(ExceptionRecord->ExceptionCode);
56
57 /* translate EXCEPTION_XXX defines into EXCEPTION_DISPOSITION enum values */
58 if (ExceptionDisposition == EXCEPTION_CONTINUE_EXECUTION)
59 return ExceptionContinueExecution;
60 else if (ExceptionDisposition == EXCEPTION_CONTINUE_SEARCH)
61 return ExceptionContinueSearch;
62
63 return -1; /* unknown return from UnhandledExceptionFilter */
64 }
65
66
67 __declspec(noreturn) void STDCALL
68 ThreadStartup
69 (
70 LPTHREAD_START_ROUTINE lpStartAddress,
71 LPVOID lpParameter
72 )
73 {
74 volatile UINT uExitCode = 0;
75
76 __try1(_except_handler)
77 {
78 /* FIXME: notify csrss of thread creation ?? */
79 uExitCode = (lpStartAddress)(lpParameter);
80 }
81 __except1
82
83 ExitThread(uExitCode);
84 }
85
86
87 /*
88 * @implemented
89 */
90 HANDLE STDCALL
91 CreateThread
92 (
93 LPSECURITY_ATTRIBUTES lpThreadAttributes,
94 DWORD dwStackSize,
95 LPTHREAD_START_ROUTINE lpStartAddress,
96 LPVOID lpParameter,
97 DWORD dwCreationFlags,
98 LPDWORD lpThreadId
99 )
100 {
101 return CreateRemoteThread
102 (
103 NtCurrentProcess(),
104 lpThreadAttributes,
105 dwStackSize,
106 lpStartAddress,
107 lpParameter,
108 dwCreationFlags,
109 lpThreadId
110 );
111 }
112
113
114 /*
115 * @implemented
116 */
117 HANDLE STDCALL
118 CreateRemoteThread
119 (
120 HANDLE hProcess,
121 LPSECURITY_ATTRIBUTES lpThreadAttributes,
122 DWORD dwStackSize,
123 LPTHREAD_START_ROUTINE lpStartAddress,
124 LPVOID lpParameter,
125 DWORD dwCreationFlags,
126 LPDWORD lpThreadId
127 )
128 {
129 HANDLE hThread;
130 CLIENT_ID cidClientId;
131 NTSTATUS nErrCode;
132 ULONG_PTR nStackReserve;
133 ULONG_PTR nStackCommit;
134 OBJECT_ATTRIBUTES oaThreadAttribs;
135 PIMAGE_NT_HEADERS pinhHeader =
136 RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress);
137
138 DPRINT
139 (
140 "hProcess %08X\n"
141 "lpThreadAttributes %08X\n"
142 "dwStackSize %08X\n"
143 "lpStartAddress %08X\n"
144 "lpParameter %08X\n"
145 "dwCreationFlags %08X\n"
146 "lpThreadId %08X\n",
147 hProcess,
148 lpThreadAttributes,
149 dwStackSize,
150 lpStartAddress,
151 lpParameter,
152 dwCreationFlags,
153 lpThreadId
154 );
155
156 /* FIXME: do more checks - e.g. the image may not have an optional header */
157 if(pinhHeader == NULL)
158 {
159 nStackReserve = 0x100000;
160 nStackCommit = PAGE_SIZE;
161 }
162 else
163 {
164 nStackReserve = pinhHeader->OptionalHeader.SizeOfStackReserve;
165 nStackCommit = pinhHeader->OptionalHeader.SizeOfStackCommit;
166 }
167
168 /* FIXME: this should be defined in winbase.h */
169 #ifndef STACK_SIZE_PARAM_IS_A_RESERVATION
170 #define STACK_SIZE_PARAM_IS_A_RESERVATION 0x00010000
171 #endif
172
173 /* use defaults */
174 if(dwStackSize == 0);
175 /* dwStackSize specifies the size to reserve */
176 else if(dwCreationFlags & STACK_SIZE_PARAM_IS_A_RESERVATION)
177 nStackReserve = dwStackSize;
178 /* dwStackSize specifies the size to commit */
179 else
180 nStackCommit = dwStackSize;
181
182 /* fix the stack reserve size */
183 if(nStackCommit > nStackReserve)
184 nStackReserve = ROUNDUP(nStackCommit, 0x100000);
185
186 /* initialize the attributes for the thread object */
187 InitializeObjectAttributes
188 (
189 &oaThreadAttribs,
190 NULL,
191 0,
192 NULL,
193 NULL
194 );
195
196 if(lpThreadAttributes)
197 {
198 /* make the handle inheritable */
199 if(lpThreadAttributes->bInheritHandle)
200 oaThreadAttribs.Attributes |= OBJ_INHERIT;
201
202 /* user-defined security descriptor */
203 oaThreadAttribs.SecurityDescriptor = lpThreadAttributes->lpSecurityDescriptor;
204 }
205
206 DPRINT
207 (
208 "RtlRosCreateUserThreadVa\n"
209 "(\n"
210 " ProcessHandle %p,\n"
211 " ObjectAttributes %p,\n"
212 " CreateSuspended %d,\n"
213 " StackZeroBits %d,\n"
214 " StackReserve %lu,\n"
215 " StackCommit %lu,\n"
216 " StartAddress %p,\n"
217 " ThreadHandle %p,\n"
218 " ClientId %p,\n"
219 " ParameterCount %u,\n"
220 " Parameters[0] %p,\n"
221 " Parameters[1] %p\n"
222 ")\n",
223 hProcess,
224 &oaThreadAttribs,
225 dwCreationFlags & CREATE_SUSPENDED,
226 0,
227 nStackReserve,
228 nStackCommit,
229 ThreadStartup,
230 &hThread,
231 &cidClientId,
232 2,
233 lpStartAddress,
234 lpParameter
235 );
236
237 /* create the thread */
238 nErrCode = RtlRosCreateUserThreadVa
239 (
240 hProcess,
241 &oaThreadAttribs,
242 dwCreationFlags & CREATE_SUSPENDED,
243 0,
244 &nStackReserve,
245 &nStackCommit,
246 (PTHREAD_START_ROUTINE)ThreadStartup,
247 &hThread,
248 &cidClientId,
249 2,
250 lpStartAddress,
251 lpParameter
252 );
253
254 /* failure */
255 if(!NT_SUCCESS(nErrCode))
256 {
257 SetLastErrorByStatus(nErrCode);
258 return NULL;
259 }
260
261 DPRINT
262 (
263 "StackReserve %p\n"
264 "StackCommit %p\n"
265 "ThreadHandle %p\n"
266 "ClientId.UniqueThread %p\n",
267 nStackReserve,
268 nStackCommit,
269 hThread,
270 cidClientId.UniqueThread
271 );
272
273 /* success */
274 if(lpThreadId) *lpThreadId = (DWORD)cidClientId.UniqueThread;
275 return hThread;
276 }
277
278
279 /*
280 * @implemented
281 */
282 HANDLE
283 STDCALL
284 OpenThread(
285 DWORD dwDesiredAccess,
286 BOOL bInheritHandle,
287 DWORD dwThreadId
288 )
289 {
290 NTSTATUS errCode;
291 HANDLE ThreadHandle;
292 OBJECT_ATTRIBUTES ObjectAttributes;
293 CLIENT_ID ClientId ;
294
295 ClientId.UniqueProcess = INVALID_HANDLE_VALUE;
296 ClientId.UniqueThread = (HANDLE)dwThreadId;
297
298 InitializeObjectAttributes (&ObjectAttributes,
299 NULL,
300 (bInheritHandle ? OBJ_INHERIT : 0),
301 NULL,
302 NULL);
303
304 errCode = NtOpenThread(&ThreadHandle,
305 dwDesiredAccess,
306 &ObjectAttributes,
307 &ClientId);
308 if (!NT_SUCCESS(errCode))
309 {
310 SetLastErrorByStatus (errCode);
311 return NULL;
312 }
313 return ThreadHandle;
314 }
315
316
317 /*
318 * @implemented
319 */
320 PTEB
321 GetTeb(VOID)
322 {
323 return(NtCurrentTeb());
324 }
325
326
327 /*
328 * @implemented
329 */
330 BOOL STDCALL
331 SwitchToThread(VOID)
332 {
333 NTSTATUS errCode;
334 errCode = NtYieldExecution();
335 return TRUE;
336 }
337
338
339 /*
340 * @implemented
341 */
342 DWORD STDCALL
343 GetCurrentThreadId(VOID)
344 {
345 return((DWORD)(NtCurrentTeb()->Cid).UniqueThread);
346 }
347
348 /*
349 * @implemented
350 */
351 VOID STDCALL
352 ExitThread(DWORD uExitCode)
353 {
354 NTSTATUS Status;
355 BOOLEAN LastThread;
356
357 /*
358 * Terminate process if this is the last thread
359 * of the current process
360 */
361 Status = NtQueryInformationThread(NtCurrentThread(),
362 ThreadAmILastThread,
363 &LastThread,
364 sizeof(BOOLEAN),
365 NULL);
366 if (NT_SUCCESS(Status) && LastThread == TRUE)
367 {
368 ExitProcess(uExitCode);
369 }
370
371 /* FIXME: notify csrss of thread termination */
372
373 LdrShutdownThread();
374
375 RtlRosExitUserThread(uExitCode);
376 }
377
378
379 /*
380 * @implemented
381 */
382 BOOL STDCALL
383 GetThreadTimes(HANDLE hThread,
384 LPFILETIME lpCreationTime,
385 LPFILETIME lpExitTime,
386 LPFILETIME lpKernelTime,
387 LPFILETIME lpUserTime)
388 {
389 KERNEL_USER_TIMES KernelUserTimes;
390 NTSTATUS Status;
391
392 Status = NtQueryInformationThread(hThread,
393 ThreadTimes,
394 &KernelUserTimes,
395 sizeof(KERNEL_USER_TIMES),
396 NULL);
397 if (!NT_SUCCESS(Status))
398 {
399 SetLastErrorByStatus(Status);
400 return(FALSE);
401 }
402
403 lpCreationTime->dwLowDateTime = KernelUserTimes.CreateTime.u.LowPart;
404 lpCreationTime->dwHighDateTime = KernelUserTimes.CreateTime.u.HighPart;
405
406 lpExitTime->dwLowDateTime = KernelUserTimes.ExitTime.u.LowPart;
407 lpExitTime->dwHighDateTime = KernelUserTimes.ExitTime.u.HighPart;
408
409 lpKernelTime->dwLowDateTime = KernelUserTimes.KernelTime.u.LowPart;
410 lpKernelTime->dwHighDateTime = KernelUserTimes.KernelTime.u.HighPart;
411
412 lpUserTime->dwLowDateTime = KernelUserTimes.UserTime.u.LowPart;
413 lpUserTime->dwHighDateTime = KernelUserTimes.UserTime.u.HighPart;
414
415 return(TRUE);
416 }
417
418
419 /*
420 * @implemented
421 */
422 BOOL STDCALL
423 GetThreadContext(HANDLE hThread,
424 LPCONTEXT lpContext)
425 {
426 NTSTATUS Status;
427
428 Status = NtGetContextThread(hThread,
429 lpContext);
430 if (!NT_SUCCESS(Status))
431 {
432 SetLastErrorByStatus(Status);
433 return(FALSE);
434 }
435
436 return(TRUE);
437 }
438
439
440 /*
441 * @implemented
442 */
443 BOOL STDCALL
444 SetThreadContext(HANDLE hThread,
445 CONST CONTEXT *lpContext)
446 {
447 NTSTATUS Status;
448
449 Status = NtSetContextThread(hThread,
450 (void *)lpContext);
451 if (!NT_SUCCESS(Status))
452 {
453 SetLastErrorByStatus(Status);
454 return(FALSE);
455 }
456
457 return(TRUE);
458 }
459
460
461 /*
462 * @implemented
463 */
464 BOOL STDCALL
465 GetExitCodeThread(HANDLE hThread,
466 LPDWORD lpExitCode)
467 {
468 THREAD_BASIC_INFORMATION ThreadBasic;
469 NTSTATUS Status;
470
471 Status = NtQueryInformationThread(hThread,
472 ThreadBasicInformation,
473 &ThreadBasic,
474 sizeof(THREAD_BASIC_INFORMATION),
475 NULL);
476 if (!NT_SUCCESS(Status))
477 {
478 SetLastErrorByStatus(Status);
479 return(FALSE);
480 }
481
482 memcpy(lpExitCode, &ThreadBasic.ExitStatus, sizeof(DWORD));
483
484 return(TRUE);
485 }
486
487
488 /*
489 * @implemented
490 */
491 DWORD STDCALL
492 ResumeThread(HANDLE hThread)
493 {
494 ULONG PreviousResumeCount;
495 NTSTATUS Status;
496
497 Status = NtResumeThread(hThread,
498 &PreviousResumeCount);
499 if (!NT_SUCCESS(Status))
500 {
501 SetLastErrorByStatus(Status);
502 return(-1);
503 }
504
505 return(PreviousResumeCount);
506 }
507
508
509 /*
510 * @implemented
511 */
512 BOOL STDCALL
513 TerminateThread(HANDLE hThread,
514 DWORD dwExitCode)
515 {
516 NTSTATUS Status;
517
518 if (0 == hThread)
519 {
520 SetLastError(ERROR_INVALID_HANDLE);
521 return(FALSE);
522 }
523
524 Status = NtTerminateThread(hThread,
525 dwExitCode);
526 if (!NT_SUCCESS(Status))
527 {
528 SetLastErrorByStatus(Status);
529 return(FALSE);
530 }
531
532 return(TRUE);
533 }
534
535
536 /*
537 * @implemented
538 */
539 DWORD STDCALL
540 SuspendThread(HANDLE hThread)
541 {
542 ULONG PreviousSuspendCount;
543 NTSTATUS Status;
544
545 Status = NtSuspendThread(hThread,
546 &PreviousSuspendCount);
547 if (!NT_SUCCESS(Status))
548 {
549 SetLastErrorByStatus(Status);
550 return(-1);
551 }
552
553 return(PreviousSuspendCount);
554 }
555
556
557 /*
558 * @implemented
559 */
560 DWORD STDCALL
561 SetThreadAffinityMask(HANDLE hThread,
562 DWORD dwThreadAffinityMask)
563 {
564 THREAD_BASIC_INFORMATION ThreadBasic;
565 KAFFINITY AffinityMask;
566 NTSTATUS Status;
567
568 AffinityMask = (KAFFINITY)dwThreadAffinityMask;
569
570 Status = NtQueryInformationThread(hThread,
571 ThreadBasicInformation,
572 &ThreadBasic,
573 sizeof(THREAD_BASIC_INFORMATION),
574 NULL);
575 if (!NT_SUCCESS(Status))
576 {
577 SetLastErrorByStatus(Status);
578 return(0);
579 }
580
581 Status = NtSetInformationThread(hThread,
582 ThreadAffinityMask,
583 &AffinityMask,
584 sizeof(KAFFINITY));
585 if (!NT_SUCCESS(Status))
586 SetLastErrorByStatus(Status);
587
588 return(ThreadBasic.AffinityMask);
589 }
590
591
592 /*
593 * @implemented
594 */
595 BOOL STDCALL
596 SetThreadPriority(HANDLE hThread,
597 int nPriority)
598 {
599 ULONG Prio = nPriority;
600 NTSTATUS Status;
601
602 Status = NtSetInformationThread(hThread,
603 ThreadBasePriority,
604 &Prio,
605 sizeof(ULONG));
606
607 if (!NT_SUCCESS(Status))
608 {
609 SetLastErrorByStatus(Status);
610 return(FALSE);
611 }
612
613 return(TRUE);
614 }
615
616
617 /*
618 * @implemented
619 */
620 int STDCALL
621 GetThreadPriority(HANDLE hThread)
622 {
623 THREAD_BASIC_INFORMATION ThreadBasic;
624 NTSTATUS Status;
625
626 Status = NtQueryInformationThread(hThread,
627 ThreadBasicInformation,
628 &ThreadBasic,
629 sizeof(THREAD_BASIC_INFORMATION),
630 NULL);
631 if (!NT_SUCCESS(Status))
632 {
633 SetLastErrorByStatus(Status);
634 return(THREAD_PRIORITY_ERROR_RETURN);
635 }
636
637 return(ThreadBasic.BasePriority);
638 }
639
640
641 /*
642 * @implemented
643 */
644 BOOL STDCALL
645 GetThreadPriorityBoost(IN HANDLE hThread,
646 OUT PBOOL pDisablePriorityBoost)
647 {
648 ULONG PriorityBoost;
649 NTSTATUS Status;
650
651 Status = NtQueryInformationThread(hThread,
652 ThreadPriorityBoost,
653 &PriorityBoost,
654 sizeof(ULONG),
655 NULL);
656 if (!NT_SUCCESS(Status))
657 {
658 SetLastErrorByStatus(Status);
659 return(FALSE);
660 }
661
662 *pDisablePriorityBoost = !((BOOL)PriorityBoost);
663
664 return(TRUE);
665 }
666
667
668 /*
669 * @implemented
670 */
671 BOOL STDCALL
672 SetThreadPriorityBoost(IN HANDLE hThread,
673 IN BOOL bDisablePriorityBoost)
674 {
675 ULONG PriorityBoost;
676 NTSTATUS Status;
677
678 PriorityBoost = (ULONG)!bDisablePriorityBoost;
679
680 Status = NtSetInformationThread(hThread,
681 ThreadPriorityBoost,
682 &PriorityBoost,
683 sizeof(ULONG));
684 if (!NT_SUCCESS(Status))
685 {
686 SetLastErrorByStatus(Status);
687 return(FALSE);
688 }
689
690 return(TRUE);
691 }
692
693
694 /*
695 * @implemented
696 */
697 BOOL STDCALL
698 GetThreadSelectorEntry(IN HANDLE hThread,
699 IN DWORD dwSelector,
700 OUT LPLDT_ENTRY lpSelectorEntry)
701 {
702 DESCRIPTOR_TABLE_ENTRY DescriptionTableEntry;
703 NTSTATUS Status;
704
705 DescriptionTableEntry.Selector = dwSelector;
706 Status = NtQueryInformationThread(hThread,
707 ThreadDescriptorTableEntry,
708 &DescriptionTableEntry,
709 sizeof(DESCRIPTOR_TABLE_ENTRY),
710 NULL);
711 if(!NT_SUCCESS(Status))
712 {
713 SetLastErrorByStatus(Status);
714 return FALSE;
715 }
716
717 *lpSelectorEntry = DescriptionTableEntry.Descriptor;
718 return TRUE;
719 }
720
721
722 /*
723 * @implemented
724 */
725 DWORD STDCALL
726 SetThreadIdealProcessor(HANDLE hThread,
727 DWORD dwIdealProcessor)
728 {
729 NTSTATUS Status;
730
731 Status = NtSetInformationThread(hThread,
732 ThreadIdealProcessor,
733 &dwIdealProcessor,
734 sizeof(ULONG));
735 if (!NT_SUCCESS(Status))
736 {
737 SetLastErrorByStatus(Status);
738 return -1;
739 }
740
741 return dwIdealProcessor;
742 }
743
744
745 /*
746 * @implemented
747 */
748 DWORD STDCALL
749 GetProcessIdOfThread(HANDLE Thread)
750 {
751 THREAD_BASIC_INFORMATION ThreadBasic;
752 NTSTATUS Status;
753
754 Status = NtQueryInformationThread(Thread,
755 ThreadBasicInformation,
756 &ThreadBasic,
757 sizeof(THREAD_BASIC_INFORMATION),
758 NULL);
759 if(!NT_SUCCESS(Status))
760 {
761 SetLastErrorByStatus(Status);
762 return 0;
763 }
764
765 return (DWORD)ThreadBasic.ClientId.UniqueProcess;
766 }
767
768
769 /*
770 * @implemented
771 */
772 DWORD STDCALL
773 GetThreadId(HANDLE Thread)
774 {
775 THREAD_BASIC_INFORMATION ThreadBasic;
776 NTSTATUS Status;
777
778 Status = NtQueryInformationThread(Thread,
779 ThreadBasicInformation,
780 &ThreadBasic,
781 sizeof(THREAD_BASIC_INFORMATION),
782 NULL);
783 if(!NT_SUCCESS(Status))
784 {
785 SetLastErrorByStatus(Status);
786 return 0;
787 }
788
789 return (DWORD)ThreadBasic.ClientId.UniqueThread;
790 }
791
792 /*
793 * @unimplemented
794 */
795 VOID STDCALL
796 SetThreadUILanguage(DWORD Unknown1)
797 {
798 DPRINT1("SetThreadUILanguage(0x%x) unimplemented!\n", Unknown1);
799 }
800
801 static void CALLBACK
802 IntCallUserApc(PVOID Function, PVOID dwData, PVOID Argument3)
803 {
804 PAPCFUNC pfnAPC = (PAPCFUNC)Function;
805 pfnAPC((ULONG_PTR)dwData);
806 }
807
808 /*
809 * @implemented
810 */
811 DWORD STDCALL
812 QueueUserAPC(PAPCFUNC pfnAPC, HANDLE hThread, ULONG_PTR dwData)
813 {
814 NTSTATUS Status;
815
816 Status = NtQueueApcThread(hThread, IntCallUserApc, pfnAPC,
817 (PVOID)dwData, NULL);
818 if (Status)
819 SetLastErrorByStatus(Status);
820
821 return NT_SUCCESS(Status);
822 }
823
824 /*
825 * @implemented
826 */
827 BOOL STDCALL
828 GetThreadIOPendingFlag(HANDLE hThread,
829 PBOOL lpIOIsPending)
830 {
831 ULONG IoPending;
832 NTSTATUS Status;
833
834 if(lpIOIsPending == NULL)
835 {
836 SetLastError(ERROR_INVALID_PARAMETER);
837 return FALSE;
838 }
839
840 Status = NtQueryInformationThread(hThread,
841 ThreadIsIoPending,
842 (PVOID)&IoPending,
843 sizeof(IoPending),
844 NULL);
845 if(NT_SUCCESS(Status))
846 {
847 *lpIOIsPending = ((IoPending != 0) ? TRUE : FALSE);
848 return TRUE;
849 }
850
851 SetLastErrorByStatus(Status);
852 return FALSE;
853 }
854
855 /* EOF */