ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

thread.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.