共用方式為


Run-Down 保護

內核模式驅動程式可以使用向下執行保護,安全地存取另一個內核模式驅動程式所建立和刪除之共享系統記憶體中的物件。

如果物件的所有未完成存取已經完成,且不會有新的存取要求授權,則該物件被稱為 已終止。 例如,可能需要完成共享物件的處理,以便將其刪除並替換為新的物件。

擁有共享對象的驅動程式可允許其他驅動程式獲取及釋放該對象的運行下縮保護。 當退化保護生效時,擁有者以外的驅動程式可以存取物件,且在存取完成之前,物件不會被擁有者刪除。 存取開始之前,存取驅動程式會要求在物件上執行防止重複釋放的保護。 對於長期存留的物件,此要求幾乎總是會被批准。 存取完成之後,存取驅動程式會在物件上釋放先前取得的循序保護。

主要降速保護例程

若要開始共享對象,擁有 對象的驅動程式會呼叫 ExInitializeRundownProtection 例程,以初始化物件的執行保護。 在此呼叫之後,存取物件的其他驅動程式可以在 物件上取得並釋放執行保護。

存取共用對象的驅動程式會呼叫 ExAcquireRundownProtection 例程,以要求對象的執行保護。 存取完成之後,此驅動程式會呼叫 ExReleaseRundownProtection 例程,以釋放對象的執行保護。

如果擁有驅動程式判斷必須刪除共享物件,該驅動程式會等到所有與該物件有關的存取操作完成後才會刪除物件。

為了準備刪除共享對象,擁有共享對象的驅動程式會呼叫 ExWaitForRundownProtectionRelease 例程,以等待物件釋放。 在此呼叫期間,ExWaitForRundownProtectionRelease 等候物件上所有先前授與的收尾保護實例被釋放,但會防止在物件上授與新的收尾保護要求。 在最後一次受保護的存取完成,並且所有執行終止保護的實例都被釋放之後,ExWaitForRundownProtectionRelease 返回,且擁有的驅動程式可以安全地刪除該物件。

ExWaitForRundownProtectionRelease 會封鎖呼叫驅動程式線程的執行,直到所有在共享物件上保留執行保護的驅動程式都會釋放此保護。 為了避免 ExWaitForRundownProtectionRelease 封鎖長時間的執行,存取共用物件的驅動程式線程應該避免在物件上保留執行關閉保護時暫停。 基於此原因,存取的驅動程式應在重要區域或受保護區域內,或於 IRQL = APC_LEVEL 執行時,呼叫 ExAcquireRundownProtectionExReleaseRundownProtection

破耗保護的用途

「資源回收保護」可以在提供共享物件的存取時非常有用,這些物件幾乎總是可用,但偶爾可能需要刪除和替換。 存取資料或呼叫此物件例程的驅動程式,在刪除對象之後,不得嘗試存取該物件。 否則,這些無效的存取可能會導致無法預期的行為、數據損毀,甚至是系統失敗。

例如,當操作系統執行時,防病毒軟體驅動程式通常會保留在記憶體中。 有時候,這個驅動程式可能需要卸除並被更新版本的驅動程式取代。 其他驅動程式會將 I/O 要求傳送至防毒驅動程式,以存取此驅動程式中的數據和例程。 傳送 I/O 要求之前,核心元件,例如文件系統篩選管理員,可以取得執行保護,以防止在處理 I/O 要求時過早卸載防病毒軟體驅動程式。 I/O 要求完成之後,就可以釋出關閉保護。

耗竭保護機制不會將對共享物件的存取操作串行化。 如果兩個或多個存取驅動程式可以同時在物件上保存執行保護,而且必須串行化物件的存取權,則必須使用其他一些機制,例如互斥鎖定,以串行化存取。

EX_RUNDOWN_REF結構

EX_RUNDOWN_REF 結構會追蹤共享物件上耗損保護的狀態。 此結構對驅動程式不透明。 系統提供的 Run-down 保護例程會使用此結構來計算目前在 物件上生效之 Run-down 保護實例的數目。 這些例程也會使用此結構來追蹤物件是已經被停用,還是正處於被停用的過程中。

