Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenthread.c
Go to the documentation of this file.
00001 /* 00002 * COPYRIGHT: See COPYING in the top level directory 00003 * PROJECT: ReactOS system libraries 00004 * FILE: lib/kernel32/thread/thread.c 00005 * PURPOSE: Thread functions 00006 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) 00007 * Ariadne ( ariadne@xs4all.nl) 00008 * 00009 */ 00010 00011 /* INCLUDES *******************************************************************/ 00012 00013 #include <k32.h> 00014 00015 #define NDEBUG 00016 #include <debug.h> 00017 00018 #define SXS_SUPPORT_FIXME 00019 00020 typedef NTSTATUS (NTAPI *PCSR_CREATE_REMOTE_THREAD)(IN HANDLE ThreadHandle, IN PCLIENT_ID ClientId); 00021 00022 NTSTATUS 00023 WINAPI 00024 BasepNotifyCsrOfThread(IN HANDLE ThreadHandle, 00025 IN PCLIENT_ID ClientId); 00026 00027 /* FUNCTIONS ******************************************************************/ 00028 00029 static 00030 LONG BaseThreadExceptionFilter(EXCEPTION_POINTERS * ExceptionInfo) 00031 { 00032 LONG ExceptionDisposition = EXCEPTION_EXECUTE_HANDLER; 00033 LPTOP_LEVEL_EXCEPTION_FILTER RealFilter; 00034 RealFilter = RtlDecodePointer(GlobalTopLevelExceptionFilter); 00035 00036 if (RealFilter != NULL) 00037 { 00038 _SEH2_TRY 00039 { 00040 ExceptionDisposition = RealFilter(ExceptionInfo); 00041 } 00042 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 00043 { 00044 ExceptionDisposition = UnhandledExceptionFilter(ExceptionInfo); 00045 } 00046 _SEH2_END; 00047 } 00048 00049 return ExceptionDisposition; 00050 } 00051 00052 __declspec(noreturn) 00053 VOID 00054 WINAPI 00055 BaseThreadStartup(IN LPTHREAD_START_ROUTINE lpStartAddress, 00056 IN LPVOID lpParameter) 00057 { 00058 /* Attempt to call the Thread Start Address */ 00059 _SEH2_TRY 00060 { 00061 /* Legacy check which is still used today for Win32 threads */ 00062 if (NtCurrentTeb()->NtTib.Version == (30 << 8)) // OS/2 V3.0 ("Cruiser") 00063 { 00064 /* This registers the termination port with CSRSS */ 00065 if (!BaseRunningInServerProcess) CsrNewThread(); 00066 } 00067 00068 /* Get the exit code from the Thread Start */ 00069 ExitThread((lpStartAddress)((PVOID)lpParameter)); 00070 } 00071 _SEH2_EXCEPT(BaseThreadExceptionFilter(_SEH2_GetExceptionInformation())) 00072 { 00073 /* Get the Exit code from the SEH Handler */ 00074 if (!BaseRunningInServerProcess) 00075 { 00076 /* Kill the whole process, usually */ 00077 ExitProcess(_SEH2_GetExceptionCode()); 00078 } 00079 else 00080 { 00081 /* If running inside CSRSS, kill just this thread */ 00082 ExitThread(_SEH2_GetExceptionCode()); 00083 } 00084 } 00085 _SEH2_END; 00086 } 00087 00088 VOID 00089 NTAPI 00090 BaseDispatchApc(IN PAPCFUNC ApcRoutine, 00091 IN PVOID Data, 00092 IN PACTIVATION_CONTEXT ActivationContext) 00093 { 00094 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME ActivationFrame; 00095 00096 /* Setup the activation context */ 00097 ActivationFrame.Size = sizeof(ActivationFrame); 00098 ActivationFrame.Format = RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER; 00099 00100 /* Check if caller wanted one */ 00101 if (ActivationContext == INVALID_ACTIVATION_CONTEXT) 00102 { 00103 /* Do the APC directly */ 00104 ApcRoutine((ULONG_PTR)Data); 00105 return; 00106 } 00107 00108 /* Then activate it */ 00109 RtlActivateActivationContextUnsafeFast(&ActivationFrame, ActivationContext); 00110 00111 /* Call the routine under SEH */ 00112 _SEH2_TRY 00113 { 00114 ApcRoutine((ULONG_PTR)Data); 00115 } 00116 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 00117 { 00118 00119 } 00120 _SEH2_END; 00121 00122 /* Now de-activate and release the activation context */ 00123 RtlDeactivateActivationContextUnsafeFast(&ActivationFrame); 00124 RtlReleaseActivationContext(ActivationContext); 00125 } 00126 00127 /* PUBLIC FUNCTIONS ***********************************************************/ 00128 00129 /* 00130 * @implemented 00131 */ 00132 HANDLE 00133 WINAPI 00134 CreateThread(IN LPSECURITY_ATTRIBUTES lpThreadAttributes, 00135 IN DWORD dwStackSize, 00136 IN LPTHREAD_START_ROUTINE lpStartAddress, 00137 IN LPVOID lpParameter, 00138 IN DWORD dwCreationFlags, 00139 OUT LPDWORD lpThreadId) 00140 { 00141 /* Act as if we're going to create a remote thread in ourselves */ 00142 return CreateRemoteThread(NtCurrentProcess(), 00143 lpThreadAttributes, 00144 dwStackSize, 00145 lpStartAddress, 00146 lpParameter, 00147 dwCreationFlags, 00148 lpThreadId); 00149 } 00150 00151 /* 00152 * @implemented 00153 */ 00154 HANDLE 00155 WINAPI 00156 CreateRemoteThread(HANDLE hProcess, 00157 LPSECURITY_ATTRIBUTES lpThreadAttributes, 00158 DWORD dwStackSize, 00159 LPTHREAD_START_ROUTINE lpStartAddress, 00160 LPVOID lpParameter, 00161 DWORD dwCreationFlags, 00162 LPDWORD lpThreadId) 00163 { 00164 NTSTATUS Status; 00165 INITIAL_TEB InitialTeb; 00166 CONTEXT Context; 00167 CLIENT_ID ClientId; 00168 OBJECT_ATTRIBUTES LocalObjectAttributes; 00169 POBJECT_ATTRIBUTES ObjectAttributes; 00170 HANDLE hThread; 00171 ULONG Dummy; 00172 00173 DPRINT("CreateRemoteThread: hProcess: %ld dwStackSize: %ld lpStartAddress" 00174 ": %p lpParameter: %lx, dwCreationFlags: %lx\n", hProcess, 00175 dwStackSize, lpStartAddress, lpParameter, dwCreationFlags); 00176 00177 /* Clear the Context */ 00178 RtlZeroMemory(&Context, sizeof(CONTEXT)); 00179 00180 /* Write PID */ 00181 ClientId.UniqueProcess = hProcess; 00182 00183 /* Create the Stack */ 00184 Status = BaseCreateStack(hProcess, 00185 dwStackSize, 00186 dwCreationFlags & STACK_SIZE_PARAM_IS_A_RESERVATION ? 00187 dwStackSize : 0, 00188 &InitialTeb); 00189 if(!NT_SUCCESS(Status)) 00190 { 00191 BaseSetLastNTError(Status); 00192 return NULL; 00193 } 00194 00195 /* Create Initial Context */ 00196 BaseInitializeContext(&Context, 00197 lpParameter, 00198 lpStartAddress, 00199 InitialTeb.StackBase, 00200 1); 00201 00202 /* initialize the attributes for the thread object */ 00203 ObjectAttributes = BaseFormatObjectAttributes(&LocalObjectAttributes, 00204 lpThreadAttributes, 00205 NULL); 00206 00207 /* Create the Kernel Thread Object */ 00208 Status = NtCreateThread(&hThread, 00209 THREAD_ALL_ACCESS, 00210 ObjectAttributes, 00211 hProcess, 00212 &ClientId, 00213 &Context, 00214 &InitialTeb, 00215 TRUE); 00216 if(!NT_SUCCESS(Status)) 00217 { 00218 BaseFreeThreadStack(hProcess, &InitialTeb); 00219 BaseSetLastNTError(Status); 00220 return NULL; 00221 } 00222 00223 /* Are we in the same process? */ 00224 if (hProcess == NtCurrentProcess()) 00225 { 00226 PTEB Teb; 00227 PVOID ActivationContextStack = NULL; 00228 THREAD_BASIC_INFORMATION ThreadBasicInfo; 00229 #ifndef SXS_SUPPORT_FIXME 00230 ACTIVATION_CONTEXT_BASIC_INFORMATION ActivationCtxInfo; 00231 ULONG_PTR Cookie; 00232 #endif 00233 ULONG retLen; 00234 00235 /* Get the TEB */ 00236 Status = NtQueryInformationThread(hThread, 00237 ThreadBasicInformation, 00238 &ThreadBasicInfo, 00239 sizeof(ThreadBasicInfo), 00240 &retLen); 00241 if (NT_SUCCESS(Status)) 00242 { 00243 /* Allocate the Activation Context Stack */ 00244 Status = RtlAllocateActivationContextStack(&ActivationContextStack); 00245 } 00246 00247 if (NT_SUCCESS(Status)) 00248 { 00249 Teb = ThreadBasicInfo.TebBaseAddress; 00250 00251 /* Save it */ 00252 Teb->ActivationContextStackPointer = ActivationContextStack; 00253 #ifndef SXS_SUPPORT_FIXME 00254 /* Query the Context */ 00255 Status = RtlQueryInformationActivationContext(1, 00256 0, 00257 NULL, 00258 ActivationContextBasicInformation, 00259 &ActivationCtxInfo, 00260 sizeof(ActivationCtxInfo), 00261 &retLen); 00262 if (NT_SUCCESS(Status)) 00263 { 00264 /* Does it need to be activated? */ 00265 if (!ActivationCtxInfo.hActCtx) 00266 { 00267 /* Activate it */ 00268 Status = RtlActivateActivationContext(1, 00269 ActivationCtxInfo.hActCtx, 00270 &Cookie); 00271 if (!NT_SUCCESS(Status)) 00272 DPRINT1("RtlActivateActivationContext failed %x\n", Status); 00273 } 00274 } 00275 else 00276 DPRINT1("RtlQueryInformationActivationContext failed %x\n", Status); 00277 #endif 00278 } 00279 else 00280 DPRINT1("RtlAllocateActivationContextStack failed %x\n", Status); 00281 } 00282 00283 /* Notify CSR */ 00284 if (!BaseRunningInServerProcess) 00285 { 00286 Status = BasepNotifyCsrOfThread(hThread, &ClientId); 00287 } 00288 else 00289 { 00290 DPRINT("Server thread in Server. Handle: %lx\n", hProcess); 00291 if (hProcess != NtCurrentProcess()) 00292 { 00293 PCSR_CREATE_REMOTE_THREAD CsrCreateRemoteThread; 00294 00295 /* Get the direct CSRSRV export */ 00296 CsrCreateRemoteThread = (PCSR_CREATE_REMOTE_THREAD) 00297 GetProcAddress(GetModuleHandleA("csrsrv"), 00298 "CsrCreateRemoteThread"); 00299 if (CsrCreateRemoteThread) 00300 { 00301 /* Call it instead of going through LPC */ 00302 Status = CsrCreateRemoteThread(hThread, &ClientId); 00303 } 00304 } 00305 } 00306 00307 if (!NT_SUCCESS(Status)) 00308 { 00309 ASSERT(FALSE); 00310 } 00311 00312 /* Success */ 00313 if(lpThreadId) *lpThreadId = HandleToUlong(ClientId.UniqueThread); 00314 00315 /* Resume it if asked */ 00316 if (!(dwCreationFlags & CREATE_SUSPENDED)) 00317 { 00318 NtResumeThread(hThread, &Dummy); 00319 } 00320 00321 /* Return handle to thread */ 00322 return hThread; 00323 } 00324 00325 /* 00326 * @implemented 00327 */ 00328 VOID 00329 WINAPI 00330 ExitThread(IN DWORD uExitCode) 00331 { 00332 NTSTATUS Status; 00333 ULONG LastThread; 00334 PRTL_CRITICAL_SECTION LoaderLock; 00335 00336 /* Make sure loader lock isn't held */ 00337 LoaderLock = NtCurrentPeb()->LoaderLock; 00338 if (LoaderLock) ASSERT(NtCurrentTeb()->ClientId.UniqueThread != LoaderLock->OwningThread); 00339 00340 /* 00341 * Terminate process if this is the last thread 00342 * of the current process 00343 */ 00344 Status = NtQueryInformationThread(NtCurrentThread(), 00345 ThreadAmILastThread, 00346 &LastThread, 00347 sizeof(LastThread), 00348 NULL); 00349 if ((NT_SUCCESS(Status)) && (LastThread)) ExitProcess(uExitCode); 00350 00351 /* Notify DLLs and TLS Callbacks of termination */ 00352 LdrShutdownThread(); 00353 00354 /* Tell the Kernel to free the Stack */ 00355 NtCurrentTeb()->FreeStackOnTermination = TRUE; 00356 NtTerminateThread(NULL, uExitCode); 00357 00358 /* We should never reach this place */ 00359 DPRINT1("It should not happen\n"); 00360 while (TRUE); 00361 } 00362 00363 /* 00364 * @implemented 00365 */ 00366 HANDLE 00367 WINAPI 00368 OpenThread(IN DWORD dwDesiredAccess, 00369 IN BOOL bInheritHandle, 00370 IN DWORD dwThreadId) 00371 { 00372 NTSTATUS Status; 00373 HANDLE ThreadHandle; 00374 OBJECT_ATTRIBUTES ObjectAttributes; 00375 CLIENT_ID ClientId; 00376 00377 ClientId.UniqueProcess = 0; 00378 ClientId.UniqueThread = ULongToHandle(dwThreadId); 00379 00380 InitializeObjectAttributes(&ObjectAttributes, 00381 NULL, 00382 (bInheritHandle ? OBJ_INHERIT : 0), 00383 NULL, 00384 NULL); 00385 00386 Status = NtOpenThread(&ThreadHandle, 00387 dwDesiredAccess, 00388 &ObjectAttributes, 00389 &ClientId); 00390 if (!NT_SUCCESS(Status)) 00391 { 00392 BaseSetLastNTError(Status); 00393 return NULL; 00394 } 00395 00396 return ThreadHandle; 00397 } 00398 00399 /* 00400 * @implemented 00401 */ 00402 PTEB 00403 GetTeb(VOID) 00404 { 00405 return NtCurrentTeb(); 00406 } 00407 00408 /* 00409 * @implemented 00410 */ 00411 BOOL 00412 WINAPI 00413 SwitchToThread(VOID) 00414 { 00415 return NtYieldExecution() != STATUS_NO_YIELD_PERFORMED; 00416 } 00417 00418 00419 /* 00420 * @implemented 00421 */ 00422 DWORD 00423 WINAPI 00424 GetCurrentThreadId(VOID) 00425 { 00426 return HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread); 00427 } 00428 00429 /* 00430 * @implemented 00431 */ 00432 BOOL 00433 NTAPI 00434 GetThreadTimes(IN HANDLE hThread, 00435 OUT LPFILETIME lpCreationTime, 00436 OUT LPFILETIME lpExitTime, 00437 OUT LPFILETIME lpKernelTime, 00438 OUT LPFILETIME lpUserTime) 00439 { 00440 KERNEL_USER_TIMES KernelUserTimes; 00441 NTSTATUS Status; 00442 00443 Status = NtQueryInformationThread(hThread, 00444 ThreadTimes, 00445 &KernelUserTimes, 00446 sizeof(KERNEL_USER_TIMES), 00447 NULL); 00448 if (!NT_SUCCESS(Status)) 00449 { 00450 BaseSetLastNTError(Status); 00451 return FALSE; 00452 } 00453 00454 *lpCreationTime = *(LPFILETIME)&KernelUserTimes.CreateTime; 00455 *lpExitTime = *(LPFILETIME)&KernelUserTimes.ExitTime; 00456 *lpKernelTime = *(LPFILETIME)&KernelUserTimes.KernelTime; 00457 *lpUserTime = *(LPFILETIME)&KernelUserTimes.UserTime; 00458 return TRUE; 00459 } 00460 00461 /* 00462 * @implemented 00463 */ 00464 BOOL 00465 WINAPI 00466 GetThreadContext(IN HANDLE hThread, 00467 OUT LPCONTEXT lpContext) 00468 { 00469 NTSTATUS Status; 00470 00471 Status = NtGetContextThread(hThread, lpContext); 00472 if (!NT_SUCCESS(Status)) 00473 { 00474 BaseSetLastNTError(Status); 00475 return FALSE; 00476 } 00477 00478 return TRUE; 00479 } 00480 00481 /* 00482 * @implemented 00483 */ 00484 BOOL 00485 WINAPI 00486 SetThreadContext(IN HANDLE hThread, 00487 IN CONST CONTEXT *lpContext) 00488 { 00489 NTSTATUS Status; 00490 00491 Status = NtSetContextThread(hThread, (PCONTEXT)lpContext); 00492 if (!NT_SUCCESS(Status)) 00493 { 00494 BaseSetLastNTError(Status); 00495 return FALSE; 00496 } 00497 00498 return TRUE; 00499 } 00500 00501 /* 00502 * @implemented 00503 */ 00504 BOOL 00505 WINAPI 00506 GetExitCodeThread(IN HANDLE hThread, 00507 OUT LPDWORD lpExitCode) 00508 { 00509 THREAD_BASIC_INFORMATION ThreadBasic; 00510 NTSTATUS Status; 00511 00512 Status = NtQueryInformationThread(hThread, 00513 ThreadBasicInformation, 00514 &ThreadBasic, 00515 sizeof(THREAD_BASIC_INFORMATION), 00516 NULL); 00517 if (!NT_SUCCESS(Status)) 00518 { 00519 BaseSetLastNTError(Status); 00520 return FALSE; 00521 } 00522 00523 *lpExitCode = ThreadBasic.ExitStatus; 00524 return TRUE; 00525 } 00526 00527 /* 00528 * @implemented 00529 */ 00530 DWORD 00531 WINAPI 00532 ResumeThread(IN HANDLE hThread) 00533 { 00534 ULONG PreviousResumeCount; 00535 NTSTATUS Status; 00536 00537 Status = NtResumeThread(hThread, &PreviousResumeCount); 00538 if (!NT_SUCCESS(Status)) 00539 { 00540 BaseSetLastNTError(Status); 00541 return -1; 00542 } 00543 00544 return PreviousResumeCount; 00545 } 00546 00547 /* 00548 * @implemented 00549 */ 00550 BOOL 00551 WINAPI 00552 TerminateThread(IN HANDLE hThread, 00553 IN DWORD dwExitCode) 00554 { 00555 NTSTATUS Status; 00556 PRTL_CRITICAL_SECTION LoaderLock; 00557 THREAD_BASIC_INFORMATION ThreadInfo; 00558 00559 /* Check for invalid thread handle */ 00560 if (!hThread) 00561 { 00562 /* Fail if one was passed */ 00563 SetLastError(ERROR_INVALID_HANDLE); 00564 return FALSE; 00565 } 00566 00567 /* Get the loader lock */ 00568 LoaderLock = NtCurrentPeb()->LoaderLock; 00569 if (LoaderLock) 00570 { 00571 /* Get our TID */ 00572 Status = NtQueryInformationThread(hThread, 00573 ThreadBasicInformation, 00574 &ThreadInfo, 00575 sizeof(ThreadInfo), 00576 NULL); 00577 if (!NT_SUCCESS(Status)) 00578 { 00579 /* Assert that we don't hold the loader lock */ 00580 ASSERT(NtCurrentTeb()->ClientId.UniqueThread != ThreadInfo.ClientId.UniqueThread); 00581 ASSERT(NtCurrentTeb()->ClientId.UniqueThread != LoaderLock->OwningThread); 00582 } 00583 } 00584 00585 /* Now terminate the thread */ 00586 Status = NtTerminateThread(hThread, dwExitCode); 00587 if (!NT_SUCCESS(Status)) 00588 { 00589 /* Fail */ 00590 BaseSetLastNTError(Status); 00591 return FALSE; 00592 } 00593 00594 /* All done */ 00595 return TRUE; 00596 } 00597 00598 /* 00599 * @implemented 00600 */ 00601 DWORD 00602 WINAPI 00603 SuspendThread(IN HANDLE hThread) 00604 { 00605 ULONG PreviousSuspendCount; 00606 NTSTATUS Status; 00607 00608 Status = NtSuspendThread(hThread, &PreviousSuspendCount); 00609 if (!NT_SUCCESS(Status)) 00610 { 00611 BaseSetLastNTError(Status); 00612 return -1; 00613 } 00614 00615 return PreviousSuspendCount; 00616 } 00617 00618 /* 00619 * @implemented 00620 */ 00621 DWORD_PTR 00622 WINAPI 00623 SetThreadAffinityMask(IN HANDLE hThread, 00624 IN DWORD_PTR dwThreadAffinityMask) 00625 { 00626 THREAD_BASIC_INFORMATION ThreadBasic; 00627 KAFFINITY AffinityMask; 00628 NTSTATUS Status; 00629 00630 AffinityMask = (KAFFINITY)dwThreadAffinityMask; 00631 00632 Status = NtQueryInformationThread(hThread, 00633 ThreadBasicInformation, 00634 &ThreadBasic, 00635 sizeof(THREAD_BASIC_INFORMATION), 00636 NULL); 00637 if (!NT_SUCCESS(Status)) 00638 { 00639 BaseSetLastNTError(Status); 00640 return 0; 00641 } 00642 00643 Status = NtSetInformationThread(hThread, 00644 ThreadAffinityMask, 00645 &AffinityMask, 00646 sizeof(KAFFINITY)); 00647 if (!NT_SUCCESS(Status)) 00648 { 00649 BaseSetLastNTError(Status); 00650 ThreadBasic.AffinityMask = 0; 00651 } 00652 00653 return ThreadBasic.AffinityMask; 00654 } 00655 00656 /* 00657 * @implemented 00658 */ 00659 BOOL 00660 WINAPI 00661 SetThreadPriority(IN HANDLE hThread, 00662 IN int nPriority) 00663 { 00664 LONG Prio = nPriority; 00665 NTSTATUS Status; 00666 00667 /* Check if values forcing saturation should be used */ 00668 if (Prio == THREAD_PRIORITY_TIME_CRITICAL) 00669 { 00670 /* This is 16 */ 00671 Prio = (HIGH_PRIORITY + 1) / 2; 00672 } 00673 else if (Prio == THREAD_PRIORITY_IDLE) 00674 { 00675 /* This is -16 */ 00676 Prio = -((HIGH_PRIORITY + 1) / 2); 00677 } 00678 00679 /* Set the Base Priority */ 00680 Status = NtSetInformationThread(hThread, 00681 ThreadBasePriority, 00682 &Prio, 00683 sizeof(LONG)); 00684 if (!NT_SUCCESS(Status)) 00685 { 00686 /* Failure */ 00687 BaseSetLastNTError(Status); 00688 return FALSE; 00689 } 00690 00691 /* Return */ 00692 return TRUE; 00693 } 00694 00695 /* 00696 * @implemented 00697 */ 00698 int 00699 WINAPI 00700 GetThreadPriority(IN HANDLE hThread) 00701 { 00702 THREAD_BASIC_INFORMATION ThreadBasic; 00703 NTSTATUS Status; 00704 00705 /* Query the Base Priority Increment */ 00706 Status = NtQueryInformationThread(hThread, 00707 ThreadBasicInformation, 00708 &ThreadBasic, 00709 sizeof(THREAD_BASIC_INFORMATION), 00710 NULL); 00711 if (!NT_SUCCESS(Status)) 00712 { 00713 /* Failure */ 00714 BaseSetLastNTError(Status); 00715 return THREAD_PRIORITY_ERROR_RETURN; 00716 } 00717 00718 /* Do some conversions for saturation values */ 00719 if (ThreadBasic.BasePriority == ((HIGH_PRIORITY + 1) / 2)) 00720 { 00721 /* Win32 calls this "time critical" */ 00722 ThreadBasic.BasePriority = THREAD_PRIORITY_TIME_CRITICAL; 00723 } 00724 else if (ThreadBasic.BasePriority == -((HIGH_PRIORITY + 1) / 2)) 00725 { 00726 /* Win32 calls this "idle" */ 00727 ThreadBasic.BasePriority = THREAD_PRIORITY_IDLE; 00728 } 00729 00730 /* Return the final result */ 00731 return ThreadBasic.BasePriority; 00732 } 00733 00734 /* 00735 * @implemented 00736 */ 00737 BOOL 00738 WINAPI 00739 GetThreadPriorityBoost(IN HANDLE hThread, 00740 OUT PBOOL pDisablePriorityBoost) 00741 { 00742 ULONG PriorityBoost; 00743 NTSTATUS Status; 00744 00745 Status = NtQueryInformationThread(hThread, 00746 ThreadPriorityBoost, 00747 &PriorityBoost, 00748 sizeof(ULONG), 00749 NULL); 00750 if (!NT_SUCCESS(Status)) 00751 { 00752 BaseSetLastNTError(Status); 00753 return FALSE; 00754 } 00755 00756 *pDisablePriorityBoost = PriorityBoost; 00757 return TRUE; 00758 } 00759 00760 /* 00761 * @implemented 00762 */ 00763 BOOL 00764 NTAPI 00765 SetThreadPriorityBoost(IN HANDLE hThread, 00766 IN BOOL bDisablePriorityBoost) 00767 { 00768 ULONG PriorityBoost; 00769 NTSTATUS Status; 00770 00771 PriorityBoost = bDisablePriorityBoost != FALSE; 00772 00773 Status = NtSetInformationThread(hThread, 00774 ThreadPriorityBoost, 00775 &PriorityBoost, 00776 sizeof(ULONG)); 00777 if (!NT_SUCCESS(Status)) 00778 { 00779 BaseSetLastNTError(Status); 00780 return FALSE; 00781 } 00782 00783 return TRUE; 00784 } 00785 00786 /* 00787 * @implemented 00788 */ 00789 BOOL 00790 WINAPI 00791 GetThreadSelectorEntry(IN HANDLE hThread, 00792 IN DWORD dwSelector, 00793 OUT LPLDT_ENTRY lpSelectorEntry) 00794 { 00795 #ifdef _M_IX86 00796 DESCRIPTOR_TABLE_ENTRY DescriptionTableEntry; 00797 NTSTATUS Status; 00798 00799 /* Set the selector and do the query */ 00800 DescriptionTableEntry.Selector = dwSelector; 00801 Status = NtQueryInformationThread(hThread, 00802 ThreadDescriptorTableEntry, 00803 &DescriptionTableEntry, 00804 sizeof(DESCRIPTOR_TABLE_ENTRY), 00805 NULL); 00806 if (!NT_SUCCESS(Status)) 00807 { 00808 /* Fail */ 00809 BaseSetLastNTError(Status); 00810 return FALSE; 00811 } 00812 00813 /* Success, return the selector */ 00814 *lpSelectorEntry = DescriptionTableEntry.Descriptor; 00815 return TRUE; 00816 #else 00817 DPRINT1("Calling GetThreadSelectorEntry!\n"); 00818 return FALSE; 00819 #endif 00820 } 00821 00822 /* 00823 * @implemented 00824 */ 00825 DWORD 00826 WINAPI 00827 SetThreadIdealProcessor(IN HANDLE hThread, 00828 IN DWORD dwIdealProcessor) 00829 { 00830 NTSTATUS Status; 00831 00832 Status = NtSetInformationThread(hThread, 00833 ThreadIdealProcessor, 00834 &dwIdealProcessor, 00835 sizeof(ULONG)); 00836 if (!NT_SUCCESS(Status)) 00837 { 00838 BaseSetLastNTError(Status); 00839 return -1; 00840 } 00841 00842 return (DWORD)Status; 00843 } 00844 00845 /* 00846 * @implemented 00847 */ 00848 DWORD 00849 WINAPI 00850 GetProcessIdOfThread(IN HANDLE Thread) 00851 { 00852 THREAD_BASIC_INFORMATION ThreadBasic; 00853 NTSTATUS Status; 00854 00855 Status = NtQueryInformationThread(Thread, 00856 ThreadBasicInformation, 00857 &ThreadBasic, 00858 sizeof(THREAD_BASIC_INFORMATION), 00859 NULL); 00860 if (!NT_SUCCESS(Status)) 00861 { 00862 BaseSetLastNTError(Status); 00863 return 0; 00864 } 00865 00866 return HandleToUlong(ThreadBasic.ClientId.UniqueProcess); 00867 } 00868 00869 /* 00870 * @implemented 00871 */ 00872 DWORD 00873 WINAPI 00874 GetThreadId(IN HANDLE Thread) 00875 { 00876 THREAD_BASIC_INFORMATION ThreadBasic; 00877 NTSTATUS Status; 00878 00879 Status = NtQueryInformationThread(Thread, 00880 ThreadBasicInformation, 00881 &ThreadBasic, 00882 sizeof(THREAD_BASIC_INFORMATION), 00883 NULL); 00884 if (!NT_SUCCESS(Status)) 00885 { 00886 BaseSetLastNTError(Status); 00887 return 0; 00888 } 00889 00890 return HandleToUlong(ThreadBasic.ClientId.UniqueThread); 00891 } 00892 00893 /* 00894 * @unimplemented 00895 */ 00896 LANGID 00897 WINAPI 00898 SetThreadUILanguage(IN LANGID LangId) 00899 { 00900 UNIMPLEMENTED; 00901 return NtCurrentTeb()->CurrentLocale; 00902 } 00903 00904 /* 00905 * @implemented 00906 */ 00907 DWORD 00908 WINAPI 00909 QueueUserAPC(IN PAPCFUNC pfnAPC, 00910 IN HANDLE hThread, 00911 IN ULONG_PTR dwData) 00912 { 00913 NTSTATUS Status; 00914 ACTIVATION_CONTEXT_BASIC_INFORMATION ActCtxInfo; 00915 00916 /* Zero the activation context and query information on it */ 00917 RtlZeroMemory(&ActCtxInfo, sizeof(ActCtxInfo)); 00918 // WARNING!!! THIS IS USING THE WIN32 FLAG BECAUSE REACTOS CONTINUES TO BE A POS!!! /// 00919 Status = RtlQueryInformationActivationContext(QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX, 00920 NULL, 00921 0, 00922 ActivationContextBasicInformation, 00923 &ActCtxInfo, 00924 sizeof(ActCtxInfo), 00925 NULL); 00926 if (!NT_SUCCESS(Status)) 00927 { 00928 /* Fail due to SxS */ 00929 DbgPrint("SXS: %s failing because RtlQueryInformationActivationContext()" 00930 "returned status %08lx\n", __FUNCTION__, Status); 00931 BaseSetLastNTError(Status); 00932 return FALSE; 00933 } 00934 00935 /* Queue the APC */ 00936 Status = NtQueueApcThread(hThread, 00937 (PKNORMAL_ROUTINE)BaseDispatchApc, 00938 pfnAPC, 00939 (PVOID)dwData, 00940 (ActCtxInfo.dwFlags & 1) ? 00941 INVALID_ACTIVATION_CONTEXT : ActCtxInfo.hActCtx); 00942 if (!NT_SUCCESS(Status)) 00943 { 00944 BaseSetLastNTError(Status); 00945 return FALSE; 00946 } 00947 00948 /* All good */ 00949 return TRUE; 00950 } 00951 00952 /* 00953 * @implemented 00954 */ 00955 BOOL 00956 WINAPI 00957 SetThreadStackGuarantee(IN OUT PULONG StackSizeInBytes) 00958 { 00959 UNIMPLEMENTED; 00960 return FALSE; 00961 } 00962 00963 /* 00964 * @implemented 00965 */ 00966 BOOL 00967 WINAPI 00968 GetThreadIOPendingFlag(IN HANDLE hThread, 00969 OUT PBOOL lpIOIsPending) 00970 { 00971 ULONG IoPending; 00972 NTSTATUS Status; 00973 00974 /* Query the flag */ 00975 Status = NtQueryInformationThread(hThread, 00976 ThreadIsIoPending, 00977 &IoPending, 00978 sizeof(IoPending), 00979 NULL); 00980 if (NT_SUCCESS(Status)) 00981 { 00982 /* Return the flag */ 00983 *lpIOIsPending = IoPending ? TRUE : FALSE; 00984 return TRUE; 00985 } 00986 00987 /* Fail */ 00988 BaseSetLastNTError(Status); 00989 return FALSE; 00990 } 00991 00992 /* 00993 * @implemented 00994 */ 00995 BOOL 00996 WINAPI 00997 QueueUserWorkItem(IN LPTHREAD_START_ROUTINE Function, 00998 IN PVOID Context, 00999 IN ULONG Flags) 01000 { 01001 NTSTATUS Status; 01002 01003 /* NOTE: Rtl needs to safely call the function using a trampoline */ 01004 Status = RtlQueueWorkItem((WORKERCALLBACKFUNC)Function, Context, Flags); 01005 if (!NT_SUCCESS(Status)) 01006 { 01007 /* Failed */ 01008 BaseSetLastNTError(Status); 01009 return FALSE; 01010 } 01011 01012 /* All good */ 01013 return TRUE; 01014 } 01015 01016 /* 01017 * @implemented 01018 */ 01019 DWORD 01020 WINAPI 01021 TlsAlloc(VOID) 01022 { 01023 ULONG Index; 01024 PTEB Teb; 01025 PPEB Peb; 01026 01027 /* Get the PEB and TEB, lock the PEB */ 01028 Teb = NtCurrentTeb(); 01029 Peb = Teb->ProcessEnvironmentBlock; 01030 RtlAcquirePebLock(); 01031 01032 /* Try to get regular TEB slot */ 01033 Index = RtlFindClearBitsAndSet(Peb->TlsBitmap, 1, 0); 01034 if (Index != 0xFFFFFFFF) 01035 { 01036 /* Clear the value. */ 01037 Teb->TlsSlots[Index] = 0; 01038 RtlReleasePebLock(); 01039 return Index; 01040 } 01041 01042 /* If it fails, try to find expansion TEB slot. */ 01043 Index = RtlFindClearBitsAndSet(Peb->TlsExpansionBitmap, 1, 0); 01044 if (Index != 0xFFFFFFFF) 01045 { 01046 /* Is there no expansion slot yet? */ 01047 if (!Teb->TlsExpansionSlots) 01048 { 01049 /* Allocate an array */ 01050 Teb->TlsExpansionSlots = RtlAllocateHeap(RtlGetProcessHeap(), 01051 HEAP_ZERO_MEMORY, 01052 TLS_EXPANSION_SLOTS * 01053 sizeof(PVOID)); 01054 } 01055 01056 /* Did we get an array? */ 01057 if (!Teb->TlsExpansionSlots) 01058 { 01059 /* Fail */ 01060 RtlClearBits(Peb->TlsExpansionBitmap, Index, 1); 01061 Index = 0xFFFFFFFF; 01062 BaseSetLastNTError(STATUS_NO_MEMORY); 01063 } 01064 else 01065 { 01066 /* Clear the value. */ 01067 Teb->TlsExpansionSlots[Index] = 0; 01068 Index += TLS_MINIMUM_AVAILABLE; 01069 } 01070 } 01071 else 01072 { 01073 /* Fail */ 01074 BaseSetLastNTError(STATUS_NO_MEMORY); 01075 } 01076 01077 /* Release the lock and return */ 01078 RtlReleasePebLock(); 01079 return Index; 01080 } 01081 01082 /* 01083 * @implemented 01084 */ 01085 BOOL 01086 WINAPI 01087 TlsFree(IN DWORD Index) 01088 { 01089 BOOL BitSet; 01090 PPEB Peb; 01091 ULONG TlsIndex; 01092 PVOID TlsBitmap; 01093 NTSTATUS Status; 01094 01095 /* Acquire the PEB lock and grab the PEB */ 01096 Peb = NtCurrentPeb(); 01097 RtlAcquirePebLock(); 01098 01099 /* Check if the index is too high */ 01100 if (Index >= TLS_MINIMUM_AVAILABLE) 01101 { 01102 /* Check if it can fit in the expansion slots */ 01103 TlsIndex = Index - TLS_MINIMUM_AVAILABLE; 01104 if (TlsIndex >= TLS_EXPANSION_SLOTS) 01105 { 01106 /* It's invalid */ 01107 BaseSetLastNTError(STATUS_INVALID_PARAMETER); 01108 RtlReleasePebLock(); 01109 return FALSE; 01110 } 01111 else 01112 { 01113 /* Use the expansion bitmap */ 01114 TlsBitmap = Peb->TlsExpansionBitmap; 01115 Index = TlsIndex; 01116 } 01117 } 01118 else 01119 { 01120 /* Use the normal bitmap */ 01121 TlsBitmap = Peb->TlsBitmap; 01122 } 01123 01124 /* Check if the index was set */ 01125 BitSet = RtlAreBitsSet(TlsBitmap, Index, 1); 01126 if (BitSet) 01127 { 01128 /* Tell the kernel to free the TLS cells */ 01129 Status = NtSetInformationThread(NtCurrentThread(), 01130 ThreadZeroTlsCell, 01131 &Index, 01132 sizeof(DWORD)); 01133 if (!NT_SUCCESS(Status)) 01134 { 01135 BaseSetLastNTError(STATUS_INVALID_PARAMETER); 01136 RtlReleasePebLock(); 01137 return FALSE; 01138 } 01139 01140 /* Clear the bit */ 01141 RtlClearBits(TlsBitmap, Index, 1); 01142 } 01143 else 01144 { 01145 /* Fail */ 01146 BaseSetLastNTError(STATUS_INVALID_PARAMETER); 01147 RtlReleasePebLock(); 01148 return FALSE; 01149 } 01150 01151 /* Done! */ 01152 RtlReleasePebLock(); 01153 return TRUE; 01154 } 01155 01156 /* 01157 * @implemented 01158 */ 01159 LPVOID 01160 WINAPI 01161 TlsGetValue(IN DWORD Index) 01162 { 01163 PTEB Teb; 01164 01165 /* Get the TEB and clear the last error */ 01166 Teb = NtCurrentTeb(); 01167 Teb->LastErrorValue = 0; 01168 01169 /* Check for simple TLS index */ 01170 if (Index < TLS_MINIMUM_AVAILABLE) 01171 { 01172 /* Return it */ 01173 return Teb->TlsSlots[Index]; 01174 } 01175 01176 /* Check for valid index */ 01177 if (Index >= TLS_EXPANSION_SLOTS + TLS_MINIMUM_AVAILABLE) 01178 { 01179 /* Fail */ 01180 BaseSetLastNTError(STATUS_INVALID_PARAMETER); 01181 return NULL; 01182 } 01183 01184 /* The expansion slots are allocated on demand, so check for it. */ 01185 Teb->LastErrorValue = 0; 01186 if (!Teb->TlsExpansionSlots) return NULL; 01187 01188 /* Return the value from the expansion slots */ 01189 return Teb->TlsExpansionSlots[Index - TLS_MINIMUM_AVAILABLE]; 01190 } 01191 01192 /* 01193 * @implemented 01194 */ 01195 BOOL 01196 WINAPI 01197 TlsSetValue(IN DWORD Index, 01198 IN LPVOID Value) 01199 { 01200 DWORD TlsIndex; 01201 PTEB Teb = NtCurrentTeb(); 01202 01203 /* Check for simple TLS index */ 01204 if (Index < TLS_MINIMUM_AVAILABLE) 01205 { 01206 /* Return it */ 01207 Teb->TlsSlots[Index] = Value; 01208 return TRUE; 01209 } 01210 01211 /* Check if this is an expansion slot */ 01212 TlsIndex = Index - TLS_MINIMUM_AVAILABLE; 01213 if (TlsIndex >= TLS_EXPANSION_SLOTS) 01214 { 01215 /* Fail */ 01216 BaseSetLastNTError(STATUS_INVALID_PARAMETER); 01217 return FALSE; 01218 } 01219 01220 /* Do we not have expansion slots? */ 01221 if (!Teb->TlsExpansionSlots) 01222 { 01223 /* Get the PEB lock to see if we still need them */ 01224 RtlAcquirePebLock(); 01225 if (!Teb->TlsExpansionSlots) 01226 { 01227 /* Allocate them */ 01228 Teb->TlsExpansionSlots = RtlAllocateHeap(RtlGetProcessHeap(), 01229 HEAP_ZERO_MEMORY, 01230 TLS_EXPANSION_SLOTS * 01231 sizeof(PVOID)); 01232 if (!Teb->TlsExpansionSlots) 01233 { 01234 /* Fail */ 01235 RtlReleasePebLock(); 01236 BaseSetLastNTError(STATUS_NO_MEMORY); 01237 return FALSE; 01238 } 01239 } 01240 01241 /* Release the lock */ 01242 RtlReleasePebLock(); 01243 } 01244 01245 /* Write the value */ 01246 Teb->TlsExpansionSlots[TlsIndex] = Value; 01247 01248 /* Success */ 01249 return TRUE; 01250 } 01251 01252 /* EOF */ Generated on Thu May 24 2012 04:24:47 for ReactOS by
1.7.6.1
|