非同步過程呼叫

非同步過程呼叫(asynchronous procedure call)是函式(過程)在特定執行緒中被非同步執行。在Microsoft Windows作業系統中, APC是一種並行機制,用於非同步IO或者定時器[1]

分類

Windows NT作業系統中有3種APC:

  • 核心模式特殊APC:相應的APC函式為核心函式。在IRQL =APC_LEVEL級上有可排程的活動時,執行此類APC。會搶先所有的使用者模態以及IRQL = PASSIVE_LEVEL的核心模態下的代碼的執行。[2]
  • 核心模式常規APC:在所有的核心模式特殊APC執行完畢後,核心模式常規APC在IRQL = PASSIVE_LEVEL下開始執行。會搶先所有的使用者模式代碼的執行。用於檔案系統。
  • 使用者模式APC:是指相應的 APC 函式位於使用者空間、在使用者空間執行。執行緒處於alertable wait狀態該APC才可以被排程執行。使用者模式下呼叫系統API如SleepEx, SignalObjectAndWait,WaitForSingleObjectEx, WaitForMultipleObjectsEx, MsgWaitForMultipleObjectEx等,可以使執行緒進入alertable狀態。這些API函式最終都是呼叫了核心中的KeWaitForSingleObject, KeWaitForMultipleObjects,KeWaitForMutexObject, KeDelayExecutionThread, KeTestAlertThread等函式。執行緒在alertable wait狀態所有核心模式API執行完畢,返回使用者模式時,核心轉去執行APC,完成後再繼續執行緒的原來執行。

API

  • APC對象:為struct KAPC類型。每個APC對象必須要包含一個KernelRoutine函式指標,當這個APC被作業系統的APC dispatcher執行時,該常式首先被執行。使用者模式APCs必須包含一個NormalRoutine函式指標,所指的函式在使用者主記憶體區域。核心模式常規APC也必須包含一個NormalRoutine,但執行在核心模式(即_KAPC.ApcMode==KernelMode)。核心模式特殊APC的NormalRoutine為空。任意類型的APC都可以定義一個RundownRoutine,所指函式在核心主記憶體區域,當系統需要釋放APC佇列的內容時(例如執行緒退出時)被呼叫。
  • 每個執行緒有兩個APC佇列,分為使用者APC佇列和核心APC佇列。
  • QueueUserAPC: 應用程式把APC放入一個執行緒的使用者模式APC佇列中;
  • KeInitializeApc 處理非同步IO的裝置驅動程式用這個函式來初始化APC對象(為struct KAPC類型)。如果函式參數NormalRoutine為NULL,那麼生成的是核心模式特殊APC對象;如果參數NormalRoutine為NULL且參數ApcMode的值是KernelMode,那麼生成的是核心模式常規APC對象;否則生成使用者模式APC對象。
  • KeInsertQueueApc 把完成初始化的APC對象存放到目標執行緒的APC佇列中
  • KiInsertQueueApc 實際完成插入到佇列中的操作
  • KiDeliverApc 即作業系統APC派發器子程式。投遞一個掛起的(pending)APC到目標執行緒。KiDeliverApc每處理完一個User APC就把UserApcPending清零,所以User APCs在返回使用者空間時還是只能投遞一次.
  • KiInitializeUserApc:在從核心態返回到使用者態以執行使用者模式APC時,修改環境以準備好由KeUserApcDispatcher呼叫User APC回呼函式.

參考文獻

  1. ^ MSDN article: "Asynchronous Procedure Calls". [2016-08-19]. (原始內容存檔於2016-09-13). 
  2. ^ Windows的中斷請求級別由低到高是0-31。其中PASSIVE_LEVEL=0,為使用者態與大部分核心態操作;APC_LEVEL為非同步過程呼叫與缺頁;DISPATCH_LEVEL=2為執行緒排程器與deferred procedure calls。