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