定義和使用事件物件

任何使用事件物件的驅動程式都必須呼叫 KeInitializeEventIoCreateNotificationEventIoCreateSynchronizationEvent ,才能等候、設定、清除或重設事件。 下圖說明具有線程的驅動程式如何使用事件物件進行同步處理。

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

如上圖所示,這類驅動程式必須提供事件物件的儲存空間,該物件必須駐留。 驅動程式可以使用驅動程式所建立之 裝置物件的裝置擴充 功能、如果使用 控制器物件,或是驅動程式所配置的非分頁集區,則為控制器擴充功能。

當驅動程式呼叫 KeInitializeEvent時,它必須傳遞指向事件物件之驅動程式的駐留儲存體指標。 此外,呼叫端必須指定事件物件 (發出訊號或未收到訊號) 的初始狀態。 呼叫端也必須指定事件種類,這可以是下列其中一項:

  • SynchronizationEvent

    同步處理事件 設定為 Signaled 狀態時,等候事件重設為Not-Signaled的單一線程會變成符合執行資格,且事件的狀態會自動重設為 Not-Signaled。

    這種事件有時稱為 自動清除事件,因為每次滿足等候時,其 Signaled 狀態都會自動重設。

  • NotificationEvent

    通知事件設定為 Signaled 狀態時,等候事件重設為Not-Signaled的所有線程都符合執行資格,而且事件會維持在 Signaled 狀態,直到明確重設為Not-Signaled發生為止:也就是說,使用指定的事件指標呼叫KeClearEventKeResetEvent

少數裝置或中繼驅動程式具有單一驅動程式專用線程,讓一組執行緒可以藉由等候保護共用資源的事件來同步處理其作業。

大部分使用事件物件的驅動程式在呼叫KeInitializeEvent時,等候 I/O 作業完成時,將輸入類型設定為NotificationEvent。 針對驅動程式使用 IoBuildSynchronousFsdRequestIoBuildDeviceIoControlRequest 建立的 IRP 所設定的事件物件,幾乎一律會初始化為 NotificationEvent ,因為呼叫端會等候事件收到一或多個較低層級驅動程式已滿足其要求的通知。

在驅動程式自行初始化之後,如果有任何驅動程式專用線程,其他常式都可以同步處理事件上的作業。 例如,具有管理 IRP 佇列之執行緒的驅動程式,例如系統磁片磁碟機控制器驅動程式,可能會同步處理事件的 IRP 處理,如下圖所示:

  1. 已清除 IRP 佇列以在裝置上進行處理的執行緒會呼叫 KeWaitForSingleObject ,並針對初始化的事件物件呼叫驅動程式提供的儲存體指標。

  2. 其他驅動程式常式會執行滿足 IRP 所需的 I/O 作業,而且當這些作業完成時,驅動程式的 DpcForIsr 常式會使用事件物件的指標呼叫 KeSetEvent 、執行緒 (Increment的驅動程式決定優先權提升,如上圖) 所示,並將 Boolean Wait 設定為 FALSE。 呼叫 KeSetEvent 會將事件物件設定為 Signaled 狀態,進而將等候執行緒的狀態變更為就緒。

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

    如果 DpcForIsr 尚未使用 IRP 呼叫 IoCompleteRequest ,執行緒現在可以完成 IRP,而且可以將另一個 IRP 清除佇列以在裝置上處理。

呼叫 KeSetEvent 並將 Wait 參數設定為 TRUE ,表示呼叫端想要立即呼叫 KeWaitForSingleObjectKeWaitForMultipleObjects 支援從 KeSetEvent傳回的常式。

請考慮將Wait參數設定為KeSetEvent的下列指導方針

在 IRQL < DISPATCH_LEVEL執行的可分頁執行緒或可分頁驅動程式常式絕對不應該呼叫 KeSetEvent ,並將 Wait 參數設定為 TRUE。 如果呼叫端發生呼叫 KeSetEventKeWaitForSingleObjectKeWaitForMultipleObjects之間的呼叫,就會造成嚴重分頁錯誤。

任何在 IRQL = DISPATCH_LEVEL執行的標準驅動程式常式,都無法在不關閉系統的情況下等待任何發送器物件的非零間隔。 不過,這類常式可以在 IRQL 小於或等於DISPATCH_LEVEL執行時呼叫 KeSetEvent

如需標準驅動程式常式執行之 IRQL 的摘要,請參閱 管理硬體優先順序

KeResetEvent 會傳回指定 事件的先前狀態:是否在呼叫 KeResetEvent 時設定為 Signaled。 KeClearEvent 只會將指定 事件 的狀態設定為 Not-Signaled。

針對何時呼叫上述支援常式,請考慮下列指導方針:

為了提升效能,除非呼叫端需要KeResetEvent傳回的資訊,否則每個驅動程式都應該呼叫KeClearEvent,以判斷下一個要執行的動作。