Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenthread.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Kernel 00003 * LICENSE: GPL - See COPYING in the top level directory 00004 * FILE: ntoskrnl/ps/thread.c 00005 * PURPOSE: Process Manager: Thread Management 00006 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 00007 * Thomas Weidenmueller (w3seek@reactos.org) 00008 */ 00009 00010 /* INCLUDES ****************************************************************/ 00011 00012 #include <ntoskrnl.h> 00013 #define NDEBUG 00014 #include <debug.h> 00015 00016 /* GLOBALS ******************************************************************/ 00017 00018 extern BOOLEAN CcPfEnablePrefetcher; 00019 extern ULONG MmReadClusterSize; 00020 POBJECT_TYPE PsThreadType = NULL; 00021 00022 /* PRIVATE FUNCTIONS *********************************************************/ 00023 00024 VOID 00025 NTAPI 00026 PspUserThreadStartup(IN PKSTART_ROUTINE StartRoutine, 00027 IN PVOID StartContext) 00028 { 00029 PETHREAD Thread; 00030 PTEB Teb; 00031 BOOLEAN DeadThread = FALSE; 00032 KIRQL OldIrql; 00033 PAGED_CODE(); 00034 PSTRACE(PS_THREAD_DEBUG, 00035 "StartRoutine: %p StartContext: %p\n", StartRoutine, StartContext); 00036 00037 /* Go to Passive Level */ 00038 KeLowerIrql(PASSIVE_LEVEL); 00039 Thread = PsGetCurrentThread(); 00040 00041 /* Check if the thread is dead */ 00042 if (Thread->DeadThread) 00043 { 00044 /* Remember that we're dead */ 00045 DeadThread = TRUE; 00046 } 00047 else 00048 { 00049 /* Get the Locale ID and save Preferred Proc */ 00050 Teb = NtCurrentTeb(); 00051 Teb->CurrentLocale = MmGetSessionLocaleId(); 00052 Teb->IdealProcessor = Thread->Tcb.IdealProcessor; 00053 } 00054 00055 /* Check if this is a dead thread, or if we're hiding */ 00056 if (!(Thread->DeadThread) && !(Thread->HideFromDebugger)) 00057 { 00058 /* We're not, so notify the debugger */ 00059 DbgkCreateThread(Thread, StartContext); 00060 } 00061 00062 /* Make sure we're not already dead */ 00063 if (!DeadThread) 00064 { 00065 /* Check if the Prefetcher is enabled */ 00066 if (CcPfEnablePrefetcher) 00067 { 00068 /* FIXME: Prepare to prefetch this process */ 00069 } 00070 00071 /* Raise to APC */ 00072 KeRaiseIrql(APC_LEVEL, &OldIrql); 00073 00074 /* Queue the User APC */ 00075 KiInitializeUserApc(KeGetExceptionFrame(&Thread->Tcb), 00076 KeGetTrapFrame(&Thread->Tcb), 00077 PspSystemDllEntryPoint, 00078 NULL, 00079 PspSystemDllBase, 00080 NULL); 00081 00082 /* Lower it back to passive */ 00083 KeLowerIrql(PASSIVE_LEVEL); 00084 } 00085 else 00086 { 00087 /* We're dead, kill us now */ 00088 PspTerminateThreadByPointer(Thread, 00089 STATUS_THREAD_IS_TERMINATING, 00090 TRUE); 00091 } 00092 00093 /* Do we have a cookie set yet? */ 00094 while (!SharedUserData->Cookie) 00095 { 00096 LARGE_INTEGER SystemTime; 00097 ULONG NewCookie; 00098 PKPRCB Prcb; 00099 00100 /* Generate a new cookie */ 00101 KeQuerySystemTime(&SystemTime); 00102 Prcb = KeGetCurrentPrcb(); 00103 NewCookie = (Prcb->MmPageFaultCount ^ Prcb->InterruptTime ^ 00104 SystemTime.u.LowPart ^ SystemTime.u.HighPart ^ 00105 (ULONG)(ULONG_PTR)&SystemTime); 00106 00107 /* Set the new cookie*/ 00108 InterlockedCompareExchange((LONG*)&SharedUserData->Cookie, 00109 NewCookie, 00110 0); 00111 } 00112 } 00113 00114 LONG 00115 PspUnhandledExceptionInSystemThread(PEXCEPTION_POINTERS ExceptionPointers) 00116 { 00117 /* Print debugging information */ 00118 DPRINT1("PS: Unhandled Kernel Mode Exception Pointers = 0x%p\n", 00119 ExceptionPointers); 00120 DPRINT1("Code %x Addr %p Info0 %p Info1 %p Info2 %p Info3 %p\n", 00121 ExceptionPointers->ExceptionRecord->ExceptionCode, 00122 ExceptionPointers->ExceptionRecord->ExceptionAddress, 00123 ExceptionPointers->ExceptionRecord->ExceptionInformation[0], 00124 ExceptionPointers->ExceptionRecord->ExceptionInformation[1], 00125 ExceptionPointers->ExceptionRecord->ExceptionInformation[2], 00126 ExceptionPointers->ExceptionRecord->ExceptionInformation[3]); 00127 00128 /* Bugcheck the system */ 00129 KeBugCheckEx(SYSTEM_THREAD_EXCEPTION_NOT_HANDLED, 00130 ExceptionPointers->ExceptionRecord->ExceptionCode, 00131 (ULONG_PTR)ExceptionPointers->ExceptionRecord->ExceptionAddress, 00132 (ULONG_PTR)ExceptionPointers->ExceptionRecord, 00133 (ULONG_PTR)ExceptionPointers->ContextRecord); 00134 return 0; 00135 } 00136 00137 VOID 00138 NTAPI 00139 PspSystemThreadStartup(IN PKSTART_ROUTINE StartRoutine, 00140 IN PVOID StartContext) 00141 { 00142 PETHREAD Thread; 00143 PSTRACE(PS_THREAD_DEBUG, 00144 "StartRoutine: %p StartContext: %p\n", StartRoutine, StartContext); 00145 00146 /* Unlock the dispatcher Database */ 00147 KeLowerIrql(PASSIVE_LEVEL); 00148 Thread = PsGetCurrentThread(); 00149 00150 /* Make sure the thread isn't gone */ 00151 _SEH2_TRY 00152 { 00153 if (!(Thread->Terminated) && !(Thread->DeadThread)) 00154 { 00155 /* Call the Start Routine */ 00156 StartRoutine(StartContext); 00157 } 00158 } 00159 _SEH2_EXCEPT(PspUnhandledExceptionInSystemThread(_SEH2_GetExceptionInformation())) 00160 { 00161 /* Bugcheck if we got here */ 00162 KeBugCheck(KMODE_EXCEPTION_NOT_HANDLED); 00163 } 00164 _SEH2_END; 00165 00166 /* Exit the thread */ 00167 PspTerminateThreadByPointer(Thread, STATUS_SUCCESS, TRUE); 00168 } 00169 00170 NTSTATUS 00171 NTAPI 00172 PspCreateThread(OUT PHANDLE ThreadHandle, 00173 IN ACCESS_MASK DesiredAccess, 00174 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, 00175 IN HANDLE ProcessHandle, 00176 IN PEPROCESS TargetProcess, 00177 OUT PCLIENT_ID ClientId, 00178 IN PCONTEXT ThreadContext, 00179 IN PINITIAL_TEB InitialTeb, 00180 IN BOOLEAN CreateSuspended, 00181 IN PKSTART_ROUTINE StartRoutine OPTIONAL, 00182 IN PVOID StartContext OPTIONAL) 00183 { 00184 HANDLE hThread; 00185 PEPROCESS Process; 00186 PETHREAD Thread; 00187 PTEB TebBase = NULL; 00188 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 00189 NTSTATUS Status, AccessStatus; 00190 HANDLE_TABLE_ENTRY CidEntry; 00191 ACCESS_STATE LocalAccessState; 00192 PACCESS_STATE AccessState = &LocalAccessState; 00193 AUX_ACCESS_DATA AuxData; 00194 BOOLEAN Result, SdAllocated; 00195 PSECURITY_DESCRIPTOR SecurityDescriptor; 00196 SECURITY_SUBJECT_CONTEXT SubjectContext; 00197 PAGED_CODE(); 00198 PSTRACE(PS_THREAD_DEBUG, 00199 "ThreadContext: %p TargetProcess: %p ProcessHandle: %p\n", 00200 ThreadContext, TargetProcess, ProcessHandle); 00201 00202 /* If we were called from PsCreateSystemThread, then we're kernel mode */ 00203 if (StartRoutine) PreviousMode = KernelMode; 00204 00205 /* Reference the Process by handle or pointer, depending on what we got */ 00206 if (ProcessHandle) 00207 { 00208 /* Normal thread or System Thread */ 00209 Status = ObReferenceObjectByHandle(ProcessHandle, 00210 PROCESS_CREATE_THREAD, 00211 PsProcessType, 00212 PreviousMode, 00213 (PVOID*)&Process, 00214 NULL); 00215 PSREFTRACE(Process); 00216 } 00217 else 00218 { 00219 /* System thread inside System Process, or Normal Thread with a bug */ 00220 if (StartRoutine) 00221 { 00222 /* Reference the Process by Pointer */ 00223 ObReferenceObject(TargetProcess); 00224 Process = TargetProcess; 00225 Status = STATUS_SUCCESS; 00226 } 00227 else 00228 { 00229 /* Fake ObReference returning this */ 00230 Status = STATUS_INVALID_HANDLE; 00231 } 00232 } 00233 00234 /* Check for success */ 00235 if (!NT_SUCCESS(Status)) return Status; 00236 00237 /* Also make sure that User-Mode isn't trying to create a system thread */ 00238 if ((PreviousMode != KernelMode) && (Process == PsInitialSystemProcess)) 00239 { 00240 /* Fail */ 00241 ObDereferenceObject(Process); 00242 return STATUS_INVALID_HANDLE; 00243 } 00244 00245 /* Create Thread Object */ 00246 Status = ObCreateObject(PreviousMode, 00247 PsThreadType, 00248 ObjectAttributes, 00249 PreviousMode, 00250 NULL, 00251 sizeof(ETHREAD), 00252 0, 00253 0, 00254 (PVOID*)&Thread); 00255 if (!NT_SUCCESS(Status)) 00256 { 00257 /* We failed; dereference the process and exit */ 00258 ObDereferenceObject(Process); 00259 return Status; 00260 } 00261 00262 /* Zero the Object entirely */ 00263 RtlZeroMemory(Thread, sizeof(ETHREAD)); 00264 00265 /* Initialize rundown protection */ 00266 ExInitializeRundownProtection(&Thread->RundownProtect); 00267 00268 /* Initialize exit code */ 00269 Thread->ExitStatus = STATUS_PENDING; 00270 00271 /* Set the Process CID */ 00272 Thread->ThreadsProcess = Process; 00273 Thread->Cid.UniqueProcess = Process->UniqueProcessId; 00274 00275 /* Create Cid Handle */ 00276 CidEntry.Object = Thread; 00277 CidEntry.GrantedAccess = 0; 00278 Thread->Cid.UniqueThread = ExCreateHandle(PspCidTable, &CidEntry); 00279 if (!Thread->Cid.UniqueThread) 00280 { 00281 /* We couldn't create the CID, dereference the thread and fail */ 00282 ObDereferenceObject(Thread); 00283 return STATUS_INSUFFICIENT_RESOURCES; 00284 } 00285 00286 /* Save the read cluster size */ 00287 Thread->ReadClusterSize = MmReadClusterSize; 00288 00289 /* Initialize the LPC Reply Semaphore */ 00290 KeInitializeSemaphore(&Thread->LpcReplySemaphore, 0, 1); 00291 00292 /* Initialize the list heads and locks */ 00293 InitializeListHead(&Thread->LpcReplyChain); 00294 InitializeListHead(&Thread->IrpList); 00295 InitializeListHead(&Thread->PostBlockList); 00296 InitializeListHead(&Thread->ActiveTimerListHead); 00297 KeInitializeSpinLock(&Thread->ActiveTimerListLock); 00298 00299 /* Acquire rundown protection */ 00300 if (!ExAcquireRundownProtection (&Process->RundownProtect)) 00301 { 00302 /* Fail */ 00303 ObDereferenceObject(Thread); 00304 return STATUS_PROCESS_IS_TERMINATING; 00305 } 00306 00307 /* Now let the kernel initialize the context */ 00308 if (ThreadContext) 00309 { 00310 /* User-mode Thread, create Teb */ 00311 Status = MmCreateTeb(Process, &Thread->Cid, InitialTeb, &TebBase); 00312 if (!NT_SUCCESS(Status)) 00313 { 00314 /* Failed to create the TEB. Release rundown and dereference */ 00315 ExReleaseRundownProtection(&Process->RundownProtect); 00316 ObDereferenceObject(Thread); 00317 return Status; 00318 } 00319 00320 /* Set the Start Addresses */ 00321 Thread->StartAddress = (PVOID)KeGetContextPc(ThreadContext); 00322 Thread->Win32StartAddress = (PVOID)KeGetContextReturnRegister(ThreadContext); 00323 00324 /* Let the kernel intialize the Thread */ 00325 Status = KeInitThread(&Thread->Tcb, 00326 NULL, 00327 PspUserThreadStartup, 00328 NULL, 00329 Thread->StartAddress, 00330 ThreadContext, 00331 TebBase, 00332 &Process->Pcb); 00333 } 00334 else 00335 { 00336 /* System Thread */ 00337 Thread->StartAddress = StartRoutine; 00338 PspSetCrossThreadFlag(Thread, CT_SYSTEM_THREAD_BIT); 00339 00340 /* Let the kernel intialize the Thread */ 00341 Status = KeInitThread(&Thread->Tcb, 00342 NULL, 00343 PspSystemThreadStartup, 00344 StartRoutine, 00345 StartContext, 00346 NULL, 00347 NULL, 00348 &Process->Pcb); 00349 } 00350 00351 /* Check if we failed */ 00352 if (!NT_SUCCESS(Status)) 00353 { 00354 /* Delete the TEB if we had done */ 00355 if (TebBase) MmDeleteTeb(Process, TebBase); 00356 00357 /* Release rundown and dereference */ 00358 ExReleaseRundownProtection(&Process->RundownProtect); 00359 ObDereferenceObject(Thread); 00360 return Status; 00361 } 00362 00363 /* Lock the process */ 00364 KeEnterCriticalRegion(); 00365 ExAcquirePushLockExclusive(&Process->ProcessLock); 00366 00367 /* Make sure the proces didn't just die on us */ 00368 if (Process->ProcessDelete) goto Quickie; 00369 00370 /* Check if the thread was ours, terminated and it was user mode */ 00371 if ((Thread->Terminated) && 00372 (ThreadContext) && 00373 (Thread->ThreadsProcess == Process)) 00374 { 00375 /* Cleanup, we don't want to start it up and context switch */ 00376 goto Quickie; 00377 } 00378 00379 /* 00380 * Insert the Thread into the Process's Thread List 00381 * Note, this is the ETHREAD Thread List. It is removed in 00382 * ps/kill.c!PspExitThread. 00383 */ 00384 InsertTailList(&Process->ThreadListHead, &Thread->ThreadListEntry); 00385 Process->ActiveThreads++; 00386 00387 /* Start the thread */ 00388 KeStartThread(&Thread->Tcb); 00389 00390 /* Release the process lock */ 00391 ExReleasePushLockExclusive(&Process->ProcessLock); 00392 KeLeaveCriticalRegion(); 00393 00394 /* Release rundown */ 00395 ExReleaseRundownProtection(&Process->RundownProtect); 00396 00397 /* Notify WMI */ 00398 //WmiTraceProcess(Process, TRUE); 00399 //WmiTraceThread(Thread, InitialTeb, TRUE); 00400 00401 /* Notify Thread Creation */ 00402 PspRunCreateThreadNotifyRoutines(Thread, TRUE); 00403 00404 /* Reference ourselves as a keep-alive */ 00405 ObReferenceObjectEx(Thread, 2); 00406 00407 /* Suspend the Thread if we have to */ 00408 if (CreateSuspended) KeSuspendThread(&Thread->Tcb); 00409 00410 /* Check if we were already terminated */ 00411 if (Thread->Terminated) KeForceResumeThread(&Thread->Tcb); 00412 00413 /* Create an access state */ 00414 Status = SeCreateAccessStateEx(NULL, 00415 ThreadContext ? 00416 PsGetCurrentProcess() : Process, 00417 &LocalAccessState, 00418 &AuxData, 00419 DesiredAccess, 00420 &PsThreadType->TypeInfo.GenericMapping); 00421 if (!NT_SUCCESS(Status)) 00422 { 00423 /* Access state failed, thread is dead */ 00424 PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT); 00425 00426 /* If we were suspended, wake it up */ 00427 if (CreateSuspended) KeResumeThread(&Thread->Tcb); 00428 00429 /* Dispatch thread */ 00430 KeReadyThread(&Thread->Tcb); 00431 00432 /* Dereference completely to kill it */ 00433 ObDereferenceObjectEx(Thread, 2); 00434 return Status; 00435 } 00436 00437 /* Insert the Thread into the Object Manager */ 00438 Status = ObInsertObject(Thread, 00439 AccessState, 00440 DesiredAccess, 00441 0, 00442 NULL, 00443 &hThread); 00444 00445 /* Delete the access state if we had one */ 00446 if (AccessState) SeDeleteAccessState(AccessState); 00447 00448 /* Check for success */ 00449 if (NT_SUCCESS(Status)) 00450 { 00451 /* Wrap in SEH to protect against bad user-mode pointers */ 00452 _SEH2_TRY 00453 { 00454 /* Return Cid and Handle */ 00455 if (ClientId) *ClientId = Thread->Cid; 00456 *ThreadHandle = hThread; 00457 } 00458 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 00459 { 00460 /* Thread insertion failed, thread is dead */ 00461 PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT); 00462 00463 /* If we were suspended, wake it up */ 00464 if (CreateSuspended) KeResumeThread(&Thread->Tcb); 00465 00466 /* Dispatch thread */ 00467 KeReadyThread(&Thread->Tcb); 00468 00469 /* Dereference it, leaving only the keep-alive */ 00470 ObDereferenceObject(Thread); 00471 00472 /* Close its handle, killing it */ 00473 ObCloseHandle(ThreadHandle, PreviousMode); 00474 00475 /* Return the exception code */ 00476 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 00477 } 00478 _SEH2_END; 00479 } 00480 else 00481 { 00482 /* Thread insertion failed, thread is dead */ 00483 PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT); 00484 00485 /* If we were suspended, wake it up */ 00486 if (CreateSuspended) KeResumeThread(&Thread->Tcb); 00487 } 00488 00489 /* Get the create time */ 00490 KeQuerySystemTime(&Thread->CreateTime); 00491 ASSERT(!(Thread->CreateTime.HighPart & 0xF0000000)); 00492 00493 /* Make sure the thread isn't dead */ 00494 if (!Thread->DeadThread) 00495 { 00496 /* Get the thread's SD */ 00497 Status = ObGetObjectSecurity(Thread, 00498 &SecurityDescriptor, 00499 &SdAllocated); 00500 if (!NT_SUCCESS(Status)) 00501 { 00502 /* Thread insertion failed, thread is dead */ 00503 PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT); 00504 00505 /* If we were suspended, wake it up */ 00506 if (CreateSuspended) KeResumeThread(&Thread->Tcb); 00507 00508 /* Dispatch thread */ 00509 KeReadyThread(&Thread->Tcb); 00510 00511 /* Dereference it, leaving only the keep-alive */ 00512 ObDereferenceObject(Thread); 00513 00514 /* Close its handle, killing it */ 00515 ObCloseHandle(ThreadHandle, PreviousMode); 00516 return Status; 00517 } 00518 00519 /* Create the subject context */ 00520 SubjectContext.ProcessAuditId = Process; 00521 SubjectContext.PrimaryToken = PsReferencePrimaryToken(Process); 00522 SubjectContext.ClientToken = NULL; 00523 00524 /* Do the access check */ 00525 Result = SeAccessCheck(SecurityDescriptor, 00526 &SubjectContext, 00527 FALSE, 00528 MAXIMUM_ALLOWED, 00529 0, 00530 NULL, 00531 &PsThreadType->TypeInfo.GenericMapping, 00532 PreviousMode, 00533 &Thread->GrantedAccess, 00534 &AccessStatus); 00535 00536 /* Dereference the token and let go the SD */ 00537 ObFastDereferenceObject(&Process->Token, 00538 SubjectContext.PrimaryToken); 00539 ObReleaseObjectSecurity(SecurityDescriptor, SdAllocated); 00540 00541 /* Remove access if it failed */ 00542 if (!Result) Process->GrantedAccess = 0; 00543 00544 /* Set least some minimum access */ 00545 Thread->GrantedAccess |= (THREAD_TERMINATE | 00546 THREAD_SET_INFORMATION | 00547 THREAD_QUERY_INFORMATION); 00548 } 00549 else 00550 { 00551 /* Set the thread access mask to maximum */ 00552 Thread->GrantedAccess = THREAD_ALL_ACCESS; 00553 } 00554 00555 /* Dispatch thread */ 00556 KeReadyThread(&Thread->Tcb); 00557 00558 /* Dereference it, leaving only the keep-alive */ 00559 ObDereferenceObject(Thread); 00560 00561 /* Return */ 00562 return Status; 00563 00564 /* Most annoying failure case ever, where we undo almost all manually */ 00565 Quickie: 00566 /* When we get here, the process is locked, unlock it */ 00567 ExReleasePushLockExclusive(&Process->ProcessLock); 00568 KeLeaveCriticalRegion(); 00569 00570 /* Uninitailize it */ 00571 KeUninitThread(&Thread->Tcb); 00572 00573 /* If we had a TEB, delete it */ 00574 if (TebBase) MmDeleteTeb(Process, TebBase); 00575 00576 /* Release rundown protection, which we also hold */ 00577 ExReleaseRundownProtection(&Process->RundownProtect); 00578 00579 /* Dereference the thread and return failure */ 00580 ObDereferenceObject(Thread); 00581 return STATUS_PROCESS_IS_TERMINATING; 00582 } 00583 00584 /* PUBLIC FUNCTIONS **********************************************************/ 00585 00586 /* 00587 * @implemented 00588 */ 00589 NTSTATUS 00590 NTAPI 00591 PsCreateSystemThread(OUT PHANDLE ThreadHandle, 00592 IN ACCESS_MASK DesiredAccess, 00593 IN POBJECT_ATTRIBUTES ObjectAttributes, 00594 IN HANDLE ProcessHandle, 00595 IN PCLIENT_ID ClientId, 00596 IN PKSTART_ROUTINE StartRoutine, 00597 IN PVOID StartContext) 00598 { 00599 PEPROCESS TargetProcess = NULL; 00600 HANDLE Handle = ProcessHandle; 00601 PAGED_CODE(); 00602 PSTRACE(PS_THREAD_DEBUG, 00603 "ProcessHandle: %p StartRoutine: %p StartContext: %p\n", 00604 ProcessHandle, StartRoutine, StartContext); 00605 00606 /* Check if we have a handle. If not, use the System Process */ 00607 if (!ProcessHandle) 00608 { 00609 Handle = NULL; 00610 TargetProcess = PsInitialSystemProcess; 00611 } 00612 00613 /* Call the shared function */ 00614 return PspCreateThread(ThreadHandle, 00615 DesiredAccess, 00616 ObjectAttributes, 00617 Handle, 00618 TargetProcess, 00619 ClientId, 00620 NULL, 00621 NULL, 00622 FALSE, 00623 StartRoutine, 00624 StartContext); 00625 } 00626 00627 /* 00628 * @implemented 00629 */ 00630 NTSTATUS 00631 NTAPI 00632 PsLookupThreadByThreadId(IN HANDLE ThreadId, 00633 OUT PETHREAD *Thread) 00634 { 00635 PHANDLE_TABLE_ENTRY CidEntry; 00636 PETHREAD FoundThread; 00637 NTSTATUS Status = STATUS_INVALID_PARAMETER; 00638 PAGED_CODE(); 00639 PSTRACE(PS_THREAD_DEBUG, "ThreadId: %p\n", ThreadId); 00640 KeEnterCriticalRegion(); 00641 00642 /* Get the CID Handle Entry */ 00643 CidEntry = ExMapHandleToPointer(PspCidTable, ThreadId); 00644 if (CidEntry) 00645 { 00646 /* Get the Process */ 00647 FoundThread = CidEntry->Object; 00648 00649 /* Make sure it's really a process */ 00650 if (FoundThread->Tcb.Header.Type == ThreadObject) 00651 { 00652 /* Safe Reference and return it */ 00653 if (ObReferenceObjectSafe(FoundThread)) 00654 { 00655 *Thread = FoundThread; 00656 Status = STATUS_SUCCESS; 00657 } 00658 } 00659 00660 /* Unlock the Entry */ 00661 ExUnlockHandleTableEntry(PspCidTable, CidEntry); 00662 } 00663 00664 /* Return to caller */ 00665 KeLeaveCriticalRegion(); 00666 return Status; 00667 } 00668 00669 /* 00670 * @implemented 00671 */ 00672 HANDLE 00673 NTAPI 00674 PsGetCurrentThreadId(VOID) 00675 { 00676 return PsGetCurrentThread()->Cid.UniqueThread; 00677 } 00678 00679 /* 00680 * @implemented 00681 */ 00682 ULONG 00683 NTAPI 00684 PsGetThreadFreezeCount(IN PETHREAD Thread) 00685 { 00686 return Thread->Tcb.FreezeCount; 00687 } 00688 00689 /* 00690 * @implemented 00691 */ 00692 BOOLEAN 00693 NTAPI 00694 PsGetThreadHardErrorsAreDisabled(IN PETHREAD Thread) 00695 { 00696 return Thread->HardErrorsAreDisabled ? TRUE : FALSE; 00697 } 00698 00699 /* 00700 * @implemented 00701 */ 00702 HANDLE 00703 NTAPI 00704 PsGetThreadId(IN PETHREAD Thread) 00705 { 00706 return Thread->Cid.UniqueThread; 00707 } 00708 00709 /* 00710 * @implemented 00711 */ 00712 PEPROCESS 00713 NTAPI 00714 PsGetThreadProcess(IN PETHREAD Thread) 00715 { 00716 return Thread->ThreadsProcess; 00717 } 00718 00719 /* 00720 * @implemented 00721 */ 00722 HANDLE 00723 NTAPI 00724 PsGetThreadProcessId(IN PETHREAD Thread) 00725 { 00726 return Thread->Cid.UniqueProcess; 00727 } 00728 00729 /* 00730 * @implemented 00731 */ 00732 HANDLE 00733 NTAPI 00734 PsGetThreadSessionId(IN PETHREAD Thread) 00735 { 00736 return (HANDLE)Thread->ThreadsProcess->Session; 00737 } 00738 00739 /* 00740 * @implemented 00741 */ 00742 PTEB 00743 NTAPI 00744 PsGetThreadTeb(IN PETHREAD Thread) 00745 { 00746 return Thread->Tcb.Teb; 00747 } 00748 00749 /* 00750 * @implemented 00751 */ 00752 PVOID 00753 NTAPI 00754 PsGetThreadWin32Thread(IN PETHREAD Thread) 00755 { 00756 return Thread->Tcb.Win32Thread; 00757 } 00758 00759 /* 00760 * @implemented 00761 */ 00762 KPROCESSOR_MODE 00763 NTAPI 00764 PsGetCurrentThreadPreviousMode(VOID) 00765 { 00766 return (KPROCESSOR_MODE)PsGetCurrentThread()->Tcb.PreviousMode; 00767 } 00768 00769 /* 00770 * @implemented 00771 */ 00772 PVOID 00773 NTAPI 00774 PsGetCurrentThreadStackBase(VOID) 00775 { 00776 return PsGetCurrentThread()->Tcb.StackBase; 00777 } 00778 00779 /* 00780 * @implemented 00781 */ 00782 PVOID 00783 NTAPI 00784 PsGetCurrentThreadStackLimit(VOID) 00785 { 00786 return (PVOID)PsGetCurrentThread()->Tcb.StackLimit; 00787 } 00788 00789 /* 00790 * @implemented 00791 */ 00792 BOOLEAN 00793 NTAPI 00794 PsIsThreadTerminating(IN PETHREAD Thread) 00795 { 00796 return Thread->Terminated ? TRUE : FALSE; 00797 } 00798 00799 /* 00800 * @implemented 00801 */ 00802 BOOLEAN 00803 NTAPI 00804 PsIsSystemThread(IN PETHREAD Thread) 00805 { 00806 return Thread->SystemThread ? TRUE: FALSE; 00807 } 00808 00809 /* 00810 * @implemented 00811 */ 00812 BOOLEAN 00813 NTAPI 00814 PsIsThreadImpersonating(IN PETHREAD Thread) 00815 { 00816 return Thread->ActiveImpersonationInfo ? TRUE : FALSE; 00817 } 00818 00819 /* 00820 * @implemented 00821 */ 00822 VOID 00823 NTAPI 00824 PsSetThreadHardErrorsAreDisabled(IN PETHREAD Thread, 00825 IN BOOLEAN HardErrorsAreDisabled) 00826 { 00827 Thread->HardErrorsAreDisabled = HardErrorsAreDisabled; 00828 } 00829 00830 /* 00831 * @implemented 00832 */ 00833 PVOID 00834 NTAPI 00835 PsGetCurrentThreadWin32Thread(VOID) 00836 { 00837 return PsGetCurrentThread()->Tcb.Win32Thread; 00838 } 00839 00840 /* 00841 * @implemented 00842 */ 00843 VOID 00844 NTAPI 00845 PsSetThreadWin32Thread(IN PETHREAD Thread, 00846 IN PVOID Win32Thread) 00847 { 00848 Thread->Tcb.Win32Thread = Win32Thread; 00849 } 00850 00851 NTSTATUS 00852 NTAPI 00853 NtCreateThread(OUT PHANDLE ThreadHandle, 00854 IN ACCESS_MASK DesiredAccess, 00855 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, 00856 IN HANDLE ProcessHandle, 00857 OUT PCLIENT_ID ClientId, 00858 IN PCONTEXT ThreadContext, 00859 IN PINITIAL_TEB InitialTeb, 00860 IN BOOLEAN CreateSuspended) 00861 { 00862 INITIAL_TEB SafeInitialTeb; 00863 PAGED_CODE(); 00864 PSTRACE(PS_THREAD_DEBUG, 00865 "ProcessHandle: %p Context: %p\n", ProcessHandle, ThreadContext); 00866 00867 /* Check if this was from user-mode */ 00868 if (KeGetPreviousMode() != KernelMode) 00869 { 00870 /* Make sure that we got a context */ 00871 if (!ThreadContext) return STATUS_INVALID_PARAMETER; 00872 00873 /* Protect checks */ 00874 _SEH2_TRY 00875 { 00876 /* Make sure the handle pointer we got is valid */ 00877 ProbeForWriteHandle(ThreadHandle); 00878 00879 /* Check if the caller wants a client id */ 00880 if (ClientId) 00881 { 00882 /* Make sure we can write to it */ 00883 ProbeForWrite(ClientId, sizeof(CLIENT_ID), sizeof(ULONG)); 00884 } 00885 00886 /* Make sure that the entire context is readable */ 00887 ProbeForRead(ThreadContext, sizeof(CONTEXT), sizeof(ULONG)); 00888 00889 /* Check the Initial TEB */ 00890 ProbeForRead(InitialTeb, sizeof(INITIAL_TEB), sizeof(ULONG)); 00891 SafeInitialTeb = *InitialTeb; 00892 } 00893 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 00894 { 00895 /* Return the exception code */ 00896 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 00897 } 00898 _SEH2_END; 00899 } 00900 else 00901 { 00902 /* Use the Initial TEB as is */ 00903 SafeInitialTeb = *InitialTeb; 00904 } 00905 00906 /* Call the shared function */ 00907 return PspCreateThread(ThreadHandle, 00908 DesiredAccess, 00909 ObjectAttributes, 00910 ProcessHandle, 00911 NULL, 00912 ClientId, 00913 ThreadContext, 00914 &SafeInitialTeb, 00915 CreateSuspended, 00916 NULL, 00917 NULL); 00918 } 00919 00920 /* 00921 * @implemented 00922 */ 00923 NTSTATUS 00924 NTAPI 00925 NtOpenThread(OUT PHANDLE ThreadHandle, 00926 IN ACCESS_MASK DesiredAccess, 00927 IN POBJECT_ATTRIBUTES ObjectAttributes, 00928 IN PCLIENT_ID ClientId OPTIONAL) 00929 { 00930 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); 00931 CLIENT_ID SafeClientId; 00932 ULONG Attributes = 0; 00933 HANDLE hThread = NULL; 00934 NTSTATUS Status; 00935 PETHREAD Thread; 00936 BOOLEAN HasObjectName = FALSE; 00937 ACCESS_STATE AccessState; 00938 AUX_ACCESS_DATA AuxData; 00939 PAGED_CODE(); 00940 PSTRACE(PS_THREAD_DEBUG, 00941 "ClientId: %p ObjectAttributes: %p\n", ClientId, ObjectAttributes); 00942 00943 /* Check if we were called from user mode */ 00944 if (PreviousMode != KernelMode) 00945 { 00946 /* Enter SEH for probing */ 00947 _SEH2_TRY 00948 { 00949 /* Probe the thread handle */ 00950 ProbeForWriteHandle(ThreadHandle); 00951 00952 /* Check for a CID structure */ 00953 if (ClientId) 00954 { 00955 /* Probe and capture it */ 00956 ProbeForRead(ClientId, sizeof(CLIENT_ID), sizeof(ULONG)); 00957 SafeClientId = *ClientId; 00958 ClientId = &SafeClientId; 00959 } 00960 00961 /* 00962 * Just probe the object attributes structure, don't capture it 00963 * completely. This is done later if necessary 00964 */ 00965 ProbeForRead(ObjectAttributes, 00966 sizeof(OBJECT_ATTRIBUTES), 00967 sizeof(ULONG)); 00968 HasObjectName = (ObjectAttributes->ObjectName != NULL); 00969 Attributes = ObjectAttributes->Attributes; 00970 } 00971 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 00972 { 00973 /* Return the exception code */ 00974 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 00975 } 00976 _SEH2_END; 00977 } 00978 else 00979 { 00980 /* Otherwise just get the data directly */ 00981 HasObjectName = (ObjectAttributes->ObjectName != NULL); 00982 Attributes = ObjectAttributes->Attributes; 00983 } 00984 00985 /* Can't pass both, fail */ 00986 if ((HasObjectName) && (ClientId)) return STATUS_INVALID_PARAMETER_MIX; 00987 00988 /* Create an access state */ 00989 Status = SeCreateAccessState(&AccessState, 00990 &AuxData, 00991 DesiredAccess, 00992 &PsProcessType->TypeInfo.GenericMapping); 00993 if (!NT_SUCCESS(Status)) return Status; 00994 00995 /* Check if this is a debugger */ 00996 if (SeSinglePrivilegeCheck(SeDebugPrivilege, PreviousMode)) 00997 { 00998 /* Did he want full access? */ 00999 if (AccessState.RemainingDesiredAccess & MAXIMUM_ALLOWED) 01000 { 01001 /* Give it to him */ 01002 AccessState.PreviouslyGrantedAccess |= THREAD_ALL_ACCESS; 01003 } 01004 else 01005 { 01006 /* Otherwise just give every other access he could want */ 01007 AccessState.PreviouslyGrantedAccess |= 01008 AccessState.RemainingDesiredAccess; 01009 } 01010 01011 /* The caller desires nothing else now */ 01012 AccessState.RemainingDesiredAccess = 0; 01013 } 01014 01015 /* Open by name if one was given */ 01016 if (HasObjectName) 01017 { 01018 /* Open it */ 01019 Status = ObOpenObjectByName(ObjectAttributes, 01020 PsThreadType, 01021 PreviousMode, 01022 &AccessState, 01023 0, 01024 NULL, 01025 &hThread); 01026 01027 /* Get rid of the access state */ 01028 SeDeleteAccessState(&AccessState); 01029 } 01030 else if (ClientId) 01031 { 01032 /* Open by Thread ID */ 01033 if (ClientId->UniqueProcess) 01034 { 01035 /* Get the Process */ 01036 Status = PsLookupProcessThreadByCid(ClientId, NULL, &Thread); 01037 } 01038 else 01039 { 01040 /* Get the Process */ 01041 Status = PsLookupThreadByThreadId(ClientId->UniqueThread, &Thread); 01042 } 01043 01044 /* Check if we didn't find anything */ 01045 if (!NT_SUCCESS(Status)) 01046 { 01047 /* Get rid of the access state and return */ 01048 SeDeleteAccessState(&AccessState); 01049 return Status; 01050 } 01051 01052 /* Open the Thread Object */ 01053 Status = ObOpenObjectByPointer(Thread, 01054 Attributes, 01055 &AccessState, 01056 0, 01057 PsThreadType, 01058 PreviousMode, 01059 &hThread); 01060 01061 /* Delete the access state and dereference the thread */ 01062 SeDeleteAccessState(&AccessState); 01063 ObDereferenceObject(Thread); 01064 } 01065 else 01066 { 01067 /* Neither an object name nor a client id was passed */ 01068 return STATUS_INVALID_PARAMETER_MIX; 01069 } 01070 01071 /* Check for success */ 01072 if (NT_SUCCESS(Status)) 01073 { 01074 /* Protect against bad user-mode pointers */ 01075 _SEH2_TRY 01076 { 01077 /* Write back the handle */ 01078 *ThreadHandle = hThread; 01079 } 01080 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 01081 { 01082 /* Get the exception code */ 01083 Status = _SEH2_GetExceptionCode(); 01084 } 01085 _SEH2_END; 01086 } 01087 01088 /* Return status */ 01089 return Status; 01090 } 01091 01092 /* EOF */ Generated on Sun May 27 2012 04:24:32 for ReactOS by
1.7.6.1
|