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