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