(74)分析 APC 插入过程 —— KeInsertQueueApc , KiInsertQueueApc
生活随笔
收集整理的這篇文章主要介紹了
(74)分析 APC 插入过程 —— KeInsertQueueApc , KiInsertQueueApc
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
一、KeInsertQueueApc(調用 KiInsertQueueApc)
BOOLEAN KeInsertQueueApc (IN PRKAPC Apc,IN PVOID SystemArgument1,IN PVOID SystemArgument2,IN KPRIORITY Increment)/*++Routine Description:This function inserts an APC object into the APC queue specifed by thethread and processor mode fields of the APC object. If the APC objectis already in an APC queue or APC queuing is disabled, then no operationis performed. Otherwise the APC object is inserted in the specified queueand appropriate scheduling decisions are made.插入 APC 到指定線程的APC隊列,用戶態和內核態分別插入對應的 APC 隊列。如果 APC 對象已經在 APC 隊列或者 APC 隊列被禁用(例如線程正在退出),則不執行操作。否則插入 APC 對象并調用相應的函數。Arguments:Apc - Supplies a pointer to a control object of type APC.APC 結構SystemArgument1, SystemArgument2 - Supply a set of two arguments thatcontain untyped data provided by the executive.傳給 APC 函數的參數。Increment - Supplies the priority increment that is to be applied ifqueuing the APC causes a thread wait to be satisfied.線程優先級增量Return Value:If the APC object is already in an APC queue or APC queuing is disabled,then a value of FALSE is returned. Otherwise a value of TRUE is returned.--*/{BOOLEAN Inserted;KLOCK_QUEUE_HANDLE LockHandle;KIRQL OldIrql;PRKTHREAD Thread;ASSERT_APC(Apc);ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);//// Raise IRQL to SYNCH_LEVEL, acquire the thread APC queue lock, and lock// the dispatcher database.// 提升 IRQL 等級,申請 APC 鎖,鎖 dispatcher databaseThread = Apc->Thread;KeAcquireInStackQueuedSpinLockRaiseToSynch(&Thread->ApcQueueLock, &LockHandle);KiLockDispatcherDatabaseAtSynchLevel();//// If APC queuing is disabled, then set inserted to FALSE. Else save// system parameter values in APC object, and attempt to queue APC.// 調用 KiInsertQueueApcif (Thread->ApcQueueable == FALSE) {Inserted = FALSE;} else {Apc->SystemArgument1 = SystemArgument1;Apc->SystemArgument2 = SystemArgument2;Inserted = KiInsertQueueApc(Apc, Increment);}//// Unlock the dispatcher database from SYNCH_LEVEL, unlock the thread APC// queue lock and lower IRQL to its previous value, and return whether the// APC was inserted.//KiUnlockDispatcherDatabaseFromSynchLevel();KeReleaseInStackQueuedSpinLock(&LockHandle);return Inserted; }二、KiInsertQueueApc
BOOLEAN FASTCALL KiInsertQueueApc (IN PKAPC Apc,IN KPRIORITY Increment)/*++Routine Description:This function inserts an APC object into a thread's APC queue. The addressof the thread object, the APC queue, and the type of APC are all derivedfrom the APC object. If the APC object is already in an APC queue, thenno opertion is performed and a function value of FALSE is returned. Elsethe APC is inserted in the specified APC queue, its inserted state is setto TRUE, and a function value of TRUE is returned. The APC will actuallybe delivered when proper enabling conditions exist.N.B. The thread APC queue lock and the dispatcher database lock must bothbe held when this routine is called.Arguments:Apc - Supplies a pointer to a control object of type APC.Increment - Supplies the priority increment that is to be applied ifqueuing the APC causes a thread wait to be satisfied.Return Value:If the APC object is already in an APC queue, then a value of FALSE isreturned. Else a value of TRUE is returned.--*/{KPROCESSOR_MODE ApcMode;PKAPC ApcEntry;PKAPC_STATE ApcState;BOOLEAN Inserted;PLIST_ENTRY ListEntry;PKTHREAD Thread;//// If the APC object is already in an APC queue, then set inserted to// FALSE. Else insert the APC object in the proper queue, set the APC// inserted state to TRUE, check to determine if the APC should be delivered// immediately, and set inserted to TRUE.//// For multiprocessor performance, the following code utilizes the fact// that kernel APC disable count is incremented before checking whether// the kernel APC queue is nonempty.//// See KeLeaveCriticalRegion().//Thread = Apc->Thread;if (Apc->Inserted) {Inserted = FALSE;} else {//typedef enum _KAPC_ENVIRONMENT {// OriginalApcEnvironment, // 所屬進程(創建線程的進程,父進程)// AttachedApcEnvironment, // 掛靠進程// CurrentApcEnvironment, // 當前環境,提供CR3的進程(正常狀態是所屬進程,掛靠狀態是掛靠進程)// InsertApcEnvironment // 插入APC時的環境//} KAPC_ENVIRONMENT;// Apc->ApcStateIndex 是在 KeInitializeApc 函數內初始化的,它的值決定了插入到哪個進程的APC隊列(所屬進程 還是 掛靠進程)// // 終止線程的 PspTerminateThreadByPointer 和3環 QueueUserApc , Apc->ApcStateIndex 都是 0// 0意味著選擇所屬進程,因為不掛靠時 ApcStatePointer[0] 是所屬線程;掛靠時 ApcStatePointer[0] 還是所屬線程的備份if (Apc->ApcStateIndex == InsertApcEnvironment) {// 插入前實時地從 Thread 里取//設計 InsertApcEnvironment 也許是考慮到初始化時和插入前線程的狀態可以發生改變Apc->ApcStateIndex = Thread->ApcStateIndex;}ApcState = Thread->ApcStatePointer[Apc->ApcStateIndex];//// Insert the APC after all other special APC entries selected by// the processor mode if the normal routine value is NULL. Else// insert the APC object at the tail of the APC queue selected by// the processor mode unless the APC mode is user and the address// of the special APC routine is exit thread, in which case insert// the APC at the front of the list and set user APC pending.//ApcMode = Apc->ApcMode; // 內核APC or 用戶APCif (Apc->NormalRoutine != NULL) {// NormalRoutine 非空,就在這里插入// NormalRoutine 是 所有用戶APC函數的入口 或者 內核APC函數,取決于APC是用戶模式還是內核模式if ((ApcMode != KernelMode) && (Apc->KernelRoutine == PsExitSpecialApc)) {// 是用戶APC,并且 KernelRoutine == PsExitSpecialApc ,3環調用 QueueUserApc 就是這種情況// 標記已插入Thread->ApcState.UserApcPending = TRUE;// 插入到隊列頭部InsertHeadList(&ApcState->ApcListHead[ApcMode],&Apc->ApcListEntry);} else {// 內核APC,比較簡單,直接插入隊列尾部InsertTailList(&ApcState->ApcListHead[ApcMode],&Apc->ApcListEntry);}} else {// NormalRoutine 是 NULL ,走這里// 從隊尾開始遍歷 APC 隊列// 直到找到下一個 NormalRoutine 為空的APCListEntry = ApcState->ApcListHead[ApcMode].Blink;while (ListEntry != &ApcState->ApcListHead[ApcMode]) {ApcEntry = CONTAINING_RECORD(ListEntry, KAPC, ApcListEntry);if (ApcEntry->NormalRoutine == NULL) {break;}ListEntry = ListEntry->Blink;}// 插入到隊列頭部InsertHeadList(ListEntry, &Apc->ApcListEntry);}// 插入成功Apc->Inserted = TRUE;//// If the APC index from the APC object matches the APC Index of// the thread, then check to determine if the APC should interrupt// thread execution or sequence the thread out of a wait state.//// 條件成立,APC 和當前線程使用同一個進程// 要么沒有attach,APC插入了所屬進程// 要么attach了,APC插入的也是掛靠的進程if (Apc->ApcStateIndex == Thread->ApcStateIndex) {//// If the processor mode of the APC is kernel, then check if// the APC should either interrupt the thread or sequence the// thread out of a Waiting state. Else check if the APC should// sequence the thread out of an alertable Waiting state.//if (ApcMode == KernelMode) {// 標記已插入內核APCThread->ApcState.KernelApcPending = TRUE;if (Thread->State == Running) {// 如果線程正在運行,則 APC 中斷KiRequestApcInterrupt(Thread->NextProcessor);} else if ((Thread->State == Waiting) && // 線程阻塞(等待)(Thread->WaitIrql == 0) &&((Apc->NormalRoutine == NULL) ||((Thread->KernelApcDisable == 0) &&(Thread->ApcState.KernelApcInProgress == FALSE)))) // 沒有正在執行的 APC{// 修改線程狀態為就緒,提升優先級KiUnwaitThread(Thread, STATUS_KERNEL_APC, Increment, NULL);}} else if ((Thread->State == Waiting) && // 線程處于阻塞狀態(Thread->WaitMode == UserMode) && // 用戶導致的阻塞(Thread->Alertable || Thread->ApcState.UserApcPending)) // 是否可以被APC喚醒或者已經插入,SleepEx 可以設置 Alertable{Thread->ApcState.UserApcPending = TRUE;// 修改線程狀態為就緒,提升優先級KiUnwaitThread(Thread, STATUS_USER_APC, Increment, NULL);}}Inserted = TRUE;}//// Return whether the APC object was inserted in an APC queue.//return Inserted; }總結
以上是生活随笔為你收集整理的(74)分析 APC 插入过程 —— KeInsertQueueApc , KiInsertQueueApc的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: (73)分析 KeInitializeA
- 下一篇: (75)内核APC执行过程,分析 KiD