どのドライバーでも、セマフォ オブジェクトを使用して、ドライバーによって作成されたスレッドとその他のドライバー ルーチンの間で操作を同期できます。 たとえば、ドライバー専用スレッドは、ドライバーの未処理の I/O 要求がない場合に待機状態に自分自身を配置する可能性があります、ドライバーのディスパッチ ルーチンは、IRP をキューに入れた直後に、セマフォを Signaled 状態に設定する可能性があります。
I/O 操作を要求するスレッドのコンテキストで実行される最上位レベルのドライバーのディスパッチ ルーチンは、セマフォを使用してディスパッチ ルーチン間で共有されるリソースを保護する場合があります。 同期 I/O 操作の下位レベルのドライバー ディスパッチ ルーチンでは、セマフォを使用して、ディスパッチ ルーチンのそのサブセット間またはドライバーによって作成されたスレッドで共有されるリソースを保護することもできます。
セマフォ オブジェクトを使用するドライバーは、セマフォ 待機または解放する前に、KeInitializeSemaphore を呼び出す必要があります。 次の図は、スレッドを持つドライバーがセマフォ オブジェクトを使用する方法を示しています。
前の図に示すように、このようなドライバーはセマフォ オブジェクトのストレージを提供する必要があります。これは常駐する必要があります。 ドライバーは、ドライバーが作成したデバイス オブジェクトの デバイス拡張機能、コントローラー オブジェクトを使用する場合はコントローラー拡張機能、またはドライバーによって割り当てられた非ページ プールを使用できます。
ドライバーの AddDevice ルーチンが KeInitializeSemaphore 呼び出すときは、セマフォ オブジェクトのドライバーの常駐ストレージへのポインターを渡す必要があります。 さらに、呼び出し元は、前の図に示すように、セマフォ オブジェクトの Count を指定する必要があります。これは、その初期状態を決定します (Signaled の場合は 0 以外)。
呼び出し元は、セマフォの 制限 も指定する必要があります。これは、次のいずれかになります。
制限 = 1
このセマフォが Signaled 状態に設定されると、セマフォが Signaled 状態に設定されるのを待機している 1 つのスレッドが実行の対象となり、セマフォによって保護されているリソースにアクセスできるようになります。
この種類のセマフォは、セマフォで保護されたリソースへの排他的アクセス権をスレッドに持っているか、または持っていないため、バイナリ セマフォ とも呼ばれます。
制限 > 1
このセマフォが Signaled 状態に設定されている場合、セマフォ オブジェクトが Signaled 状態に設定されるのを待機している一部のスレッドは実行の対象となり、セマフォによって保護されているリソースにアクセスできます。
セマフォを Signaled 状態に設定するルーチンは、待機中のスレッドの状態を待機から準備に変更できる数も指定するため、この種類のセマフォは カウント セマフォ と呼ばれます。 このような待機中のスレッドの数は、セマフォが初期化されたときに設定された 制限、またはこのプリセット 制限よりも少ない数にすることができます。
ドライバーが作成したスレッドが 1 つだけのデバイスまたは中間ドライバーはほとんどありません。セマフォが取得または解放されるのを待つ可能性のあるスレッドのセットがさらに少なくなります。 セマフォ オブジェクトを使用するシステム提供のドライバーは少なく、バイナリ セマフォを使用するドライバーは少なくなります。 バイナリ セマフォは、ミューテックス オブジェクトと機能が似ているように見えるかもしれませんが、バイナリ セマフォでは、SMP マシンで実行されているシステム スレッドに対してミューテックス オブジェクトが持つデッドロックに対する組み込みの保護は提供されません。
初期化されたセマフォを持つドライバーが読み込まれた後、共有リソースを保護するセマフォに対する操作を同期できます。 たとえば、システム フロッピー コントローラー ドライバーなどの IRP のキューを管理するデバイス専用スレッドを持つドライバーは、前の図に示すように、セマフォで IRP キューを同期する可能性があります。
スレッドは、keWaitForSingleObjectを呼び出し、初期化されたセマフォ オブジェクトが待機状態になるまで、ドライバーが提供するストレージへのポインターを指定します。
デバイスの I/O 操作を必要とする IRP が入り始めます。 ドライバーのディスパッチ ルーチンは、スピン ロック制御下のインターロック されたキューに各 IRP を挿入し、セマフォ オブジェクトへのポインター、スレッドのドライバーによって決定された優先度ブースト (前の図に示すように、インクリメント)、各 IRP がキューに登録されるときにセマフォのカウントに追加される 1 の 調整 を持つ KeReleaseSemaphoreを呼び出します。 ブール 待機 FALSE をに設定します。 セマフォカウントが 0 以外の場合、セマフォ オブジェクトは Signaled 状態に設定され、待機中のスレッドの状態が準備完了に変更されます。
カーネルは、プロセッサが使用可能になるとすぐに実行のためにスレッドをディスパッチします。つまり、優先度の高い他のスレッドは現在準備完了状態であり、より高い IRQL で実行されるカーネル モード ルーチンはありません。
スレッドは、スピン ロック制御下のインターロック されたキューから IRP を削除し、さらに処理するために他のドライバー ルーチンに渡し、KeWaitForSingleObject 再度呼び出。 セマフォがまだ Signaled 状態に設定されている場合 (つまり、その数は 0 以外のままであり、ドライバーのインターロック キューに IRP が多く存在することを示します)、カーネルは再びスレッドの状態を待機から準備に変更します。
この方法でカウント セマフォを使用すると、このようなドライバー スレッドは、そのスレッドが実行されるたびに、インターロックされたキューから削除される IRP があることを "認識" します。
KeReleaseSemaphoreを呼び出すときの IRQL の管理に固有の情報については、「KeReleaseSemaphoreの解説」セクションを参照してください。
PASSIVE_LEVELより大きい IRQL で実行される標準ドライバー ルーチンは、システムを停止せずにディスパッチャー オブジェクトで 0 以外の間隔を待機することはできません。詳細については カーネル ディスパッチャー オブジェクトの を参照してください。 ただし、このようなルーチンは、DISPATCH_LEVEL以下の IRQL で実行しているときに、KeReleaseSemaphore を呼び出すことができます。
標準ドライバー ルーチンを実行する IRQL の概要については、「ハードウェア優先度の管理を参照してください。 特定のサポート ルーチンの IRQL 要件については、ルーチンのリファレンス ページを参照してください。