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