使用微調鎖定:範例
將驅動程式持有微調鎖定的時間降到最低,可以大幅改善驅動程式和整體系統的效能。 例如,假設下圖顯示中斷微調鎖定如何保護必須在ISR與SMP機器中的 StartIo 和 DpcForIsr 例程之間共用的裝置特定數據。
當驅動程式的 ISR 在一個處理器上的 DIRQL 上執行時,其 StartIo 例程會在第二個處理器上的DISPATCH_LEVEL執行。 核心插斷處理程式會保存驅動程式 ISR 的 InterruptSpinLock,其會存取受保護的裝置特定數據,例如裝置註冊的狀態或指標, (SynchronizeContext) 驅動程式的裝置擴充功能。 StartIo 例程已準備好存取 SynchronizeContext、呼叫 KeSynchronizeExecution、將指標傳遞給相關聯的中斷對象、共用的 SynchronizeContext,以及驅動程式的 SynchCritSection 例程 (上圖中的 AccessDevice) 。
在ISR傳回之前,藉此釋放驅動程式的InterruptSpinLock,KeSynchronizeExecution 會在第二個處理器上微調,以防止 AccessDevice 觸碰 SynchronizeContext。 不過, KeSynchronizeExecution 也會將第二個處理器上的 IRQL 引發至中斷物件的 SynchronizeIrql,藉此防止該處理器上發生另一個裝置中斷,以便在 ISR 傳回時立即在 DIRQL 上執行 AccessDevice。 不過,其他裝置的 DIRQL 中斷較高、時鐘中斷和電源故障中斷仍可在任一處理器上發生。
當ISR將驅動程式的 DpcForIsr 排入佇列並傳回時,AccessDevice 會在相關聯中斷物件之 SynchronizeIrql 的第二個處理器上執行,並存取 SynchronizeContext。 同時, DpcForIsr 會在DISPATCH_LEVEL IRQL 的另一個處理器上執行。 DpcForIsr 也準備好存取 SynchronizeContext,因此它會使用 StartIo 例程在步驟 1 中執行的相同參數來呼叫 KeSynchronizeExecution。
當 KeSynchronizeExecution 取得微調鎖定並代表 StartIo 例程執行 AccessDevice 時,驅動程式提供的同步處理程式 AccessDevice 會獲得 SynchronizeContext 的獨佔存取權。 由於 AccessDevice 會在 SynchronizeIrql 上執行,因此驅動程式的 ISR 無法取得微調鎖定並存取相同的區域,直到釋放微調鎖定為止,即使裝置在執行 AccessDevice 時在另一個處理器上中斷也一樣。
AccessDevice 會傳回,釋放微調鎖定。 StartIo 例程會在第二個處理器的DISPATCH_LEVEL繼續執行。 KeSynchronizeExecution 現在會在第三個處理器上執行 AccessDevice,因此它可以代表 DpcForIsr 存取 SynchronizeContext。 不過,如果在步驟 2 中名為 KeSynchronizeExecution 的 DpcForIsr 之前發生裝置中斷,ISR 可能會在另一個處理器上執行,然後 KeSynchronizeExecution 才能取得微調鎖定,並在第三個處理器上執行 AccessDevice。
如上圖所示,雖然在一個處理器上執行的例程會保留微調鎖定,但嘗試取得微調鎖定的所有其他例程不會完成任何工作。 每個嘗試取得已保留微調鎖定的例程只會在其目前的處理器上旋轉,直到持有者釋放微調鎖定為止。 釋放微調鎖定時,只有一個例程可以取得它;目前嘗試取得相同微調鎖定的所有其他例程都會繼續微調。
任何微調鎖定的持有者都會在引發的 IRQL 上執行:在執行微調鎖定DISPATCH_LEVEL,或在 DIRQL 上執行中斷微調鎖定。 KeAcquireSpinLock 和 KeAcquireInStackQueuedSpinLock 的呼叫端會在DISPATCH_LEVEL執行,直到呼叫 KeReleaseSpinLock 或 KeReleaseInStackQueuedSpinLock 以釋放鎖定為止。 KeSynchronizeExecution 的呼叫端會自動將目前處理器上的 IRQL 引發至中斷物件的 SynchronizeIrql,直到呼叫端提供的 SynchCritSection 例程結束,且 KeSynchronizeExecution 會傳回控制權。 如需詳細資訊,請參閱 呼叫使用微調鎖定的支援例程。
請記住下列關於使用微調鎖定的事實:
在較低 IRQL 執行的所有程式碼,都無法在微調鎖定持有者所佔用的處理器集合上完成任何工作,以及其他嘗試取得相同微調鎖定的例程。
因此,將驅動程式持有微調鎖定的時間降至最低,可大幅提升驅動程式效能,並大幅提升整體系統效能。
如上圖所示,核心插斷處理程式會在多處理器計算機中,以初次提供的第一個服務基礎,在相同的 IRQL 上執行例程。 核心也會執行下列動作:
當驅動程式例程呼叫 KeSynchronizeExecution 時,核心會導致驅動程式的 SynchCritSection 例程在呼叫 KeSynchronizeExecution 的相同處理器上執行, (請參閱步驟 1 和 3) 。
當驅動程式的 ISR 將 DpcForIsr 排入佇列時,核心會導致 DPC 在 IRQL 低於的第一個可用處理器上執行DISPATCH_LEVEL。 這不一定與 IoRequestDpc 呼叫發生的處理器相同, (請參閱步驟 2) 。
驅動程式的插斷驅動 I/O 作業可能通常會在單處理器機器中串行化,但相同的作業可以在 SMP 機器中真正異步。 如上圖所示,驅動程式的 ISR 可以在 SMP 機器的 CPU4 上執行,然後 DpcForIsr 開始處理 ISR 已在 CPU1 上處理裝置中斷的 IRP。
換句話說,您不應該假設中斷微調鎖定可以在 DpcForIsr 或 CustomDpc 例程執行之前,在 DpcForIsr 或 CustomDpc 例程執行之前,於某個處理器上執行 ISR 時,保護 ISR 在一個處理器上執行時所儲存的作業特定數據。
雖然驅動程式可能會嘗試串行化所有中斷驅動 I/O 作業,以保留 ISR 所收集的數據,但該驅動程式在 SMP 機器中執行的速度不會比單處理器電腦快很多。 若要取得最佳的可能驅動程式效能,同時在單處理器和多處理器平臺上保持可攜式,驅動程式應該使用一些其他技術來儲存 ISR 取得的作業特定數據,以供 DpcForIsr 後續處理。
例如,ISR 可以在傳遞給 DpcForIsr 的 IRP 中儲存作業特定數據。 這項技術的精簡是實作 DpcForIsr 來諮詢 ISR 增強計數、使用 ISR 提供的數據來處理計數的 IRP 數目,並在傳回之前將計數重設為零。 當然,計數必須受到驅動程式中斷微調鎖定的保護,因為其ISR和 SynchCritSection 會動態維護其值。