$ 前言
這篇文章應該寫於 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...