[SAL]
[reactos.git] / reactos / dll / win32 / kernel32 / client / 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 <debug.h>
17
18 #define SXS_SUPPORT_FIXME
19
20 typedef NTSTATUS (NTAPI *PCSR_CREATE_REMOTE_THREAD)(IN HANDLE ThreadHandle, IN PCLIENT_ID ClientId);
21
22 NTSTATUS
23 WINAPI
24 BasepNotifyCsrOfThread(IN HANDLE ThreadHandle,
25 IN PCLIENT_ID ClientId);
26
27 /* FUNCTIONS ******************************************************************/
28
29 static
30 LONG BaseThreadExceptionFilter(EXCEPTION_POINTERS * ExceptionInfo)
31 {
32 LONG ExceptionDisposition = EXCEPTION_EXECUTE_HANDLER;
33 LPTOP_LEVEL_EXCEPTION_FILTER RealFilter;
34 RealFilter = RtlDecodePointer(GlobalTopLevelExceptionFilter);
35
36 if (RealFilter != NULL)
37 {
38 _SEH2_TRY
39 {
40 ExceptionDisposition = RealFilter(ExceptionInfo);
41 }
42 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
43 {
44 ExceptionDisposition = UnhandledExceptionFilter(ExceptionInfo);
45 }
46 _SEH2_END;
47 }
48
49 return ExceptionDisposition;
50 }
51
52 __declspec(noreturn)
53 VOID
54 WINAPI
55 BaseThreadStartup(IN LPTHREAD_START_ROUTINE lpStartAddress,
56 IN LPVOID lpParameter)
57 {
58 /* Attempt to call the Thread Start Address */
59 _SEH2_TRY
60 {
61 /* Legacy check which is still used today for Win32 threads */
62 if (NtCurrentTeb()->NtTib.Version == (30 << 8)) // OS/2 V3.0 ("Cruiser")
63 {
64 /* This registers the termination port with CSRSS */
65 if (!BaseRunningInServerProcess) CsrNewThread();
66 }
67
68 /* Get the exit code from the Thread Start */
69 ExitThread((lpStartAddress)((PVOID)lpParameter));
70 }
71 _SEH2_EXCEPT(BaseThreadExceptionFilter(_SEH2_GetExceptionInformation()))
72 {
73 /* Get the Exit code from the SEH Handler */
74 if (!BaseRunningInServerProcess)
75 {
76 /* Kill the whole process, usually */
77 ExitProcess(_SEH2_GetExceptionCode());
78 }
79 else
80 {
81 /* If running inside CSRSS, kill just this thread */
82 ExitThread(_SEH2_GetExceptionCode());
83 }
84 }
85 _SEH2_END;
86 }
87
88 VOID
89 NTAPI
90 BaseDispatchApc(IN PAPCFUNC ApcRoutine,
91 IN PVOID Data,
92 IN PACTIVATION_CONTEXT ActivationContext)
93 {
94 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME ActivationFrame;
95
96 /* Setup the activation context */
97 ActivationFrame.Size = sizeof(ActivationFrame);
98 ActivationFrame.Format = RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER;
99
100 /* Check if caller wanted one */
101 if (ActivationContext == INVALID_ACTIVATION_CONTEXT)
102 {
103 /* Do the APC directly */
104 ApcRoutine((ULONG_PTR)Data);
105 return;
106 }
107
108 /* Then activate it */
109 RtlActivateActivationContextUnsafeFast(&ActivationFrame, ActivationContext);
110
111 /* Call the routine under SEH */
112 _SEH2_TRY
113 {
114 ApcRoutine((ULONG_PTR)Data);
115 }
116 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
117 {
118
119 }
120 _SEH2_END;
121
122 /* Now de-activate and release the activation context */
123 RtlDeactivateActivationContextUnsafeFast(&ActivationFrame);
124 RtlReleaseActivationContext(ActivationContext);
125 }
126
127 /* PUBLIC FUNCTIONS ***********************************************************/
128
129 /*
130 * @implemented
131 */
132 HANDLE
133 WINAPI
134 CreateThread(IN LPSECURITY_ATTRIBUTES lpThreadAttributes,
135 IN DWORD dwStackSize,
136 IN LPTHREAD_START_ROUTINE lpStartAddress,
137 IN LPVOID lpParameter,
138 IN DWORD dwCreationFlags,
139 OUT LPDWORD lpThreadId)
140 {
141 /* Act as if we're going to create a remote thread in ourselves */
142 return CreateRemoteThread(NtCurrentProcess(),
143 lpThreadAttributes,
144 dwStackSize,
145 lpStartAddress,
146 lpParameter,
147 dwCreationFlags,
148 lpThreadId);
149 }
150
151 /*
152 * @implemented
153 */
154 HANDLE
155 WINAPI
156 CreateRemoteThread(IN HANDLE hProcess,
157 IN LPSECURITY_ATTRIBUTES lpThreadAttributes,
158 IN DWORD dwStackSize,
159 IN LPTHREAD_START_ROUTINE lpStartAddress,
160 IN LPVOID lpParameter,
161 IN DWORD dwCreationFlags,
162 OUT LPDWORD lpThreadId)
163 {
164 NTSTATUS Status;
165 INITIAL_TEB InitialTeb;
166 CONTEXT Context;
167 CLIENT_ID ClientId;
168 OBJECT_ATTRIBUTES LocalObjectAttributes;
169 POBJECT_ATTRIBUTES ObjectAttributes;
170 HANDLE hThread;
171 ULONG Dummy;
172 PTEB Teb;
173 THREAD_BASIC_INFORMATION ThreadBasicInfo;
174 PVOID ActivationContextStack = NULL;
175 ACTIVATION_CONTEXT_BASIC_INFORMATION ActCtxInfo;
176 ULONG_PTR Cookie;
177 ULONG ReturnLength;
178 DPRINT("CreateRemoteThread: hProcess: %ld dwStackSize: %ld lpStartAddress"
179 ": %p lpParameter: %lx, dwCreationFlags: %lx\n", hProcess,
180 dwStackSize, lpStartAddress, lpParameter, dwCreationFlags);
181
182 /* Clear the Context */
183 RtlZeroMemory(&Context, sizeof(CONTEXT));
184
185 /* Write PID */
186 ClientId.UniqueProcess = hProcess;
187
188 /* Create the Stack */
189 Status = BaseCreateStack(hProcess,
190 dwStackSize,
191 dwCreationFlags & STACK_SIZE_PARAM_IS_A_RESERVATION ?
192 dwStackSize : 0,
193 &InitialTeb);
194 if(!NT_SUCCESS(Status))
195 {
196 BaseSetLastNTError(Status);
197 return NULL;
198 }
199
200 /* Create Initial Context */
201 BaseInitializeContext(&Context,
202 lpParameter,
203 lpStartAddress,
204 InitialTeb.StackBase,
205 1);
206
207 /* initialize the attributes for the thread object */
208 ObjectAttributes = BaseFormatObjectAttributes(&LocalObjectAttributes,
209 lpThreadAttributes,
210 NULL);
211
212 /* Create the Kernel Thread Object */
213 Status = NtCreateThread(&hThread,
214 THREAD_ALL_ACCESS,
215 ObjectAttributes,
216 hProcess,
217 &ClientId,
218 &Context,
219 &InitialTeb,
220 TRUE);
221 if (!NT_SUCCESS(Status))
222 {
223 /* Fail the kernel create */
224 BaseFreeThreadStack(hProcess, &InitialTeb);
225 BaseSetLastNTError(Status);
226 return NULL;
227 }
228
229 /* Are we in the same process? */
230 if (hProcess == NtCurrentProcess())
231 {
232 /* Get the TEB */
233 Status = NtQueryInformationThread(hThread,
234 ThreadBasicInformation,
235 &ThreadBasicInfo,
236 sizeof(ThreadBasicInfo),
237 &ReturnLength);
238 if (!NT_SUCCESS(Status))
239 {
240 /* Fail */
241 DbgPrint("SXS: %s - Failing thread create because "
242 "NtQueryInformationThread() failed with status %08lx\n",
243 __FUNCTION__, Status);
244 ASSERT(FALSE); // while (TRUE);
245 return NULL;
246 }
247
248 /* Allocate the Activation Context Stack */
249 Status = RtlAllocateActivationContextStack(&ActivationContextStack);
250 if (!NT_SUCCESS(Status))
251 {
252 /* Fail */
253 DbgPrint("SXS: %s - Failing thread create because "
254 "RtlAllocateActivationContextStack() failed with status %08lx\n",
255 __FUNCTION__, Status);
256 ASSERT(FALSE); // while (TRUE);
257 return NULL;
258 }
259
260 /* Save it */
261 Teb = ThreadBasicInfo.TebBaseAddress;
262 Teb->ActivationContextStackPointer = ActivationContextStack;
263
264 /* Query the Context */
265 // WARNING!!! THIS IS USING THE WIN32 FLAG BECAUSE REACTOS CONTINUES TO BE A POS!!! ///
266 Status = RtlQueryInformationActivationContext(QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX,
267 NULL,
268 0,
269 ActivationContextBasicInformation,
270 &ActCtxInfo,
271 sizeof(ActCtxInfo),
272 &ReturnLength);
273 if (!NT_SUCCESS(Status))
274 {
275 /* Fail */
276 DbgPrint("SXS: %s - Failing thread create because "
277 "RtlQueryInformationActivationContext() failed with status %08lx\n",
278 __FUNCTION__, Status);
279 ASSERT(FALSE); // while (TRUE);
280 return NULL;
281 }
282
283 /* Does it need to be activated? */
284 if ((ActCtxInfo.hActCtx) && !(ActCtxInfo.dwFlags & 1))
285 {
286 /* Activate it */
287 Status = RtlActivateActivationContextEx(RTL_ACTIVATE_ACTIVATION_CONTEXT_EX_FLAG_RELEASE_ON_STACK_DEALLOCATION,
288 Teb,
289 ActCtxInfo.hActCtx,
290 &Cookie);
291 if (!NT_SUCCESS(Status))
292 {
293 /* Fail */
294 DbgPrint("SXS: %s - Failing thread create because "
295 "RtlActivateActivationContextEx() failed with status %08lx\n",
296 __FUNCTION__, Status);
297 ASSERT(FALSE); // while (TRUE);
298 return NULL;
299 }
300 }
301 }
302
303 /* Notify CSR */
304 if (!BaseRunningInServerProcess)
305 {
306 /* Notify CSR */
307 Status = BasepNotifyCsrOfThread(hThread, &ClientId);
308 ASSERT(NT_SUCCESS(Status));
309 }
310 else
311 {
312 if (hProcess != NtCurrentProcess())
313 {
314 PCSR_CREATE_REMOTE_THREAD CsrCreateRemoteThread;
315
316 /* Get the direct CSRSRV export */
317 CsrCreateRemoteThread = (PCSR_CREATE_REMOTE_THREAD)
318 GetProcAddress(GetModuleHandleA("csrsrv"),
319 "CsrCreateRemoteThread");
320 if (CsrCreateRemoteThread)
321 {
322 /* Call it instead of going through LPC */
323 Status = CsrCreateRemoteThread(hThread, &ClientId);
324 ASSERT(NT_SUCCESS(Status));
325 }
326 }
327 }
328
329 /* Success */
330 if (lpThreadId) *lpThreadId = HandleToUlong(ClientId.UniqueThread);
331
332 /* Resume it if asked */
333 if (!(dwCreationFlags & CREATE_SUSPENDED)) NtResumeThread(hThread, &Dummy);
334
335 /* Return handle to thread */
336 return hThread;
337 }
338
339 /*
340 * @implemented
341 */
342 VOID
343 WINAPI
344 ExitThread(IN DWORD uExitCode)
345 {
346 NTSTATUS Status;
347 ULONG LastThread;
348 PRTL_CRITICAL_SECTION LoaderLock;
349
350 /* Make sure loader lock isn't held */
351 LoaderLock = NtCurrentPeb()->LoaderLock;
352 if (LoaderLock) ASSERT(NtCurrentTeb()->ClientId.UniqueThread != LoaderLock->OwningThread);
353
354 /*
355 * Terminate process if this is the last thread
356 * of the current process
357 */
358 Status = NtQueryInformationThread(NtCurrentThread(),
359 ThreadAmILastThread,
360 &LastThread,
361 sizeof(LastThread),
362 NULL);
363 if ((NT_SUCCESS(Status)) && (LastThread)) ExitProcess(uExitCode);
364
365 /* Notify DLLs and TLS Callbacks of termination */
366 LdrShutdownThread();
367
368 /* Tell the Kernel to free the Stack */
369 NtCurrentTeb()->FreeStackOnTermination = TRUE;
370 NtTerminateThread(NULL, uExitCode);
371
372 /* We should never reach this place */
373 DPRINT1("It should not happen\n");
374 ASSERT(FALSE);
375 while (TRUE); // 'noreturn' function.
376 }
377
378 /*
379 * @implemented
380 */
381 HANDLE
382 WINAPI
383 OpenThread(IN DWORD dwDesiredAccess,
384 IN BOOL bInheritHandle,
385 IN DWORD dwThreadId)
386 {
387 NTSTATUS Status;
388 HANDLE ThreadHandle;
389 OBJECT_ATTRIBUTES ObjectAttributes;
390 CLIENT_ID ClientId;
391
392 ClientId.UniqueProcess = 0;
393 ClientId.UniqueThread = ULongToHandle(dwThreadId);
394
395 InitializeObjectAttributes(&ObjectAttributes,
396 NULL,
397 (bInheritHandle ? OBJ_INHERIT : 0),
398 NULL,
399 NULL);
400
401 Status = NtOpenThread(&ThreadHandle,
402 dwDesiredAccess,
403 &ObjectAttributes,
404 &ClientId);
405 if (!NT_SUCCESS(Status))
406 {
407 BaseSetLastNTError(Status);
408 return NULL;
409 }
410
411 return ThreadHandle;
412 }
413
414 /*
415 * @implemented
416 */
417 PTEB
418 GetTeb(VOID)
419 {
420 return NtCurrentTeb();
421 }
422
423 /*
424 * @implemented
425 */
426 BOOL
427 WINAPI
428 SwitchToThread(VOID)
429 {
430 return NtYieldExecution() != STATUS_NO_YIELD_PERFORMED;
431 }
432
433
434 /*
435 * @implemented
436 */
437 DWORD
438 WINAPI
439 GetCurrentThreadId(VOID)
440 {
441 return HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread);
442 }
443
444 /*
445 * @implemented
446 */
447 BOOL
448 NTAPI
449 GetThreadTimes(IN HANDLE hThread,
450 OUT LPFILETIME lpCreationTime,
451 OUT LPFILETIME lpExitTime,
452 OUT LPFILETIME lpKernelTime,
453 OUT LPFILETIME lpUserTime)
454 {
455 KERNEL_USER_TIMES KernelUserTimes;
456 NTSTATUS Status;
457
458 Status = NtQueryInformationThread(hThread,
459 ThreadTimes,
460 &KernelUserTimes,
461 sizeof(KERNEL_USER_TIMES),
462 NULL);
463 if (!NT_SUCCESS(Status))
464 {
465 BaseSetLastNTError(Status);
466 return FALSE;
467 }
468
469 *lpCreationTime = *(LPFILETIME)&KernelUserTimes.CreateTime;
470 *lpExitTime = *(LPFILETIME)&KernelUserTimes.ExitTime;
471 *lpKernelTime = *(LPFILETIME)&KernelUserTimes.KernelTime;
472 *lpUserTime = *(LPFILETIME)&KernelUserTimes.UserTime;
473 return TRUE;
474 }
475
476 /*
477 * @implemented
478 */
479 BOOL
480 WINAPI
481 GetThreadContext(IN HANDLE hThread,
482 OUT LPCONTEXT lpContext)
483 {
484 NTSTATUS Status;
485
486 Status = NtGetContextThread(hThread, lpContext);
487 if (!NT_SUCCESS(Status))
488 {
489 BaseSetLastNTError(Status);
490 return FALSE;
491 }
492
493 return TRUE;
494 }
495
496 /*
497 * @implemented
498 */
499 BOOL
500 WINAPI
501 SetThreadContext(IN HANDLE hThread,
502 IN CONST CONTEXT *lpContext)
503 {
504 NTSTATUS Status;
505
506 Status = NtSetContextThread(hThread, (PCONTEXT)lpContext);
507 if (!NT_SUCCESS(Status))
508 {
509 BaseSetLastNTError(Status);
510 return FALSE;
511 }
512
513 return TRUE;
514 }
515
516 /*
517 * @implemented
518 */
519 BOOL
520 WINAPI
521 GetExitCodeThread(IN HANDLE hThread,
522 OUT LPDWORD lpExitCode)
523 {
524 THREAD_BASIC_INFORMATION ThreadBasic;
525 NTSTATUS Status;
526
527 Status = NtQueryInformationThread(hThread,
528 ThreadBasicInformation,
529 &ThreadBasic,
530 sizeof(THREAD_BASIC_INFORMATION),
531 NULL);
532 if (!NT_SUCCESS(Status))
533 {
534 BaseSetLastNTError(Status);
535 return FALSE;
536 }
537
538 *lpExitCode = ThreadBasic.ExitStatus;
539 return TRUE;
540 }
541
542 /*
543 * @implemented
544 */
545 DWORD
546 WINAPI
547 ResumeThread(IN HANDLE hThread)
548 {
549 ULONG PreviousResumeCount;
550 NTSTATUS Status;
551
552 Status = NtResumeThread(hThread, &PreviousResumeCount);
553 if (!NT_SUCCESS(Status))
554 {
555 BaseSetLastNTError(Status);
556 return -1;
557 }
558
559 return PreviousResumeCount;
560 }
561
562 /*
563 * @implemented
564 */
565 BOOL
566 WINAPI
567 TerminateThread(IN HANDLE hThread,
568 IN DWORD dwExitCode)
569 {
570 NTSTATUS Status;
571 PRTL_CRITICAL_SECTION LoaderLock;
572 THREAD_BASIC_INFORMATION ThreadInfo;
573
574 /* Check for invalid thread handle */
575 if (!hThread)
576 {
577 /* Fail if one was passed */
578 SetLastError(ERROR_INVALID_HANDLE);
579 return FALSE;
580 }
581
582 /* Get the loader lock */
583 LoaderLock = NtCurrentPeb()->LoaderLock;
584 if (LoaderLock)
585 {
586 /* Get our TID */
587 Status = NtQueryInformationThread(hThread,
588 ThreadBasicInformation,
589 &ThreadInfo,
590 sizeof(ThreadInfo),
591 NULL);
592 if (!NT_SUCCESS(Status))
593 {
594 /* Assert that we don't hold the loader lock */
595 ASSERT(NtCurrentTeb()->ClientId.UniqueThread != ThreadInfo.ClientId.UniqueThread);
596 ASSERT(NtCurrentTeb()->ClientId.UniqueThread != LoaderLock->OwningThread);
597 }
598 }
599
600 /* Now terminate the thread */
601 Status = NtTerminateThread(hThread, dwExitCode);
602 if (!NT_SUCCESS(Status))
603 {
604 /* Fail */
605 BaseSetLastNTError(Status);
606 return FALSE;
607 }
608
609 /* All done */
610 return TRUE;
611 }
612
613 /*
614 * @implemented
615 */
616 DWORD
617 WINAPI
618 SuspendThread(IN HANDLE hThread)
619 {
620 ULONG PreviousSuspendCount;
621 NTSTATUS Status;
622
623 Status = NtSuspendThread(hThread, &PreviousSuspendCount);
624 if (!NT_SUCCESS(Status))
625 {
626 BaseSetLastNTError(Status);
627 return -1;
628 }
629
630 return PreviousSuspendCount;
631 }
632
633 /*
634 * @implemented
635 */
636 DWORD_PTR
637 WINAPI
638 SetThreadAffinityMask(IN HANDLE hThread,
639 IN DWORD_PTR dwThreadAffinityMask)
640 {
641 THREAD_BASIC_INFORMATION ThreadBasic;
642 KAFFINITY AffinityMask;
643 NTSTATUS Status;
644
645 AffinityMask = (KAFFINITY)dwThreadAffinityMask;
646
647 Status = NtQueryInformationThread(hThread,
648 ThreadBasicInformation,
649 &ThreadBasic,
650 sizeof(THREAD_BASIC_INFORMATION),
651 NULL);
652 if (!NT_SUCCESS(Status))
653 {
654 BaseSetLastNTError(Status);
655 return 0;
656 }
657
658 Status = NtSetInformationThread(hThread,
659 ThreadAffinityMask,
660 &AffinityMask,
661 sizeof(KAFFINITY));
662 if (!NT_SUCCESS(Status))
663 {
664 BaseSetLastNTError(Status);
665 ThreadBasic.AffinityMask = 0;
666 }
667
668 return ThreadBasic.AffinityMask;
669 }
670
671 /*
672 * @implemented
673 */
674 BOOL
675 WINAPI
676 SetThreadPriority(IN HANDLE hThread,
677 IN int nPriority)
678 {
679 LONG Prio = nPriority;
680 NTSTATUS Status;
681
682 /* Check if values forcing saturation should be used */
683 if (Prio == THREAD_PRIORITY_TIME_CRITICAL)
684 {
685 /* This is 16 */
686 Prio = (HIGH_PRIORITY + 1) / 2;
687 }
688 else if (Prio == THREAD_PRIORITY_IDLE)
689 {
690 /* This is -16 */
691 Prio = -((HIGH_PRIORITY + 1) / 2);
692 }
693
694 /* Set the Base Priority */
695 Status = NtSetInformationThread(hThread,
696 ThreadBasePriority,
697 &Prio,
698 sizeof(LONG));
699 if (!NT_SUCCESS(Status))
700 {
701 /* Failure */
702 BaseSetLastNTError(Status);
703 return FALSE;
704 }
705
706 /* Return */
707 return TRUE;
708 }
709
710 /*
711 * @implemented
712 */
713 int
714 WINAPI
715 GetThreadPriority(IN HANDLE hThread)
716 {
717 THREAD_BASIC_INFORMATION ThreadBasic;
718 NTSTATUS Status;
719
720 /* Query the Base Priority Increment */
721 Status = NtQueryInformationThread(hThread,
722 ThreadBasicInformation,
723 &ThreadBasic,
724 sizeof(THREAD_BASIC_INFORMATION),
725 NULL);
726 if (!NT_SUCCESS(Status))
727 {
728 /* Failure */
729 BaseSetLastNTError(Status);
730 return THREAD_PRIORITY_ERROR_RETURN;
731 }
732
733 /* Do some conversions for saturation values */
734 if (ThreadBasic.BasePriority == ((HIGH_PRIORITY + 1) / 2))
735 {
736 /* Win32 calls this "time critical" */
737 ThreadBasic.BasePriority = THREAD_PRIORITY_TIME_CRITICAL;
738 }
739 else if (ThreadBasic.BasePriority == -((HIGH_PRIORITY + 1) / 2))
740 {
741 /* Win32 calls this "idle" */
742 ThreadBasic.BasePriority = THREAD_PRIORITY_IDLE;
743 }
744
745 /* Return the final result */
746 return ThreadBasic.BasePriority;
747 }
748
749 /*
750 * @implemented
751 */
752 BOOL
753 WINAPI
754 GetThreadPriorityBoost(IN HANDLE hThread,
755 OUT PBOOL pDisablePriorityBoost)
756 {
757 ULONG PriorityBoost;
758 NTSTATUS Status;
759
760 Status = NtQueryInformationThread(hThread,
761 ThreadPriorityBoost,
762 &PriorityBoost,
763 sizeof(ULONG),
764 NULL);
765 if (!NT_SUCCESS(Status))
766 {
767 BaseSetLastNTError(Status);
768 return FALSE;
769 }
770
771 *pDisablePriorityBoost = PriorityBoost;
772 return TRUE;
773 }
774
775 /*
776 * @implemented
777 */
778 BOOL
779 NTAPI
780 SetThreadPriorityBoost(IN HANDLE hThread,
781 IN BOOL bDisablePriorityBoost)
782 {
783 ULONG PriorityBoost;
784 NTSTATUS Status;
785
786 PriorityBoost = bDisablePriorityBoost != FALSE;
787
788 Status = NtSetInformationThread(hThread,
789 ThreadPriorityBoost,
790 &PriorityBoost,
791 sizeof(ULONG));
792 if (!NT_SUCCESS(Status))
793 {
794 BaseSetLastNTError(Status);
795 return FALSE;
796 }
797
798 return TRUE;
799 }
800
801 /*
802 * @implemented
803 */
804 BOOL
805 WINAPI
806 GetThreadSelectorEntry(IN HANDLE hThread,
807 IN DWORD dwSelector,
808 OUT LPLDT_ENTRY lpSelectorEntry)
809 {
810 #ifdef _M_IX86
811 DESCRIPTOR_TABLE_ENTRY DescriptionTableEntry;
812 NTSTATUS Status;
813
814 /* Set the selector and do the query */
815 DescriptionTableEntry.Selector = dwSelector;
816 Status = NtQueryInformationThread(hThread,
817 ThreadDescriptorTableEntry,
818 &DescriptionTableEntry,
819 sizeof(DESCRIPTOR_TABLE_ENTRY),
820 NULL);
821 if (!NT_SUCCESS(Status))
822 {
823 /* Fail */
824 BaseSetLastNTError(Status);
825 return FALSE;
826 }
827
828 /* Success, return the selector */
829 *lpSelectorEntry = DescriptionTableEntry.Descriptor;
830 return TRUE;
831 #else
832 DPRINT1("Calling GetThreadSelectorEntry!\n");
833 return FALSE;
834 #endif
835 }
836
837 /*
838 * @implemented
839 */
840 DWORD
841 WINAPI
842 SetThreadIdealProcessor(IN HANDLE hThread,
843 IN DWORD dwIdealProcessor)
844 {
845 NTSTATUS Status;
846
847 Status = NtSetInformationThread(hThread,
848 ThreadIdealProcessor,
849 &dwIdealProcessor,
850 sizeof(ULONG));
851 if (!NT_SUCCESS(Status))
852 {
853 BaseSetLastNTError(Status);
854 return -1;
855 }
856
857 return (DWORD)Status;
858 }
859
860 /*
861 * @implemented
862 */
863 DWORD
864 WINAPI
865 GetProcessIdOfThread(IN HANDLE Thread)
866 {
867 THREAD_BASIC_INFORMATION ThreadBasic;
868 NTSTATUS Status;
869
870 Status = NtQueryInformationThread(Thread,
871 ThreadBasicInformation,
872 &ThreadBasic,
873 sizeof(THREAD_BASIC_INFORMATION),
874 NULL);
875 if (!NT_SUCCESS(Status))
876 {
877 BaseSetLastNTError(Status);
878 return 0;
879 }
880
881 return HandleToUlong(ThreadBasic.ClientId.UniqueProcess);
882 }
883
884 /*
885 * @implemented
886 */
887 DWORD
888 WINAPI
889 GetThreadId(IN HANDLE Thread)
890 {
891 THREAD_BASIC_INFORMATION ThreadBasic;
892 NTSTATUS Status;
893
894 Status = NtQueryInformationThread(Thread,
895 ThreadBasicInformation,
896 &ThreadBasic,
897 sizeof(THREAD_BASIC_INFORMATION),
898 NULL);
899 if (!NT_SUCCESS(Status))
900 {
901 BaseSetLastNTError(Status);
902 return 0;
903 }
904
905 return HandleToUlong(ThreadBasic.ClientId.UniqueThread);
906 }
907
908 /*
909 * @unimplemented
910 */
911 LANGID
912 WINAPI
913 SetThreadUILanguage(IN LANGID LangId)
914 {
915 UNIMPLEMENTED;
916 return NtCurrentTeb()->CurrentLocale;
917 }
918
919 /*
920 * @implemented
921 */
922 DWORD
923 WINAPI
924 QueueUserAPC(IN PAPCFUNC pfnAPC,
925 IN HANDLE hThread,
926 IN ULONG_PTR dwData)
927 {
928 NTSTATUS Status;
929 ACTIVATION_CONTEXT_BASIC_INFORMATION ActCtxInfo;
930
931 /* Zero the activation context and query information on it */
932 RtlZeroMemory(&ActCtxInfo, sizeof(ActCtxInfo));
933 // WARNING!!! THIS IS USING THE WIN32 FLAG BECAUSE REACTOS CONTINUES TO BE A POS!!! ///
934 Status = RtlQueryInformationActivationContext(QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX,
935 NULL,
936 0,
937 ActivationContextBasicInformation,
938 &ActCtxInfo,
939 sizeof(ActCtxInfo),
940 NULL);
941 if (!NT_SUCCESS(Status))
942 {
943 /* Fail due to SxS */
944 DbgPrint("SXS: %s failing because RtlQueryInformationActivationContext()"
945 "returned status %08lx\n", __FUNCTION__, Status);
946 BaseSetLastNTError(Status);
947 return FALSE;
948 }
949
950 /* Queue the APC */
951 Status = NtQueueApcThread(hThread,
952 (PKNORMAL_ROUTINE)BaseDispatchApc,
953 pfnAPC,
954 (PVOID)dwData,
955 (ActCtxInfo.dwFlags & 1) ?
956 INVALID_ACTIVATION_CONTEXT : ActCtxInfo.hActCtx);
957 if (!NT_SUCCESS(Status))
958 {
959 BaseSetLastNTError(Status);
960 return FALSE;
961 }
962
963 /* All good */
964 return TRUE;
965 }
966
967 /*
968 * @implemented
969 */
970 BOOL
971 WINAPI
972 SetThreadStackGuarantee(IN OUT PULONG StackSizeInBytes)
973 {
974 UNIMPLEMENTED;
975 return FALSE;
976 }
977
978 /*
979 * @implemented
980 */
981 BOOL
982 WINAPI
983 GetThreadIOPendingFlag(IN HANDLE hThread,
984 OUT PBOOL lpIOIsPending)
985 {
986 ULONG IoPending;
987 NTSTATUS Status;
988
989 /* Query the flag */
990 Status = NtQueryInformationThread(hThread,
991 ThreadIsIoPending,
992 &IoPending,
993 sizeof(IoPending),
994 NULL);
995 if (NT_SUCCESS(Status))
996 {
997 /* Return the flag */
998 *lpIOIsPending = IoPending ? TRUE : FALSE;
999 return TRUE;
1000 }
1001
1002 /* Fail */
1003 BaseSetLastNTError(Status);
1004 return FALSE;
1005 }
1006
1007 /*
1008 * @implemented
1009 */
1010 BOOL
1011 WINAPI
1012 QueueUserWorkItem(IN LPTHREAD_START_ROUTINE Function,
1013 IN PVOID Context,
1014 IN ULONG Flags)
1015 {
1016 NTSTATUS Status;
1017
1018 /* NOTE: Rtl needs to safely call the function using a trampoline */
1019 Status = RtlQueueWorkItem((WORKERCALLBACKFUNC)Function, Context, Flags);
1020 if (!NT_SUCCESS(Status))
1021 {
1022 /* Failed */
1023 BaseSetLastNTError(Status);
1024 return FALSE;
1025 }
1026
1027 /* All good */
1028 return TRUE;
1029 }
1030
1031 /*
1032 * @implemented
1033 */
1034 DWORD
1035 WINAPI
1036 TlsAlloc(VOID)
1037 {
1038 ULONG Index;
1039 PTEB Teb;
1040 PPEB Peb;
1041
1042 /* Get the PEB and TEB, lock the PEB */
1043 Teb = NtCurrentTeb();
1044 Peb = Teb->ProcessEnvironmentBlock;
1045 RtlAcquirePebLock();
1046
1047 /* Try to get regular TEB slot */
1048 Index = RtlFindClearBitsAndSet(Peb->TlsBitmap, 1, 0);
1049 if (Index != 0xFFFFFFFF)
1050 {
1051 /* Clear the value. */
1052 Teb->TlsSlots[Index] = 0;
1053 RtlReleasePebLock();
1054 return Index;
1055 }
1056
1057 /* If it fails, try to find expansion TEB slot. */
1058 Index = RtlFindClearBitsAndSet(Peb->TlsExpansionBitmap, 1, 0);
1059 if (Index != 0xFFFFFFFF)
1060 {
1061 /* Is there no expansion slot yet? */
1062 if (!Teb->TlsExpansionSlots)
1063 {
1064 /* Allocate an array */
1065 Teb->TlsExpansionSlots = RtlAllocateHeap(RtlGetProcessHeap(),
1066 HEAP_ZERO_MEMORY,
1067 TLS_EXPANSION_SLOTS *
1068 sizeof(PVOID));
1069 }
1070
1071 /* Did we get an array? */
1072 if (!Teb->TlsExpansionSlots)
1073 {
1074 /* Fail */
1075 RtlClearBits(Peb->TlsExpansionBitmap, Index, 1);
1076 Index = 0xFFFFFFFF;
1077 BaseSetLastNTError(STATUS_NO_MEMORY);
1078 }
1079 else
1080 {
1081 /* Clear the value. */
1082 Teb->TlsExpansionSlots[Index] = 0;
1083 Index += TLS_MINIMUM_AVAILABLE;
1084 }
1085 }
1086 else
1087 {
1088 /* Fail */
1089 BaseSetLastNTError(STATUS_NO_MEMORY);
1090 }
1091
1092 /* Release the lock and return */
1093 RtlReleasePebLock();
1094 return Index;
1095 }
1096
1097 /*
1098 * @implemented
1099 */
1100 BOOL
1101 WINAPI
1102 TlsFree(IN DWORD Index)
1103 {
1104 BOOL BitSet;
1105 PPEB Peb;
1106 ULONG TlsIndex;
1107 PVOID TlsBitmap;
1108 NTSTATUS Status;
1109
1110 /* Acquire the PEB lock and grab the PEB */
1111 Peb = NtCurrentPeb();
1112 RtlAcquirePebLock();
1113
1114 /* Check if the index is too high */
1115 if (Index >= TLS_MINIMUM_AVAILABLE)
1116 {
1117 /* Check if it can fit in the expansion slots */
1118 TlsIndex = Index - TLS_MINIMUM_AVAILABLE;
1119 if (TlsIndex >= TLS_EXPANSION_SLOTS)
1120 {
1121 /* It's invalid */
1122 BaseSetLastNTError(STATUS_INVALID_PARAMETER);
1123 RtlReleasePebLock();
1124 return FALSE;
1125 }
1126 else
1127 {
1128 /* Use the expansion bitmap */
1129 TlsBitmap = Peb->TlsExpansionBitmap;
1130 Index = TlsIndex;
1131 }
1132 }
1133 else
1134 {
1135 /* Use the normal bitmap */
1136 TlsBitmap = Peb->TlsBitmap;
1137 }
1138
1139 /* Check if the index was set */
1140 BitSet = RtlAreBitsSet(TlsBitmap, Index, 1);
1141 if (BitSet)
1142 {
1143 /* Tell the kernel to free the TLS cells */
1144 Status = NtSetInformationThread(NtCurrentThread(),
1145 ThreadZeroTlsCell,
1146 &Index,
1147 sizeof(DWORD));
1148 if (!NT_SUCCESS(Status))
1149 {
1150 BaseSetLastNTError(STATUS_INVALID_PARAMETER);
1151 RtlReleasePebLock();
1152 return FALSE;
1153 }
1154
1155 /* Clear the bit */
1156 RtlClearBits(TlsBitmap, Index, 1);
1157 }
1158 else
1159 {
1160 /* Fail */
1161 BaseSetLastNTError(STATUS_INVALID_PARAMETER);
1162 RtlReleasePebLock();
1163 return FALSE;
1164 }
1165
1166 /* Done! */
1167 RtlReleasePebLock();
1168 return TRUE;
1169 }
1170
1171 /*
1172 * @implemented
1173 */
1174 LPVOID
1175 WINAPI
1176 TlsGetValue(IN DWORD Index)
1177 {
1178 PTEB Teb;
1179
1180 /* Get the TEB and clear the last error */
1181 Teb = NtCurrentTeb();
1182 Teb->LastErrorValue = 0;
1183
1184 /* Check for simple TLS index */
1185 if (Index < TLS_MINIMUM_AVAILABLE)
1186 {
1187 /* Return it */
1188 return Teb->TlsSlots[Index];
1189 }
1190
1191 /* Check for valid index */
1192 if (Index >= TLS_EXPANSION_SLOTS + TLS_MINIMUM_AVAILABLE)
1193 {
1194 /* Fail */
1195 BaseSetLastNTError(STATUS_INVALID_PARAMETER);
1196 return NULL;
1197 }
1198
1199 /* The expansion slots are allocated on demand, so check for it. */
1200 Teb->LastErrorValue = 0;
1201 if (!Teb->TlsExpansionSlots) return NULL;
1202
1203 /* Return the value from the expansion slots */
1204 return Teb->TlsExpansionSlots[Index - TLS_MINIMUM_AVAILABLE];
1205 }
1206
1207 /*
1208 * @implemented
1209 */
1210 BOOL
1211 WINAPI
1212 TlsSetValue(IN DWORD Index,
1213 IN LPVOID Value)
1214 {
1215 DWORD TlsIndex;
1216 PTEB Teb = NtCurrentTeb();
1217
1218 /* Check for simple TLS index */
1219 if (Index < TLS_MINIMUM_AVAILABLE)
1220 {
1221 /* Return it */
1222 Teb->TlsSlots[Index] = Value;
1223 return TRUE;
1224 }
1225
1226 /* Check if this is an expansion slot */
1227 TlsIndex = Index - TLS_MINIMUM_AVAILABLE;
1228 if (TlsIndex >= TLS_EXPANSION_SLOTS)
1229 {
1230 /* Fail */
1231 BaseSetLastNTError(STATUS_INVALID_PARAMETER);
1232 return FALSE;
1233 }
1234
1235 /* Do we not have expansion slots? */
1236 if (!Teb->TlsExpansionSlots)
1237 {
1238 /* Get the PEB lock to see if we still need them */
1239 RtlAcquirePebLock();
1240 if (!Teb->TlsExpansionSlots)
1241 {
1242 /* Allocate them */
1243 Teb->TlsExpansionSlots = RtlAllocateHeap(RtlGetProcessHeap(),
1244 HEAP_ZERO_MEMORY,
1245 TLS_EXPANSION_SLOTS *
1246 sizeof(PVOID));
1247 if (!Teb->TlsExpansionSlots)
1248 {
1249 /* Fail */
1250 RtlReleasePebLock();
1251 BaseSetLastNTError(STATUS_NO_MEMORY);
1252 return FALSE;
1253 }
1254 }
1255
1256 /* Release the lock */
1257 RtlReleasePebLock();
1258 }
1259
1260 /* Write the value */
1261 Teb->TlsExpansionSlots[TlsIndex] = Value;
1262
1263 /* Success */
1264 return TRUE;
1265 }
1266
1267 /* EOF */