スピンロック


スピンロック


IRQLの概念は単一CPU上の同期問題だけを解決することができ、マルチプロセッサプラットフォームでは、他のプロセッサで実行されているコードに干渉されないことを保証することはできません.スピンロック(spin lock)と呼ばれる元のオブジェクトがこの問題を解決することができる.スピンロックを取得するには、あるCPU上で実行されるコードは、まず原子操作を実行する必要があります.この操作は、原子操作であるため、他のCPUがこのメモリ変数にアクセスすることはできません.試験結果がロックが空きであることを示す場合、プログラムはこのスピンロックを取得し、実行を継続する.テスト結果がロックがまだ占有されていることを示す場合、プログラムは小さなサイクルでこの「テストと設定(test-and-set)」操作を繰り返し、「スピン」を開始します.最後に、ロックの所有者は、変数をリセットすることによってこのスピンロックを解放し、待機しているtest−and−set操作は、ロックが解放されたことを呼び出し者に報告する.
スピンロックについて2つの明らかな事実がある.第1に、既にスピンロックを持っているCPUがこのスピンロックを2回目に取得しようとすると、CPUはデッドロックになる.スピンロックには、カウンタの使用(Useカウンタ)または所有者IDが関連付けられていません.ロックまたは占有または空き.ロックが占有されている間に取得すると、ロックが解放されるまで待機します.たまたまCPUがロックを持っている場合、ロックを解除するためのコードは実行されません.CPUをメモリ変数のスピン状態で常に「テストして設定」するためです.
スピンロックに関するもう一つの事実は、CPUがスピンロックを待つ間、何の役にも立たず、待つだけである.したがって、パフォーマンスに影響を与えないように、CPUがこのスピンロックを待っている可能性があるため、スピンロックを持っているときはできるだけ少ない操作をする必要があります.
スピンロックについてはまだ明らかではありませんが、重要な事実があります.DISPATCH以下または等しいことしかできません.LEVELレベルでスピンロックを要求します.スピンロックを持っている間、カーネルはあなたのコードをDISPATCHに引き上げます.LEVELレベルで動作します.内部では、カーネルはDISPATCHよりも高いことができます.LEVELのレベルでスピンロックを取得しますが、あなたも私にはできません.

スピンロックを使用

スピンロックを明確に使用するには、まず非ページングメモリにKSPIN_LOCKオブジェクト割り当てストレージ。次に、KeInitializeSpinLockを呼び出してこのオブジェクトを初期化します。次に、コードがDISPATCH以下で実行されると、LEVELレベルでこのロックを取得し、保護が必要なコードを実行し、最後にスピンロックを解放します。たとえば、デバイス拡張にQLockというスピンロックがあるとします。これを使用して、専用のIRPキューへのアクセスを保護します。AddDevice関数でこのロックを初期化する必要があります。 typedef struct _DEVICE_EXTENSION { ... KSPIN_LOCK QLock; } DEVICE_EXTENSION, *PDEVICE_EXTENSION; ... NTSTATUS AddDevice(...) { ... PDEVICE_EXTENSION pdx = ...; KeInitializeSpinLock(&pdx->QLock); ... } ドライバの他の場所では、あるIRPの派遣関数で、必要なキュー操作コードの周囲でスピンロックを取得(すぐに解放)したと仮定します。この関数は、アップグレードされたIRQL上で実行される期間があるため、非ページングメモリに存在する必要があります。 NTSTATUS DispatchSomething(...) { KIRQL oldirql; PDEVICE_EXTENSION pdx = ...; KeAcquireSpinLock(&pdx->QLock, &oldirql); <--1 ... KeReleaseSpinLock(&pdx->QLock, oldirql); <--2 } KeAcquireSpinLockがスピンロックを取得すると、IRQLもDISPATCH_に昇格します。LEVEL級に上がる。 KeReleaseSpinLockがスピンロックを解放すると、IRQLも元のIRQLレベルに低下する。 コードがDISPATCHにあることを知っていればLEVELレベルでは、スピンロックを取得するために2つの専用関数を呼び出すことができます。この技術はDPC、StartIo、その他DISPATCHで実行するのに適しています。LEVELレベルのドライバルーチン: KeAcquireSpinLockAtDpcLevel(&pdx->QLock); ... KeReleaseSpinLockFromDpcLevel(&pdx->QLock);