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