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