セマフォ オブジェクト

どのドライバもセマフォオブジェクトを使用して、ドライバが作成したスレッドと他のドライバルーチン間の操作を同期させることができます。 例えば、ドライバ専用のスレッドは、ドライバに対する未処理のI/O要求がないときにそれ自身を待機状態にし、ドライバのディスパッチルーチンは、IRPをキューに入れた直後にセマフォを通知状態に設定する場合があります。

I/O操作を要求するスレッドのコンテキストで実行される最上位ドライバのディスパッチルーチンは、ディスパッチルーチン間で共有されるリソースを保護するためにセマフォを使用する場合があります。 同期I/O操作のための下位ドライバのディスパッチルーチンも、ディスパッチルーチンのサブセット間、またはドライバが作成したスレッドで共有されるリソースを保護するためにセマフォを使用する場合があります。

セマフォオブジェクトを使用するドライバは、セマフォを待機またはリリースする前に KeInitializeSemaphore を呼び出す必要があります。 次の図は、スレッドを持つドライバがセマフォオブジェクトを使用する方法を示しています。

diagram illustrating waiting for a semaphore object.

前の図が示すように、このようなドライバはセマフォオブジェクトを常駐させるためのストレージを提供しなければなりません。 ドライバーは、ドライバーが作成したデバイス オブジェクトの デバイス拡張 、コントローラー拡張 ( コントローラー オブジェクトを使用する場合)、またはドライバーによって割り当てられた非ページ プールを使用できます。

ドライバの AddDevice ルーチン が KeInitializeSemaphoreを呼び出す場合、セマフォオブジェクト用のドライバの常駐ストレージへのポインタを渡す必要があります。 さらに、呼び出し元はセマフォオブジェクトに Count を指定する必要があります。Countは前の図に示すように、セマフォオブジェクトの初期状態(通知の場合は0以外)を決定します。

呼び出し側はまた、セマフォに次ぎのいずれかの Limit を指定する必要があります。

  • Limit = 1

    このセマフォが通知状態に設定されると、セマフォが通知状態に設定されるのを待っているスレッドが実行可能になり、セマフォによって保護されているリソースにアクセスできるようになります。

    このタイプのセマフォは バイナリセマフォオ とも呼ばれます。これは、スレッドがセマフォで保護されたリソースへの排他的なアクセス権を持つか持たないかのどちらかであるためです。

  • Limit > 1

    このセマフォが通知状態に設定されると、セマフォが通知状態に設定されるのを待っているスレッドが実行可能になり、セマフォによって保護されているリソースにアクセスできるようになります。

    このタイプのセマフォは カウントセマフォ と呼ばれますが、これはセマフォを通知状態に設定するルーチンが、待機しているスレッドの状態を待機状態から準備完了状態に変更させることができるスレッドの数も指定するからです。 そのような待機スレッドの数は、セマフォが初期化されたときに設定された Limit か、このプリセット Limitより少ない数になります。

単一のドライバ作成スレッドを持つデバイスや中間ドライバはほとんどなく、セマフォの獲得やリリースを待つスレッドの集合を持つものはさらに少数です。 システムが提供するドライバでセマフォオブジェクトを使用しているものはほとんどなく、使用しているものでも、バイナリセマフォを使用しているものはさらに少数です。 バイナリーセマフォは mutexオブジェクトと機能が似ているように見えるかもしれませんが、バイナリーセマフォはSMPマシンで動作するシステムスレッドに対してmutexオブジェクトのようなデッドロックに対するビルトインの保護を提供しません。

初期化されたセマフォを持つドライバがロードされた後、共有リソースを保護するセマフォ上の操作を同期させることが可能です。 例えば、システムフロッピーコントローラのドライバのように、IRPのキューイングを管理するデバイス専用スレッドを持つドライバは、前の図に示すように、セマフォ上のIRPキューイングを同期させることができます。

  1. スレッドは、 KeWaitForSingleObject を、初期化されたセマフォオブジェクトのドライバ提供のストレージへのポインタで呼び出し、待機状態にします。

  2. デバイスのI/O操作を要求するIRPが来始めます。 ドライバのディスパッチルーチンは、そのようなIRPをスピンロック制御下のインターロックされたキューに挿入し、セマフォオブジェクトへのポインタを持つ KeReleaseSemaphore 、スレッドに対するドライバが決定した優先度ブースト (Increment、 前の図に示されているように)、 各IRPがキューに入れられるときにセマフォのカウントに追加される Adjustment の1、およびブール値 Wait (これは FALSEに設定されたもの)を呼び出します。 非ゼロのセマフォカウントは、セマフォオブジェクトを通知状態に設定し、それによって待機スレッドを準備完了状態に変更します。

  3. カーネルは、優先順位の高いスレッドが待機状態になく、より高いIRQLで実行すべきカーネルモードルーチンが存在しない場合にのみ、プロセッサが使用可能になるとすぐに実行のためにスレッドをディスパッチします。

    スレッドは、スピンロック制御下のインターロックされたキューからIRPを削除し、それを他のドライバ ルーチンに渡してさらに処理し、 KeWaitForSingleObject を再度呼び出します。 セマフォがまだ通知状態に設定されている場合(つまり、カウントがゼロ以外のままであり、ドライバのインターロックされたキューにIRPがあることを示している)、カーネルはスレッドの状態を再び待機から準備状態に変更します。

    このようにカウントセマフォを使用することで、そのようなドライバーのスレッドは、そのスレッドが実行されるたびに、インターロックされたキューから削除されるIRPがあることを「知って」います。

KeReleaseSemaphoreを呼び出す際の IRQL の管理に固有の情報については、 KeReleaseSemaphoreの備考セクションを参照してください。

PASSIVE_LEVEL よりも大きな IRQL で実行される標準ドライバ・ルーチンは、システムをダウンさせることなく、ディスパッチャ・オブジェクト上でゼロ以外のインターバルを待つことはできません。詳細は Kernel Dispatcher Objects を参照してください。 しかし、そのようなルーチンは、DISPATCH_LEVEL以下のIRQLで実行中に KeReleaseSemaphore を呼び出すことができます。

標準ドライバー・ルーチンが実行されるIRQLの概要については Managing Hardware Prioritiesを参照してください。 特定のサポートルーチンのIRQL要件については、そのルーチンのリファレンスページを参照してください。