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