旗號物件

任何驅動程式都可以使用旗號物件,在其驅動程式建立的執行緒和其他驅動程式常式之間同步處理作業。 例如,當驅動程式沒有未完成的 I/O 要求時,驅動程式專用線程可能會自行進入等候狀態,而驅動程式的分派常式可能會將旗號設定為訊號狀態,只是在排入 IRP 佇列之後。

在要求 I/O 作業的執行緒內容中執行的最高層級驅動程式分派常式,可能會使用旗號來保護分派常式之間共用的資源。 同步 I/O 作業的較低層級驅動程式分派常式也可能會使用號號來保護分派常式子集或驅動程式建立執行緒之間共用的資源。

任何使用旗號物件的驅動程式都必須呼叫 KeInitializeSemaphore ,才能等候或釋放旗號。 下圖說明具有線程的驅動程式如何使用旗號物件。

說明等候號號物件的圖表。

如上圖所示,這類驅動程式必須提供號號物件的儲存空間,這應該位於該物件中。 驅動程式可以使用驅動程式所建立 裝置物件的裝置延伸模組 、控制器擴充功能,如果使用 控制器物件,或驅動程式所配置的非分頁集區。

當驅動程式的 AddDevice 常式呼叫 KeInitializeSemaphore時,它必須傳遞指標給驅動程式的駐留儲存體,以供旗號物件使用。 此外,呼叫端必須指定旗號物件的 Count ,如上圖所示,決定其初始狀態 (非零的 Signaled) 。

呼叫端也必須指定旗號 的限制 ,這可以是下列其中一項:

  • 限制 = 1

    當這個旗號設定為 Signaled 狀態時,等候訊號設定為訊號狀態的單一線程會變成符合執行資格,而且可以存取受旗號保護的任何資源。

    這種類型的旗 號也稱為二進位旗號, 因為執行緒具有或沒有受旗號保護資源的獨佔存取權。

  • 限制 > 1

    當這個旗號設定為 Signaled 狀態時,等候信號物件設定為 Signaled 狀態的一些執行緒數目會變成符合執行資格,而且可以存取受旗號保護的任何資源。

    這種類型的旗 號稱為計數旗號, 因為將信號設定為 Signaled 狀態的常式也會指定有多少等候執行緒可以讓其狀態從等候變更為就緒。 當旗號初始化時,這類等候執行緒的數目可以是 設定的限制 ,或是小於此預設 限制的一些數位。

少數裝置或中繼驅動程式具有單一驅動程式建立的執行緒;較少的執行緒集可能會等待取得或釋放旗號。 少數系統提供的驅動程式會使用旗號物件,而且其中有些是使用二進位旗號。 雖然二進位旗號在功能上似乎類似 mutex 物件,但二進位旗號不會針對在 SMP 機器中執行之系統執行緒的死結提供內建保護。

載入具有初始化旗號的驅動程式之後,它可以同步處理旗號上的作業,以保護共用資源。 例如,具有裝置專用線程的驅動程式,可管理 IRP 的佇列,例如系統磁片磁碟機驅動程式,可能會同步處理信號上的 IRP 佇列,如上圖所示:

  1. 執行緒會呼叫 KeWaitForSingleObject ,並使用驅動程式提供的儲存體指標,讓初始化的旗號物件進入等候狀態。

  2. IRP 開始需要裝置 I/O 作業。 驅動程式的分派常式會將每個這類 IRP 插入微調鎖定控制下的相互鎖定佇列中,並使用信號物件的指標呼叫 KeReleaseSemaphore 、執行緒 (遞增的驅動程式決定優先權提升,如上圖) 所示,將調整 1 新增至旗號的計數,因為每個 IRP 已排入佇列, 和布林 值等候 設定為 FALSE。 非零號號計數會將旗號物件設定為 Signaled 狀態,藉此將等候執行緒的狀態變更為就緒。

  3. 核心會在處理器可用時立即分派執行執行緒:也就是說,沒有其他優先順序較高的執行緒處於就緒狀態,而且沒有核心模式常式可在較高的 IRQL 執行。

    執行緒會從微調鎖定控制下的內鎖佇列中移除 IRP、將其傳遞至其他驅動程式常式以進行進一步處理,並再次呼叫 KeWaitForSingleObject 。 如果旗號仍然設定為 Signaled 狀態 (,其 Count 會維持非零,表示更多 IRP 位於驅動程式的相互鎖定佇列中) ,核心會再次變更執行緒的狀態,使其無法等候就緒。

    透過以此方式使用計數號號,這類驅動程式執行緒「知道」每當執行該執行緒時,就會從連結佇列中移除 IRP。

如需呼叫 KeReleaseSemaphore時管理 IRQL 的特定資訊,請參閱 KeReleaseSemaphore的一節。

任何在 IRQL 上執行且大於 PASSIVE_LEVEL 的標準驅動程式常式,都無法等候任何發送器物件的非零間隔,而不需要關閉系統;如需詳細資訊,請參閱 核心發送器物件 。 不過,這類常式可以在 IRQL 小於或等於DISPATCH_LEVEL時呼叫 KeReleaseSemaphore

如需標準驅動程式常式執行之 IRQL 的摘要,請參閱 管理硬體優先順序。 如需特定支援常式的 IRQL 需求,請參閱常式的參考頁面。