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
19 typedef NTSTATUS (NTAPI *PCSR_CREATE_REMOTE_THREAD)(IN HANDLE ThreadHandle, IN PCLIENT_ID ClientId);
20
21 /* FUNCTIONS ******************************************************************/
22
23 NTSTATUS
24 WINAPI
BasepNotifyCsrOfThread(IN HANDLE ThreadHandle,IN PCLIENT_ID ClientId)25 BasepNotifyCsrOfThread(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
53 DECLSPEC_NORETURN
54 VOID
55 WINAPI
BaseThreadStartup(_In_ LPTHREAD_START_ROUTINE lpStartAddress,_In_ LPVOID lpParameter)56 BaseThreadStartup(
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
90 VOID
91 NTAPI
BaseDispatchApc(IN PAPCFUNC ApcRoutine,IN PVOID Data,IN PACTIVATION_CONTEXT ActivationContext)92 BaseDispatchApc(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 */
134 HANDLE
135 WINAPI
136 DECLSPEC_HOTPATCH
CreateThread(IN LPSECURITY_ATTRIBUTES lpThreadAttributes,IN DWORD dwStackSize,IN LPTHREAD_START_ROUTINE lpStartAddress,IN LPVOID lpParameter,IN DWORD dwCreationFlags,OUT LPDWORD lpThreadId)137 CreateThread(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 */
157 HANDLE
158 WINAPI
CreateRemoteThread(IN HANDLE hProcess,IN LPSECURITY_ATTRIBUTES lpThreadAttributes,IN DWORD dwStackSize,IN LPTHREAD_START_ROUTINE lpStartAddress,IN LPVOID lpParameter,IN DWORD dwCreationFlags,OUT LPDWORD lpThreadId)159 CreateRemoteThread(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
330 Quit:
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 */
363 VOID
364 WINAPI
ExitThread(IN DWORD uExitCode)365 ExitThread(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 */
401 HANDLE
402 WINAPI
OpenThread(IN DWORD dwDesiredAccess,IN BOOL bInheritHandle,IN DWORD dwThreadId)403 OpenThread(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 */
437 PTEB
GetTeb(VOID)438 GetTeb(VOID)
439 {
440 return NtCurrentTeb();
441 }
442
443 /*
444 * @implemented
445 */
446 BOOL
447 WINAPI
SwitchToThread(VOID)448 SwitchToThread(VOID)
449 {
450 return NtYieldExecution() != STATUS_NO_YIELD_PERFORMED;
451 }
452
453
454 /*
455 * @implemented
456 */
457 DWORD
458 WINAPI
GetCurrentThreadId(VOID)459 GetCurrentThreadId(VOID)
460 {
461 return HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread);
462 }
463
464 /*
465 * @implemented
466 */
467 BOOL
468 NTAPI
GetThreadTimes(IN HANDLE hThread,OUT LPFILETIME lpCreationTime,OUT LPFILETIME lpExitTime,OUT LPFILETIME lpKernelTime,OUT LPFILETIME lpUserTime)469 GetThreadTimes(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 */
499 BOOL
500 WINAPI
GetThreadContext(IN HANDLE hThread,OUT LPCONTEXT lpContext)501 GetThreadContext(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 */
519 BOOL
520 WINAPI
SetThreadContext(IN HANDLE hThread,IN CONST CONTEXT * lpContext)521 SetThreadContext(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 */
539 BOOL
540 WINAPI
GetExitCodeThread(IN HANDLE hThread,OUT LPDWORD lpExitCode)541 GetExitCodeThread(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 */
565 DWORD
566 WINAPI
ResumeThread(IN HANDLE hThread)567 ResumeThread(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 */
585 BOOL
586 WINAPI
TerminateThread(IN HANDLE hThread,IN DWORD dwExitCode)587 TerminateThread(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 */
640 DWORD
641 WINAPI
SuspendThread(IN HANDLE hThread)642 SuspendThread(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 */
660 DWORD_PTR
661 WINAPI
SetThreadAffinityMask(IN HANDLE hThread,IN DWORD_PTR dwThreadAffinityMask)662 SetThreadAffinityMask(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 */
698 BOOL
699 WINAPI
SetThreadPriority(IN HANDLE hThread,IN int nPriority)700 SetThreadPriority(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 */
737 int
738 WINAPI
GetThreadPriority(IN HANDLE hThread)739 GetThreadPriority(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 */
776 BOOL
777 WINAPI
GetThreadPriorityBoost(IN HANDLE hThread,OUT PBOOL pDisablePriorityBoost)778 GetThreadPriorityBoost(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 */
802 BOOL
803 NTAPI
SetThreadPriorityBoost(IN HANDLE hThread,IN BOOL bDisablePriorityBoost)804 SetThreadPriorityBoost(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 */
828 BOOL
829 WINAPI
GetThreadSelectorEntry(IN HANDLE hThread,IN DWORD dwSelector,OUT LPLDT_ENTRY lpSelectorEntry)830 GetThreadSelectorEntry(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 */
864 DWORD
865 WINAPI
SetThreadIdealProcessor(IN HANDLE hThread,IN DWORD dwIdealProcessor)866 SetThreadIdealProcessor(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 */
887 DWORD
888 WINAPI
GetProcessIdOfThread(IN HANDLE Thread)889 GetProcessIdOfThread(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 */
911 DWORD
912 WINAPI
GetThreadId(IN HANDLE Thread)913 GetThreadId(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 */
935 LANGID
936 WINAPI
SetThreadUILanguage(IN LANGID LangId)937 SetThreadUILanguage(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 */
957 DWORD
958 WINAPI
QueueUserAPC(IN PAPCFUNC pfnAPC,IN HANDLE hThread,IN ULONG_PTR dwData)959 QueueUserAPC(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 */
1004 BOOL
1005 WINAPI
SetThreadStackGuarantee(IN OUT PULONG StackSizeInBytes)1006 SetThreadStackGuarantee(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 */
1045 BOOL
1046 WINAPI
GetThreadIOPendingFlag(IN HANDLE hThread,OUT PBOOL lpIOIsPending)1047 GetThreadIOPendingFlag(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 */
1074 BOOL
1075 WINAPI
QueueUserWorkItem(IN LPTHREAD_START_ROUTINE Function,IN PVOID Context,IN ULONG Flags)1076 QueueUserWorkItem(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 */
1098 DWORD
1099 WINAPI
TlsAlloc(VOID)1100 TlsAlloc(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 */
1164 BOOL
1165 WINAPI
TlsFree(IN DWORD Index)1166 TlsFree(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 */
1238 LPVOID
1239 WINAPI
TlsGetValue(IN DWORD Index)1240 TlsGetValue(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 */
1274 BOOL
1275 WINAPI
TlsSetValue(IN DWORD Index,IN LPVOID Value)1276 TlsSetValue(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 */
1332