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