若要開始共享對象,擁有對象的驅動程式會呼叫 ExInitializeRundownProtection,以初始化與 對象相關聯的 EX_RUNDOWN_REF 結構。 初始化之後,擁有驅動程式可以將此結構提供給需要存取物件的其他驅動程式。 存取驅動程式會將這個結構當做參數傳遞至 ExAcquireRundownProtectionExReleaseRundownProtection 以獲取和釋放物件上的節流保護。 擁有的驅動程式會將這個結構當做參數傳遞至 ExWaitForRundownProtectionRelease 呼叫,以等待物件運行結束,從而能夠安全地刪除它。

與鎖具的比較

耗盡保護是保證共享物件安全存取的數種方式之一。 另一種方法是使用互斥軟體鎖定。 如果驅動程式需要存取目前由另一個驅動程式鎖定的物件,則第一個驅動程式必須等候第二個驅動程序釋放鎖定。 不過,取得和釋放鎖可能會成為效能瓶頸,而鎖可能會消耗大量的記憶體。 如果不正確使用,鎖定可能會導致競爭相同共用對象的驅動程式變成死結。 偵測並避免死結的努力通常需要大量運算資源的轉移。

相較於鎖,耗竭防護的處理時間和記憶體需求相對較少。 一個簡單的引用計數與物件相關聯,以確保刪除該物件會被延遲,直到該物件的所有未完成的存取操作完成為止。 透過此方法,可以使用原子性、互鎖的硬體指令,而不是互斥的軟體鎖定,以保障對物件的安全存取。 呼叫取得和釋放耗盡保護通常是快速的。 使用輕量級機制的好處,例如運行終止保護,對於需長期運作且在多個驅動程式間共享的共享物件來說,效益可能相當顯著。

其他執行保護例程

除了先前提到的程式之外,還有數個其他執行保護例程可供使用。 某些驅動程式可能會使用這些額外的例程。

ExReInitializeRundownProtection 例程可讓先前使用的 EX_RUNDOWN_REF 結構與新的對象相關聯,並初始化此對象的執行保護。

ExRundownCompleted 例程會更新 EX_RUNDOWN_REF 結構,指出相關聯對象的執行已完成。

ExAcquireRundownProtectionExExReleaseRundownProtectionEx 例程類似 ExAcquireRundownProtectionExReleaseRundownProtection。 這四個程序會增加或減少在共享物件上啟用的保護實例計數。 雖然 ExAcquireRundownProtectionExReleaseRundownProtection 以 1 遞增和遞減此計數,ExAcquireRundownProtectionExExReleaseRundownProtectionEx 則可以任意數量遞增和遞減計數。

快取感知的 Run-down 保護

摘要參考是一種精簡且快速的資料結構,但當多個處理器同時嘗試獲取該參考時,可能會導致快取內容爭用。 這可能會影響驅動程式的效能和延展性。

為了避免這個問題,您可以使用具備快取感知的整理參考,將參考追蹤分散到多個快取行。 這樣可減少快取爭用,並改善多處理器計算機上的驅動程式效能。

若要使用快取感知的階段性釋放參考,請遵循下列步驟:

  1. 執行下列其中一項動作,以建立 EX_RUNDOWN_REF_CACHE_AWARE 物件:
  2. 呼叫 ExAcquireRundownProtectionCacheAware 例程,要求獲取對象的執行終止保護。 如果請求被授予,此例程將返回 TRUE;如果物件正在被終止,則返回 FALSE。
  3. 藉由呼叫 ExReleaseRundownProtectionCacheAware 例程,在存取對象之後釋放物件的保護功能。
  4. 在刪除對象之前,請使用 ExWaitForRundownProtectionReleaseCacheAware 例程來等待其終止。 此例程會封鎖當前的線程,直到物件上的所有運行保護實例被釋放。
  5. 如果驅動程式先前呼叫了 ExAllocateCacheAwareRundownProtection,則它應該呼叫 ExFreeCacheAwareRundownProtection 來釋放 Rundown 參考。

若要重複使用快取感知的執行終止參考,請遵循下列步驟:

  1. 在呼叫 ExWaitForRundownProtectionReleaseCacheAware之後,請呼叫 ExRundownCompletedCacheAware,以表示舊物件的執行程序已完成。
  2. 呼叫 ExReInitializeRundownProtectionCacheAware,以在相關聯物件完成運行後重新初始化參考。
  3. 現在驅動程式可以再次呼叫 ExAcquireRundownProtectionCacheAware

具快取感知功能的參考在特定情況下具有較佳的效能和擴展性的優點,但會消耗比一般參考更多的記憶體。 在選擇這兩種類型的清理參考時,您應該考慮這個取捨。