(62)时钟中断切换线程,时间片管理, KiDispatchInterrupt
一、回顧
前面的課程,我們分析了API主動切換線程的流程,分析了 KiSwapContext 和 SwapContext 函數(shù),這兩個是切換線程的函數(shù)。分析了 KiSwapThread 函數(shù),功能是找到新的就緒線程。分析了 KiFindReadyThread 函數(shù),了解了操作系統(tǒng)如何根據(jù)線程優(yōu)先級來調(diào)度線程。
除了主動切換以外,時鐘中斷和異常也會導致線程切換。
這次課我們來學習另一種導致線程切換的情景 —— 時鐘中斷。
二、時鐘中斷
Windows系統(tǒng)每隔10-20毫秒會觸發(fā)一次時鐘中斷,可以調(diào)用 GetSystemTimeAdjustment 函數(shù)獲取準確數(shù)值。
時鐘中斷的中斷號是0x30,中斷請求級別IRQL是0,我們可以在IDT表里找到時鐘中斷處理函數(shù) KiStartUnexpectedRange 。
我們可以在IDA里跟一下 KiStartUnexpectedRange 的執(zhí)行流程,發(fā)現(xiàn)依次調(diào)用了以下函數(shù):
KiDispatchInterrupt 函數(shù)會根據(jù)當前線程剩余時間片和備用線程的情況來決定下一步的調(diào)用,這部分在逆向時詳細介紹。
三、時間片 Quantum ,備用線程 NextThread
當一個新的線程開始執(zhí)行時,初始化程序會在 _KTHREAD.Quantum 賦初始值,該值的大小由_KPROCESS.ThreadQuantum 決定,默認是6.
KeUpdateRunTime
每次時鐘中斷會調(diào)用KeUpdateRunTime函數(shù),該函數(shù)每次將當前線程 Quantum減少3個單位,如果減到0,則將KPCR.PrcbData.QuantumEnd的 值設(shè)置為非0。
.text:0046A1B8 sub [ebx+_KTHREAD.Quantum], 3 ; 時間片 -3 .text:0046A1BC jg short loc_46A1D7 .text:0046A1BE cmp ebx, [eax+_KPCR.PrcbData.IdleThread] .text:0046A1C4 jz short loc_46A1D7 .text:0046A1C6 mov [eax+_KPCR.PrcbData.QuantumEnd], esp可以看出,一個線程初始狀態(tài)有6個時間片,每次中斷會把當前線程時間片減3,這意味著一個線程要經(jīng)過兩次時鐘中斷時間片才會用完。
KiDispatchInterrupt
KiDispatchInterrupt 函數(shù)會判斷當前線程時間片,如果 QuantumEnd 是非0,表明時間片用完,然后就會調(diào)用 KiQuantumEnd 函數(shù)重新設(shè)置時間片,然后執(zhí)行線程切換;如果時間片沒用完,但是存在備用線程 NextThread,那么也會發(fā)生切換:
KiDispatchInterrupt 函數(shù)的主要功能已經(jīng)分析完了,其中有兩個函數(shù)還沒介紹,分別是 KiQuantumEnd 和 KiReadyThread 。
KiQuantumEnd
KiQuantumEnd 函數(shù)主要工作就是重新設(shè)置時間片:
mov al, [eax+_EPROCESS.Pcb.ThreadQuantum] mov [esi+_ETHREAD.Tcb.Quantum], al ; 重新設(shè)置一下當前線程的時間片然后調(diào)用 KiFindReadyThread 找新的就緒線程作為函數(shù)返回值:
movzx ecx, [esi+_ETHREAD.Tcb.NextProcessor] call @KiFindReadyThread@8 ; KiFindReadyThread(x,x) cmp eax, ebx jz short loc_428C4BKiReadyThread
這個函數(shù)的作用是把舊線程 ETHREAD(ecx 傳參)添加到就緒鏈表里,關(guān)鍵代碼如下:
.text:00429A40 loc_429A40: ; CODE XREF: KiReadyThread(x)+5E↑j .text:00429A40 ; KiReadyThread(x)+12A↑j .text:00429A40 mov [eax+_ETHREAD.Tcb.State], 1 ; 就緒狀態(tài) .text:00429A44 add eax, 60h ; ETHREAD + 0x60 是一個鏈表, WaitListEntry / SwapListEntry .text:00429A47 test bl, bl .text:00429A49 lea edx, _KiDispatcherReadyListHead[ecx*8] ; edx 指向?qū)獌?yōu)先級的鏈表頭 .text:00429A50 jz short loc_429A60 .text:00429A52 mov esi, [edx] ; 下一個線程.FLink .text:00429A54 mov [eax], esi ; ETHREAD.WaitListEntry.FLink 指向下一個線程 .text:00429A56 mov [eax+4], edx ; ETHREAD.WaitListEntry.BLink 指向鏈表頭 .text:00429A59 mov [esi+4], eax ; 下一個線程.BLink 指向 ETHREAD.WaitListEntry .text:00429A5C mov [edx], eax ; 鏈表頭.FLink = ETHREAD.WaitListEntry .text:00429A5E jmp short loc_429A6D 《新程序員》:云原生和全面數(shù)字化實踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的(62)时钟中断切换线程,时间片管理, KiDispatchInterrupt的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: (61)分析 KiFindReadyTh
- 下一篇: (63)0环与3环通信非常规方式 ——