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