* Sync up to trunk HEAD (r62502).
[reactos.git] / dll / win32 / kernel32 / client / thread.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: dll/win32/kernel32/client/thread.c
5 * PURPOSE: Thread functions
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Ariadne (ariadne@xs4all.nl)
8 *
9 */
10
11 /* INCLUDES *******************************************************************/
12
13 #include <k32.h>
14
15 #define NDEBUG
16 #include <debug.h>
17
18 #define SXS_SUPPORT_FIXME
19
20 typedef NTSTATUS (NTAPI *PCSR_CREATE_REMOTE_THREAD)(IN HANDLE ThreadHandle, IN PCLIENT_ID ClientId);
21
22 NTSTATUS
23 WINAPI
24 BasepNotifyCsrOfThread(IN HANDLE ThreadHandle,
25 IN PCLIENT_ID ClientId);
26
27 /* FUNCTIONS ******************************************************************/
28
29 static
30 LONG BaseThreadExceptionFilter(EXCEPTION_POINTERS * ExceptionInfo)
31 {
32 LONG ExceptionDisposition = EXCEPTION_EXECUTE_HANDLER;
33 LPTOP_LEVEL_EXCEPTION_FILTER RealFilter;
34 RealFilter = RtlDecodePointer(GlobalTopLevelExceptionFilter);
35
36 if (RealFilter != NULL)
37 {
38 _SEH2_TRY
39 {
40 ExceptionDisposition = RealFilter(ExceptionInfo);
41 }
42 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
43 {
44 ExceptionDisposition = UnhandledExceptionFilter(ExceptionInfo);
45 }
46 _SEH2_END;
47 }
48
49 return ExceptionDisposition;
50 }
51
52 __declspec(noreturn)
53 VOID
54 WINAPI
55 BaseThreadStartup(IN LPTHREAD_START_ROUTINE lpStartAddress,
56 IN LPVOID lpParameter)
57 {
58 /* Attempt to call the Thread Start Address */
59 _SEH2_TRY
60 {
61 /* Legacy check which is still used today for Win32 threads */
62 if (NtCurrentTeb()->NtTib.Version == (30 << 8)) // OS/2 V3.0 ("Cruiser")
63 {
64 /* This registers the termination port with CSRSS */
65 if (!BaseRunningInServerProcess) CsrNewThread();
66 }
67
68 /* Get the exit code from the Thread Start */
69 ExitThread((lpStartAddress)((PVOID)lpParameter));
70 }
71 _SEH2_EXCEPT(BaseThreadExceptionFilter(_SEH2_GetExceptionInformation()))
72 {
73 /* Get the Exit code from the SEH Handler */
74 if (!BaseRunningInServerProcess)
75 {
76 /* Kill the whole process, usually */
77 ExitProcess(_SEH2_GetExceptionCode());
78 }
79 else
80 {
81 /* If running inside CSRSS, kill just this thread */
82 ExitThread(_SEH2_GetExceptionCode());
83 }
84 }
85 _SEH2_END;
86 }
87
88 VOID
89 NTAPI
90 BaseDispatchApc(IN PAPCFUNC ApcRoutine,
91 IN PVOID Data,
92 IN PACTIVATION_CONTEXT ActivationContext)
93 {
94 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME ActivationFrame;
95
96 /* Setup the activation context */
97 ActivationFrame.Size = sizeof(ActivationFrame);
98 ActivationFrame.Format = RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER;
99
100 /* Check if caller wanted one */
101 if (ActivationContext == INVALID_ACTIVATION_CONTEXT)
102 {
103 /* Do the APC directly */
104 ApcRoutine((ULONG_PTR)Data);
105 return;
106 }
107
108 /* Then activate it */
109 RtlActivateActivationContextUnsafeFast(&ActivationFrame, ActivationContext);
110
111 /* Call the routine under SEH */
112 _SEH2_TRY
113 {
114 ApcRoutine((ULONG_PTR)Data);
115 }
116 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
117 {
118
119 }
120 _SEH2_END;
121
122 /* Now de-activate and release the activation context */
123 RtlDeactivateActivationContextUnsafeFast(&ActivationFrame);
124 RtlReleaseActivationContext(ActivationContext);
125 }
126
127 /* PUBLIC FUNCTIONS ***********************************************************/
128
129 /*
130 * @implemented
131 */
132 HANDLE
133 WINAPI
134 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 UNIMPLEMENTED;
982 return FALSE;
983 }
984
985 /*
986 * @implemented
987 */
988 BOOL
989 WINAPI
990 GetThreadIOPendingFlag(IN HANDLE hThread,
991 OUT PBOOL lpIOIsPending)
992 {
993 ULONG IoPending;
994 NTSTATUS Status;
995
996 /* Query the flag */
997 Status = NtQueryInformationThread(hThread,
998 ThreadIsIoPending,
999 &IoPending,
1000 sizeof(IoPending),
1001 NULL);
1002 if (NT_SUCCESS(Status))
1003 {
1004 /* Return the flag */
1005 *lpIOIsPending = IoPending ? TRUE : FALSE;
1006 return TRUE;
1007 }
1008
1009 /* Fail */
1010 BaseSetLastNTError(Status);
1011 return FALSE;
1012 }
1013
1014 /*
1015 * @implemented
1016 */
1017 BOOL
1018 WINAPI
1019 QueueUserWorkItem(IN LPTHREAD_START_ROUTINE Function,
1020 IN PVOID Context,
1021 IN ULONG Flags)
1022 {
1023 NTSTATUS Status;
1024
1025 /* NOTE: Rtl needs to safely call the function using a trampoline */
1026 Status = RtlQueueWorkItem((WORKERCALLBACKFUNC)Function, Context, Flags);
1027 if (!NT_SUCCESS(Status))
1028 {
1029 /* Failed */
1030 BaseSetLastNTError(Status);
1031 return FALSE;
1032 }
1033
1034 /* All good */
1035 return TRUE;
1036 }
1037
1038 /*
1039 * @implemented
1040 */
1041 DWORD
1042 WINAPI
1043 TlsAlloc(VOID)
1044 {
1045 ULONG Index;
1046 PTEB Teb;
1047 PPEB Peb;
1048
1049 /* Get the PEB and TEB, lock the PEB */
1050 Teb = NtCurrentTeb();
1051 Peb = Teb->ProcessEnvironmentBlock;
1052 RtlAcquirePebLock();
1053
1054 /* Try to get regular TEB slot */
1055 Index = RtlFindClearBitsAndSet(Peb->TlsBitmap, 1, 0);
1056 if (Index != 0xFFFFFFFF)
1057 {
1058 /* Clear the value. */
1059 Teb->TlsSlots[Index] = 0;
1060 RtlReleasePebLock();
1061 return Index;
1062 }
1063
1064 /* If it fails, try to find expansion TEB slot. */
1065 Index = RtlFindClearBitsAndSet(Peb->TlsExpansionBitmap, 1, 0);
1066 if (Index != 0xFFFFFFFF)
1067 {
1068 /* Is there no expansion slot yet? */
1069 if (!Teb->TlsExpansionSlots)
1070 {
1071 /* Allocate an array */
1072 Teb->TlsExpansionSlots = RtlAllocateHeap(RtlGetProcessHeap(),
1073 HEAP_ZERO_MEMORY,
1074 TLS_EXPANSION_SLOTS *
1075 sizeof(PVOID));
1076 }
1077
1078 /* Did we get an array? */
1079 if (!Teb->TlsExpansionSlots)
1080 {
1081 /* Fail */
1082 RtlClearBits(Peb->TlsExpansionBitmap, Index, 1);
1083 Index = 0xFFFFFFFF;
1084 BaseSetLastNTError(STATUS_NO_MEMORY);
1085 }
1086 else
1087 {
1088 /* Clear the value. */
1089 Teb->TlsExpansionSlots[Index] = 0;
1090 Index += TLS_MINIMUM_AVAILABLE;
1091 }
1092 }
1093 else
1094 {
1095 /* Fail */
1096 BaseSetLastNTError(STATUS_NO_MEMORY);
1097 }
1098
1099 /* Release the lock and return */
1100 RtlReleasePebLock();
1101 return Index;
1102 }
1103
1104 /*
1105 * @implemented
1106 */
1107 BOOL
1108 WINAPI
1109 TlsFree(IN DWORD Index)
1110 {
1111 BOOL BitSet;
1112 PPEB Peb;
1113 ULONG TlsIndex;
1114 PVOID TlsBitmap;
1115 NTSTATUS Status;
1116
1117 /* Acquire the PEB lock and grab the PEB */
1118 Peb = NtCurrentPeb();
1119 RtlAcquirePebLock();
1120
1121 /* Check if the index is too high */
1122 if (Index >= TLS_MINIMUM_AVAILABLE)
1123 {
1124 /* Check if it can fit in the expansion slots */
1125 TlsIndex = Index - TLS_MINIMUM_AVAILABLE;
1126 if (TlsIndex >= TLS_EXPANSION_SLOTS)
1127 {
1128 /* It's invalid */
1129 BaseSetLastNTError(STATUS_INVALID_PARAMETER);
1130 RtlReleasePebLock();
1131 return FALSE;
1132 }
1133 else
1134 {
1135 /* Use the expansion bitmap */
1136 TlsBitmap = Peb->TlsExpansionBitmap;
1137 Index = TlsIndex;
1138 }
1139 }
1140 else
1141 {
1142 /* Use the normal bitmap */
1143 TlsBitmap = Peb->TlsBitmap;
1144 }
1145
1146 /* Check if the index was set */
1147 BitSet = RtlAreBitsSet(TlsBitmap, Index, 1);
1148 if (BitSet)
1149 {
1150 /* Tell the kernel to free the TLS cells */
1151 Status = NtSetInformationThread(NtCurrentThread(),
1152 ThreadZeroTlsCell,
1153 &Index,
1154 sizeof(DWORD));
1155 if (!NT_SUCCESS(Status))
1156 {
1157 BaseSetLastNTError(STATUS_INVALID_PARAMETER);
1158 RtlReleasePebLock();
1159 return FALSE;
1160 }
1161
1162 /* Clear the bit */
1163 RtlClearBits(TlsBitmap, Index, 1);
1164 }
1165 else
1166 {
1167 /* Fail */
1168 BaseSetLastNTError(STATUS_INVALID_PARAMETER);
1169 RtlReleasePebLock();
1170 return FALSE;
1171 }
1172
1173 /* Done! */
1174 RtlReleasePebLock();
1175 return TRUE;
1176 }
1177
1178 /*
1179 * @implemented
1180 */
1181 LPVOID
1182 WINAPI
1183 TlsGetValue(IN DWORD Index)
1184 {
1185 PTEB Teb;
1186
1187 /* Get the TEB and clear the last error */
1188 Teb = NtCurrentTeb();
1189 Teb->LastErrorValue = 0;
1190
1191 /* Check for simple TLS index */
1192 if (Index < TLS_MINIMUM_AVAILABLE)
1193 {
1194 /* Return it */
1195 return Teb->TlsSlots[Index];
1196 }
1197
1198 /* Check for valid index */
1199 if (Index >= TLS_EXPANSION_SLOTS + TLS_MINIMUM_AVAILABLE)
1200 {
1201 /* Fail */
1202 BaseSetLastNTError(STATUS_INVALID_PARAMETER);
1203 return NULL;
1204 }
1205
1206 /* The expansion slots are allocated on demand, so check for it. */
1207 Teb->LastErrorValue = 0;
1208 if (!Teb->TlsExpansionSlots) return NULL;
1209
1210 /* Return the value from the expansion slots */
1211 return Teb->TlsExpansionSlots[Index - TLS_MINIMUM_AVAILABLE];
1212 }
1213
1214 /*
1215 * @implemented
1216 */
1217 BOOL
1218 WINAPI
1219 TlsSetValue(IN DWORD Index,
1220 IN LPVOID Value)
1221 {
1222 DWORD TlsIndex;
1223 PTEB Teb = NtCurrentTeb();
1224
1225 /* Check for simple TLS index */
1226 if (Index < TLS_MINIMUM_AVAILABLE)
1227 {
1228 /* Return it */
1229 Teb->TlsSlots[Index] = Value;
1230 return TRUE;
1231 }
1232
1233 /* Check if this is an expansion slot */
1234 TlsIndex = Index - TLS_MINIMUM_AVAILABLE;
1235 if (TlsIndex >= TLS_EXPANSION_SLOTS)
1236 {
1237 /* Fail */
1238 BaseSetLastNTError(STATUS_INVALID_PARAMETER);
1239 return FALSE;
1240 }
1241
1242 /* Do we not have expansion slots? */
1243 if (!Teb->TlsExpansionSlots)
1244 {
1245 /* Get the PEB lock to see if we still need them */
1246 RtlAcquirePebLock();
1247 if (!Teb->TlsExpansionSlots)
1248 {
1249 /* Allocate them */
1250 Teb->TlsExpansionSlots = RtlAllocateHeap(RtlGetProcessHeap(),
1251 HEAP_ZERO_MEMORY,
1252 TLS_EXPANSION_SLOTS *
1253 sizeof(PVOID));
1254 if (!Teb->TlsExpansionSlots)
1255 {
1256 /* Fail */
1257 RtlReleasePebLock();
1258 BaseSetLastNTError(STATUS_NO_MEMORY);
1259 return FALSE;
1260 }
1261 }
1262
1263 /* Release the lock */
1264 RtlReleasePebLock();
1265 }
1266
1267 /* Write the value */
1268 Teb->TlsExpansionSlots[TlsIndex] = Value;
1269
1270 /* Success */
1271 return TRUE;
1272 }
1273
1274 /* EOF */