DPC 延遲過程呼叫

2021-04-09 06:43:55 字數 2771 閱讀 1241

$ 前言

這篇文章應該寫於 2023年4月13日,是寫給自己備忘的研究文件,本來是根本沒有打算放出來的。

$ dpc

deferred procedure call (dpc) 延遲過程呼叫

dpc 主要是為了減少處於高 irql 的硬體中斷處理的時間。

由於低 irql 的硬體中斷不能中斷 高 irql 的硬體中斷處理。

而可能有些硬體的中斷處理**量比較大,花的時間比較多,會造成其他硬體中斷的響應會等的時間比較長。

很有可能就是因為 時鐘中斷處理,非常非常頻繁,**量也比較多,可能會比較大的影響到其他硬體中斷的響應,至於硬體中斷響應比較慢可能會對不同的硬體造成什麼結果,有待研究。

$ dpc 佇列

整個系統只有乙個 dpc 佇列,至少對單cpu的系統是如此,對於多cpu系統有可能是乙個cpu乙個,有待驗證。

這個佇列是個 list_entry 鍊錶。

煉表頭在 pcr 的 +800 struct _list_entry dpclisthead。

鏈的深度在 pcr 的 +808 uint32 dpcqueuedepth。

所有的 dpc 都鏈在這個鏈上。

鏈上的每項是個 kdpc 結構。

struct   _kdpc (sizeof=32)

+00 int16    type

+02 byte     number

+03 byte     importance

+04 struct   _list_entry dpclistentry

+04    struct   _list_entry *flink

+08    struct   _list_entry *blink

+0c function *deferredroutine

+10 void     *deferredcontext

+14 void     *systemargument1

+18 void     *systemargument2

+1c uint32   *lock

$ dpc 的源頭

所有的 dpc 都是在 irql >= dispatch_level 的**中產生的。

也就是只有 irql 大於等於 dispatch_level 的**使用 dpc。

dpc 都是在硬體中斷服務例程(isr)中,由硬體中斷服務例程根據自己的需要,鏈入到 dpc 佇列中的。

中斷服務例程中呼叫 keinsertqueuedpc 將 dpc 鏈入 dpc 佇列,或者,中斷服務例程直接操作 dpc 鍊錶,將 dpc 鏈入。

keinsertqueuedpc 除了將 dpc 鏈入鏈之外,還會呼叫 kirequestsoftwareinterrupt(dispatch_level),如果呼叫是的 irql 高於 dispatch_level,會使得 dpc pending,等到 irql 降下來的時候得到執行。

如果是自己直接操作鏈來將dpc鏈入的話,也需要自己呼叫類似 kirequestsoftwareinterrupt(dispatch_level) 的函式。

$ dpc 的執行

在硬體中斷處理的最後,會呼叫 halendsysteminterrupt。

halendsysteminterrupt 中,會將 irql 降低,然後檢查是否有 dpc pending,有的話,會呼叫 kidispatchinterrupt 處理 dpc。

kidispatchinterrupt 中呼叫 kiretiredpclist 處理 dpc。

也就是說,當在硬體中斷處理中加入乙個 dpc,那麼當這個硬體中斷處理結束的時候,就會呼叫這個被加入的 dpc。

a:所有處理都放在isr中

b:處理分兩部分,必須要做的放在isr中,剩下的放在dpc中,isr中使用dpc

a的處理**一直執行下來,只可能被irql比它高的硬體中斷中斷。

b的isr一直執行下來,緊接著執行dpc。isr部分只能被irql比它高的硬體中斷中斷。dpc部分可被任何硬體中斷中斷。

$ dpc 不可能受到執行緒切換的影響

會不會 dpc 中的**執行到一半,發生執行緒切換,或者執行緒搶占,cpu 轉去執行什麼執行緒?

答案是絕對不會。

這是由於負責執行緒切換,搶占的**就是執行在 irql dispatch_level,而 irql 小於等於當前 irql 的中斷不能發生。

所以執行 dpc 時,irql 為 dispatch_level,根本就不會發生執行緒切換,執行緒搶占之類的事情。

當然中斷中,就更不會了。

$ kidispatchinterrupt

dispatch_level 上執行的**有兩大種,

一種是各種 isr 加的 dpc,處理乙個 dpc,也就是呼叫這個 dpc 中的 deferredroutine。

一種是關於執行緒排程的。

由於 kidispatchinterrupt 會在各種硬體中斷處理的結束有可能得到呼叫,當硬體中斷處理過程中使用dpc的情況下就會在中斷處理結束的時候被呼叫。

如果有任何**使用 dispatch_level requestsoftwareinterrupt 的話,kidispatchinterrupt 也可能被立即執行。

quantumend 不為0的情況,目前只有一種情況引起,就是時鐘中斷處理中,將當前執行緒的 quantum 減少後,發現當前執行緒 quantum 用完,就會設定 quantumend,並在 時鐘中斷 處理結束的時候,引起 kidispatchinterrupt 執行。

nextthread 不為0的情況,是哪些情況下引起的,還待研究。

Swift Defer 延遲呼叫

func checksomething func dosomething print checkpoint 3 checkpoint 1,checkpoint 2,checkpoint 3,clean up here,checkpoint 4 checksomething 在你的 塊就要結束前。如果...

延遲呼叫performSelector介紹

performselector void performselector sel aselector withobject id anargument afterdelay nstimeinterval delay 上述的方法可以靈活的運用,使用方便,只需要告訴他會呼叫什麼方法,然後在多長時間對他進...

golang延遲呼叫(defer)

defer特性 關鍵字 defer 用於註冊延遲呼叫。這些呼叫直到 return 前才被執。因此,可以用來做資源清理。多個defer語句,按先進後出的方式執行。defer語句中的變數,在defer宣告時就決定了。defer用途 關閉檔案控制代碼 鎖資源釋放 資料庫連線釋放 defer的觸發packa...