跳至內容

延遲過程調用

本頁使用了標題或全文手工轉換
維基百科,自由的百科全書

延遲過程調用(DPC)是Microsoft Windows操作系統的機制,允許高優先級任務(如中斷處理程序英語interrupt handler)延遲所需的低優先級任務稍後執行。這使得設備驅動程序與其他低層事件消費者更快地執行其處理的高優先級部分,調度非關鍵的附件處理稍後以較低優先級執行。

DPC是通過DPC對象實現的。當設備驅動程序或其他內核態程序發出DPC請求時,操作系統內核創建DPC對象,投寄到DPC隊列尾部。多核處理器的每個內核有自己的DPC隊列。當Windows操作系統的IRQL降低到Dispatch/DPC級,操作系統檢查DPC隊列,逐個執行掛起的DPC,直至隊列為空或者發生IRQL更高的中斷。

例如,當時鐘中斷發生時,時鐘中斷服務程序通常增加當前線程的計數器以計算當前線程的總執行時間,把它的時間片減1。當時間片減少到0,線程調度器將被喚醒去選擇下一個在當前處理器內核上運行的線程並做線程上下文切換。時鐘中斷服務程序運行在非常高的IRQL上,它應該在稍後的IRQL下降到低級時才去執行線程調度程序。因此時鐘中斷服務程序請求一個DPC對象並把這個對象放在DPC隊列尾部,當處理器的IRQL下降到DPC/Dispatch級別時,回去執行DPC隊列中的任務。

當流音視頻工作時,使用DPC處理流輸入到緩衝區的音頻。如果另外一個DPC執行了很長時間並且另一次中斷產生了新的緩衝區數據,在第一塊數據被處理前,會發生信號缺失英語Dropout (electronics)結果。[1]

技術細節[編輯]

具體說,CPU的每個內核對應的_KPRCB數據結構中,有兩個DPC隊列:

  • (普通)DPC隊列:普通的DPC可以在任何一個線程環境中運行
  • 線程化DPC隊列:這種DPC只能在內核啟動時系統創建的一個叫做DPC的線程中運行。該線程工作在passive層,但有最高的線程優先級(Realtime級)。因此,CPU一旦工作在passive級,最先執行的就是線程化DPC例程中的代碼。

DPC執行例程一般較大,為避免當前線程的運行棧溢出,DPC例程使用每個CPU專門的DPC運行棧。

DPC有三種優先級:

  • low:入隊時放在隊列頭部,僅當隊列長度超限或者DPC請求率太低,才會被執行。
  • medium:默認值。入隊時放在隊列尾部,總是被投遞(即執行)。
  • high:入隊時放在隊列頭部,總是被投遞(即執行)。

DPC對象是Windows內核對象之一,其數據結構定義為:

Typedef struct _KDPC
{
 UCHAR Type;//DpcObject或者ThreadedDpcObject类型
 UCHAR Importance;//High,medium,low
 USHORT Number;//CPU的哪个核上
 LIST_ENTRY DpcListEntry;//链表结构
 PKDEFERRED_ROUTINE DeferredRoutine;//DPC例程
 PVOID DeferredContext;//执行DPC时的上下文 
 PVOID SystemArgument1;//执行DPC时的参数1 
 PVOID SystemArgument2;//执行DPC时的参数2 
 Volatile PVOID DpcData;//指向CPU的核的数据结构_KPRCB中的DpcData成员
}KDPC

DPC對象入隊時,內核會請求一個在Dispatch/DPC級的軟件中斷。當IRQL降低到APC或者PASSIVE級時,會投遞一個APC對象並把IRQL升到DPC級。此時DPC例程會在任何任意進程的運行環境中,因此DPC例程通常只使用內核地址空間。

設備驅動編程[編輯]

設備驅動編程中使用下述API來管理延遲過程調用:

  • IolnitimizeDpcRequest:初始化設備對象的內置DPC對象,同時註冊一個DPC例程。由KeInitializeDpc將DPC對象與DPC例程、驅動程序創建的設備對象聯繫起來。
  • IoRequestDpc:請求一個DPC調用,由KeInsertQueueDpc函數將DPC對象排隊。如果在DPC例程運行前,該設備又生成一個中斷,系統內核將忽略隨後入隊的任何DPC對象。即每個設備只能有一個DPC對象。
  • KeSetTargetProcessorDpc:把一個DPC對象送入特定處理器的DPC隊列
  • KeSetImportanceDpc:設置DPC對象的優先級
  • KiRetireDpcList:逐個執行DPC隊列中的所有對象

參考文獻[編輯]

  1. ^ Ute Eberhardt. DPC Latency Checker. Thesycon.de. 27 June 2012 [2012-11-07]. (原始內容存檔於2012年10月30日).