カーネル ディスパッチャー オブジェクトの概要

カーネルは、カーネル ディスパッチャー オブジェクト、または単にディスパッチャー オブジェクトと呼ばれるオブジェクト タイプのセットを定義します。 ディスパッチャー オブジェクトには、タイマー オブジェクト、イベント オブジェクト、セマフォ オブジェクト、ミューテックス オブジェクト、スレッド オブジェクトが含まれます。

ドライバーは、PASSIVE_LEVEL に等しい IRQL で 実行中に、非固定スレッド コンテキスト内での同期メカニズムとして、ディスパッチャー オブジェクトを使用できます。

ディスパッチャー オブジェクトの状態

すべてのカーネル定義ディスパッチャー オブジェクトの種類は、状態が Signaled か、Not-Signaled のいずれかに設定されていまzす。

スレッド グループは、1 つ以上のスレッドが KeWaitForSingleObjectKeWaitForMutexObject、または KeWaitForMultipleObjects を呼び出した場合に、操作を同期することができます。 これらの関数は、ディスパッチャー オブジェクト ポインターを入力として受け取り、別のルーチンまたはスレッドが 1 つ以上のディスパッチャー オブジェクトを Signaled 状態に設定するまで待機します。

スレッドが KeWaitForSingleObject を呼び出してディスパッチャー オブジェクト (ミューテックスの場合は KeWaitForMutexObject) を待機すると、ディスパッチャー オブジェクトが Signaled 状態に設定されるまでスレッドは待機状態になります。 スレッドは KeWaitForMultipleObjects を呼び出すことで、ディスパッチャー オブジェクトのセットの任意の部分、あるいはすべてが Signaled に設定されるまで待機することができます。

ディスパッチャー オブジェクトが Signaled 状態に設定されるたびに、カーネルは、そのオブジェクトを待機しているスレッドの状態を準備完了に変更します。 (同期タイマーと同期イベントはこの規則の例外です。同期イベントまたはタイマーが通知されると、待機中のスレッドが 1 つだけ準備完了状態に設定されます。詳細については、「タイマー オブジェクトと DPC」 および「イベント オブジェクト」を参照してください)。準備完了状態のスレッドは、現在の実行時スレッドの優先度と、その優先度を持つ任意のスレッドのプロセッサの現在の可用性に応じて実行するようにスケジュールされます。

ドライバーがディスパッチャー オブジェクトを待機できるタイミング

一般に、ドライバーは、次の状況の少なくとも 1 つが当てはまる場合にのみ、ディスパッチャー オブジェクトが設定されるのを待機することができます。

  • ドライバーが非固定スレッド コンテキストで実行されている。

    これはつまり、待機状態になるスレッドを識別することができます。 実際には、非固定スレッド コンテキストで実行されるドライバー ルーチンは、ドライバーの DriverEntryAddDeviceReinitializeUnload ルーチン、および最上位レベルのドライバーのディスパッチ ルーチンだけです。 これらのルーチンはすべて、システムによって直接呼び出されます。

  • ドライバーが、完全に同期 I/O 要求を実行している。

    つまり、I/O 要求の処理中にドライバーは操作をキューに入れず、その下位ドライバーが要求の処理を完了するまでドライバーは返しません。

また、ドライバーは、DISPATCH_LEVEL と同等以上の IRQL で実行されている場合、待機状態を入力できません。

これらの制限に基づいて、次の規則を使用する必要があります。

  • 任意のドライバーの DriverEntryAddDeviceReinitialize、Unload ルーチンは、ディスパッチャー オブジェクトを待機できます。

  • 最上位レベルのドライバーのディスパッチ ルーチンは、ディスパッチャー オブジェクトを待機できます。

  • 下位レベルのドライバーのディスパッチ ルーチンは、作成、フラッシュ、シャットダウン、閉じる操作、一部のデバイス I/O 制御操作、一部の PnP および電源操作など、I/O 操作が同期している場合に、ディスパッチ オブジェクトを待機できます。

  • 下位レベルのドライバーのディスパッチ ルーチンは、ディスパッチャー オブジェクトが非同期 I/O 操作を完了するのを待機できません。

  • IRQL DISPATCH_LEVEL 以上で実行されているドライバー ルーチンは、ディスパッチャー オブジェクトが Signaled 状態に設定されるのを待機してはなりません。

  • ドライバーは、ディスパッチャー オブジェクトがページング デバイスとの間の転送操作の完了に対して Signaled 状態に設定されるのを待機してはなりません。

  • 通常、読み取り/書き込み要求を処理するドライバー ディスパッチ ルーチンは、ディスパッチャー オブジェクトが Signaled 状態に設定されるのを待機することはできません。

  • デバイス I/O 制御要求のディスパッチ ルーチンは、I/O 制御コードの転送の種類が METHOD_BUFFERED である場合にのみ、ディスパッチャー オブジェクトが Signaled 状態に設定されるまで待機できます。

  • SCSI ミニポート ドライバーでは、カーネル ディスパッチャー オブジェクトを使用しないでください。 SCSI ミニポート ドライバーは、SCSI ポート ライブラリ ルーチンのみを呼び出す必要があります。

他のすべての標準ドライバー ルーチンは、任意のスレッド コンテキストで実行されます。これは、キューに登録された操作を処理したり、デバイスの割り込みを処理したりするためにドライバー ルーチンが呼び出されたときに、現在のスレッドに発生するスレッドのコンテキストです。 さらに、ほとんどの標準ドライバー ルーチンは、DISPATCH_LEVEL か、デバイス ドライバーの場合は DIRQL で、IRQL を上げた状態で実行されます。

必要に応じて、ドライバーは、デバイス専用スレッドを作成し、ドライバーの他のルーチン (ISR または SynchCritSection ルーチンを除く) がディスパッチャー オブジェクトを Signaled 状態に設定し、Not-Signaled 状態にリセットするのを待機することができます。

一般的なガイドラインとして、新しいデバイス ドライバーが I/O 操作中にデバイス状態の変更を待機している間、50 マイクロ秒を超えてストールする必要が頻繁に生じると予想される場合は、デバイス専用スレッドを使用してドライバーを実装することを検討してください。 デバイス ドライバーも最上位レベルのドライバーである場合は、システム ワーカー スレッドを使用し、1 つ以上のワーカー スレッド コールバック ルーチンを実装することを検討してください。 「PsCreateSystemThread」および「ドライバーによって作成されたスレッドを使用したインタロック キューの管理」を参照してください。