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( 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 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 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 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 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 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 438 GetTeb(VOID) 439 { 440 return NtCurrentTeb(); 441 } 442 443 /* 444 * @implemented 445 */ 446 BOOL 447 WINAPI 448 SwitchToThread(VOID) 449 { 450 return NtYieldExecution() != STATUS_NO_YIELD_PERFORMED; 451 } 452 453 454 /* 455 * @implemented 456 */ 457 DWORD 458 WINAPI 459 GetCurrentThreadId(VOID) 460 { 461 return HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread); 462 } 463 464 /* 465 * @implemented 466 */ 467 BOOL 468 NTAPI 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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