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