NTSTATUS PsLookupProcessByProcessId( __in HANDLE ProcessId, __deref_out PEPROCESS *Process ) /*++ Routine Description: This function accepts the process id of a process and returns a referenced pointer to the process. Arguments: ProcessId - Specifies the Process ID of the process. Process - Returns a referenced pointer to the process specified by the process id. Return Value: STATUS_SUCCESS - A process was located based on the contents of the process id. STATUS_INVALID_PARAMETER - The process was not found. --*/ { PHANDLE_TABLE_ENTRY CidEntry; PEPROCESS lProcess; PETHREAD CurrentThread; NTSTATUS Status; PAGED_CODE(); Status = STATUS_INVALID_PARAMETER; CurrentThread = PsGetCurrentThread (); KeEnterCriticalRegionThread (&CurrentThread->Tcb); CidEntry = ExMapHandleToPointer(PspCidTable, ProcessId); if (CidEntry != NULL) { lProcess = (PEPROCESS)CidEntry->Object; if (lProcess->Pcb.Header.Type == ProcessObject && lProcess->GrantedAccess != 0) { if (ObReferenceObjectSafe(lProcess)) { *Process = lProcess; Status = STATUS_SUCCESS; } } ExUnlockHandleTableEntry(PspCidTable, CidEntry); } KeLeaveCriticalRegionThread (&CurrentThread->Tcb); return Status; }
NTSTATUS MmPrefetchPagesIntoLockedMdl ( IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN SIZE_T Length, OUT PMDL *MdlOut ) /*++ Routine Description: This routine fills an MDL with pages described by the file object's offset and length. This routine is for cache manager usage only. Arguments: FileObject - Supplies a pointer to the file object for a file which was opened with NO_INTERMEDIATE_BUFFERING clear, i.e., for which CcInitializeCacheMap was called by the file system. FileOffset - Supplies the byte offset in the file for the desired data. Length - Supplies the length of the desired data in bytes. MdlOut - On output it returns a pointer to an Mdl describing the desired data. Return Value: NTSTATUS. Environment: Kernel mode. PASSIVE_LEVEL. --*/ { MI_READ_INFO MiReadInfo; NTSTATUS status; LOGICAL ApcNeeded; PETHREAD CurrentThread; ASSERT (KeGetCurrentIrql() == PASSIVE_LEVEL); RtlZeroMemory (&MiReadInfo, sizeof(MiReadInfo)); MiReadInfo.FileObject = FileObject; MiReadInfo.FileOffset = *FileOffset; MiReadInfo.LengthInBytes = Length; // // Prepare for the impending read : allocate MDLs, inpage blocks, // reference count subsections, etc. // status = MiCcPrepareReadInfo (&MiReadInfo); if (!NT_SUCCESS (status)) { MiCcReleasePrefetchResources (&MiReadInfo, status); return status; } ASSERT (MiReadInfo.InPageSupport != NULL); // // APCs must be disabled once we put a page in transition. Otherwise // a thread suspend will stop us from issuing the I/O - this will hang // any other threads that need the same page. // CurrentThread = PsGetCurrentThread(); ApcNeeded = FALSE; KeEnterCriticalRegionThread (&CurrentThread->Tcb); // // The nested fault count protects this thread from deadlocks where a // special kernel APC fires and references the same user page(s) we are // putting in transition. // KeEnterGuardedRegionThread (&CurrentThread->Tcb); ASSERT (CurrentThread->ActiveFaultCount == 0); CurrentThread->ActiveFaultCount += 1; KeLeaveGuardedRegionThread (&CurrentThread->Tcb); // // Allocate physical memory, lock down all the pages and issue any // I/O that may be needed. When MiCcPutPagesInTransition returns // STATUS_SUCCESS or STATUS_ISSUE_PAGING_IO, it guarantees that the // ApiMdl contains reference-counted (locked-down) pages. // status = MiCcPutPagesInTransition (&MiReadInfo); if (NT_SUCCESS (status)) { // // No I/O was issued because all the pages were already resident and // have now been locked down. // ASSERT (MiReadInfo.ApiMdl != NULL); } else if (status == STATUS_ISSUE_PAGING_IO) { // // Wait for the I/O to complete. Note APCs must remain disabled. // ASSERT (MiReadInfo.InPageSupport != NULL); status = MiCcCompletePrefetchIos (&MiReadInfo); } else { // // Some error occurred (like insufficient memory, etc) so fail // the request by falling through. // } // // Release acquired resources like pool, subsections, etc. // MiCcReleasePrefetchResources (&MiReadInfo, status); // // Only now that the I/O have been completed (not just issued) can // APCs be re-enabled. This prevents a user-issued suspend APC from // keeping a shared page in transition forever. // KeEnterGuardedRegionThread (&CurrentThread->Tcb); ASSERT (CurrentThread->ActiveFaultCount == 1); CurrentThread->ActiveFaultCount -= 1; if (CurrentThread->ApcNeeded == 1) { ApcNeeded = TRUE; CurrentThread->ApcNeeded = 0; } KeLeaveGuardedRegionThread (&CurrentThread->Tcb); KeLeaveCriticalRegionThread (&CurrentThread->Tcb); ASSERT (KeGetCurrentIrql() == PASSIVE_LEVEL); ASSERT (CurrentThread->ActiveFaultCount == 0); ASSERT (CurrentThread->ApcNeeded == 0); if (ApcNeeded == TRUE) { IoRetryIrpCompletions (); } *MdlOut = MiReadInfo.ApiMdl; return status; }
NTSTATUS PsLookupProcessThreadByCid( __in PCLIENT_ID Cid, __deref_opt_out PEPROCESS *Process, __deref_out PETHREAD *Thread ) /*++ Routine Description: This function accepts The Client ID of a thread, and returns a referenced pointer to the thread, and possibly a referenced pointer to the process. Arguments: Cid - Specifies the Client ID of the thread. Process - If specified, returns a referenced pointer to the process specified in the Cid. Thread - Returns a referenced pointer to the thread specified in the Cid. Return Value: STATUS_SUCCESS - A process and thread were located based on the contents of the Cid. STATUS_INVALID_CID - The specified Cid is invalid. --*/ { PHANDLE_TABLE_ENTRY CidEntry; PETHREAD lThread; PETHREAD CurrentThread; PEPROCESS lProcess; NTSTATUS Status; PAGED_CODE(); lThread = NULL; CurrentThread = PsGetCurrentThread (); KeEnterCriticalRegionThread (&CurrentThread->Tcb); CidEntry = ExMapHandleToPointer(PspCidTable, Cid->UniqueThread); if (CidEntry != NULL) { lThread = (PETHREAD)CidEntry->Object; if (!ObReferenceObjectSafe (lThread)) { lThread = NULL; } ExUnlockHandleTableEntry(PspCidTable, CidEntry); } KeLeaveCriticalRegionThread (&CurrentThread->Tcb); Status = STATUS_INVALID_CID; if (lThread != NULL) { // // This could be a thread or a process. Check its a thread. // if (lThread->Tcb.Header.Type != ThreadObject || lThread->Cid.UniqueProcess != Cid->UniqueProcess || lThread->GrantedAccess == 0) { ObDereferenceObject (lThread); } else { *Thread = lThread; if (ARGUMENT_PRESENT (Process)) { lProcess = THREAD_TO_PROCESS (lThread); *Process = lProcess; // // Since the thread holds a reference to the process this reference does not have to // be protected. // ObReferenceObject (lProcess); } Status = STATUS_SUCCESS; } } return Status; }
NTSTATUS PsLookupThreadByThreadId( __in HANDLE ThreadId, __deref_out PETHREAD *Thread ) /*++ Routine Description: This function accepts the thread id of a thread and returns a referenced pointer to the thread. Arguments: ThreadId - Specifies the Thread ID of the thread. Thread - Returns a referenced pointer to the thread specified by the thread id. Return Value: STATUS_SUCCESS - A thread was located based on the contents of the thread id. STATUS_INVALID_PARAMETER - The thread was not found. --*/ { PHANDLE_TABLE_ENTRY CidEntry; PETHREAD lThread; PETHREAD CurrentThread; NTSTATUS Status; PAGED_CODE(); Status = STATUS_INVALID_PARAMETER; CurrentThread = PsGetCurrentThread (); KeEnterCriticalRegionThread (&CurrentThread->Tcb); CidEntry = ExMapHandleToPointer(PspCidTable, ThreadId); if (CidEntry != NULL) { lThread = (PETHREAD)CidEntry->Object; if (lThread->Tcb.Header.Type == ThreadObject && lThread->GrantedAccess) { if (ObReferenceObjectSafe(lThread)) { *Thread = lThread; Status = STATUS_SUCCESS; } } ExUnlockHandleTableEntry(PspCidTable, CidEntry); } KeLeaveCriticalRegionThread (&CurrentThread->Tcb); return Status; }
PEX_CALLBACK_ROUTINE_BLOCK ExReferenceCallBackBlock ( IN OUT PEX_CALLBACK CallBack ) /*++ Routine Description: This function takes a reference on the call back block inside the callback structure. Arguments: CallBack - Call back to obtain the call back block from Return Value: PEX_CALLBACK_ROUTINE_BLOCK - Referenced structure or NULL if these wasn't one --*/ { EX_FAST_REF OldRef; PEX_CALLBACK_ROUTINE_BLOCK CallBackBlock; // // Get a reference to the callback block if we can. // OldRef = ExFastReference (&CallBack->RoutineBlock); // // If there is no callback then return // if (ExFastRefObjectNull (OldRef)) { return NULL; } // // If we didn't get a reference then use a lock to get one. // if (!ExFastRefCanBeReferenced (OldRef)) { PKTHREAD CurrentThread; CurrentThread = KeGetCurrentThread (); KeEnterCriticalRegionThread (CurrentThread); ExAcquirePushLockExclusive (&ExpCallBackFlush); CallBackBlock = ExFastRefGetObject (CallBack->RoutineBlock); if (CallBackBlock && !ExAcquireRundownProtection (&CallBackBlock->RundownProtect)) { CallBackBlock = NULL; } ExReleasePushLockExclusive (&ExpCallBackFlush); KeLeaveCriticalRegionThread (CurrentThread); if (CallBackBlock == NULL) { return NULL; } } else { CallBackBlock = ExFastRefGetObject (OldRef); // // If we just removed the last reference then attempt fix it up. // if (ExFastRefIsLastReference (OldRef) && !ExpCallBackReturnRefs) { ULONG RefsToAdd; RefsToAdd = ExFastRefGetAdditionalReferenceCount (); // // If we can't add the references then just give up // if (ExAcquireRundownProtectionEx (&CallBackBlock->RundownProtect, RefsToAdd)) { // // Repopulate the cached refs. If this fails we just give them back. // if (!ExFastRefAddAdditionalReferenceCounts (&CallBack->RoutineBlock, CallBackBlock, RefsToAdd)) { ExReleaseRundownProtectionEx (&CallBackBlock->RundownProtect, RefsToAdd); } } } } return CallBackBlock; }
BOOLEAN ExCompareExchangeCallBack ( IN OUT PEX_CALLBACK CallBack, IN PEX_CALLBACK_ROUTINE_BLOCK NewBlock, IN PEX_CALLBACK_ROUTINE_BLOCK OldBlock ) /*++ Routine Description: This function assigns, removes or swaps a low overhead callback function. Arguments: CallBack - Callback structure to be modified NewBlock - New block to be installed in the callback OldBlock - The old block that must be there now to be replaced Return Value: BOOLEAN - TRUE: The swap occured, FALSE: The swap failed --*/ { EX_FAST_REF OldRef; PEX_CALLBACK_ROUTINE_BLOCK ReplacedBlock; if (NewBlock != NULL) { // // Add the additional references to the routine block // if (!ExAcquireRundownProtectionEx (&NewBlock->RundownProtect, ExFastRefGetAdditionalReferenceCount () + 1)) { ASSERTMSG ("Callback block is already undergoing rundown", FALSE); return FALSE; } } // // Attempt to replace the existing object and balance all the reference counts // OldRef = ExFastRefCompareSwapObject (&CallBack->RoutineBlock, NewBlock, OldBlock); ReplacedBlock = ExFastRefGetObject (OldRef); // // See if the swap occured. If it didn't undo the original references we added. // If it did then release remaining references on the original // if (ReplacedBlock == OldBlock) { PKTHREAD CurrentThread; // // We need to flush out any slow referencers at this point. We do this by // acquiring and releasing a lock. // if (ReplacedBlock != NULL) { CurrentThread = KeGetCurrentThread (); KeEnterCriticalRegionThread (CurrentThread); ExAcquireReleasePushLockExclusive (&ExpCallBackFlush); KeLeaveCriticalRegionThread (CurrentThread); ExReleaseRundownProtectionEx (&ReplacedBlock->RundownProtect, ExFastRefGetUnusedReferences (OldRef) + 1); } return TRUE; } else { // // The swap failed. Remove the addition references if we had added any. // if (NewBlock != NULL) { ExReleaseRundownProtectionEx (&NewBlock->RundownProtect, ExFastRefGetAdditionalReferenceCount () + 1); } return FALSE; } }