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