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