SMPマシンでは 、割り込みコンテキストからspin_lock_irqsave
ではなく、使用する必要があります。spin_lock_irq
フラグ(IFを含む)を保存したいのはなぜですか?
私たちに割り込む可能性のある別の割り込みルーチンはありますか?
SMPマシンでは 、割り込みコンテキストからspin_lock_irqsave
ではなく、使用する必要があります。spin_lock_irq
フラグ(IFを含む)を保存したいのはなぜですか?
私たちに割り込む可能性のある別の割り込みルーチンはありますか?
spin_lock_irqsave
これは基本的に、スピンロックを取得する前に割り込み状態を保存するために使用されます。これは、ロックが割り込みコンテキストで取得されると、スピンロックが割り込みを無効にし、ロック解除中に再度有効にするためです。割り込み状態は保存されるため、割り込みを再び復元する必要があります。
例:
spin_lock_irq
割り込みxを無効にし、ロックを取得しますspin_unlock_irq
割り込みxを有効にします。したがって、ロックを解放した後の上記の3番目のステップでは、ロックが取得される前に以前に無効にされていた割り込みxが有効になります。
したがって、割り込みが無効になっていないことが確実な場合にのみ、spin_lock_irq
それ以外の場合は常にを使用する必要がありますspin_lock_irqsave
。
コードがロックを開始する前に割り込みがすでに無効になっている場合は、呼び出すときspin_unlock_irq
に、望ましくない可能性のある方法で割り込みを強制的に再度有効にします。代わりに、現在の割り込み有効化状態も保存し、ロックを解除した後に同じもので割り込みを再度有効化しようとするとflags
、関数は以前の状態を復元するだけです(したがって、必ずしも割り込みを有効化する必要はありません)。spin_lock_irqsave
flags
例spin_lock_irqsave
:
spinlock_t mLock = SPIN_LOCK_UNLOCK;
unsigned long flags;
spin_lock_irqsave(&mLock, flags); // Save the state of interrupt enable in flags and then disable interrupts
// Critical section
spin_unlock_irqrestore(&mLock, flags); // Return to the previous state saved in flags
spin_lock_irq
(irqsaveなしの)例:
spinlock_t mLock = SPIN_LOCK_UNLOCK;
unsigned long flags;
spin_lock_irq(&mLock); // Does not know if interrupts are already disabled
// Critical section
spin_unlock_irq(&mLock); // Could result in an unwanted interrupt re-enable...
spin_lock_irqsave
ほかに必要な理由は、に加えて必要なspin_lock_irq
理由と非常に似ています。これは、RobertLoveによるLinuxKernel DevelopmentSecondEditionから取得したこの要件の適切な説明です。local_irq_save(flags)
local_irq_disable
local_irq_disable()ルーチンは、呼び出し前に割り込みがすでに無効になっている場合は危険です。local_irq_enable()への対応する呼び出しは、最初から割り込みがオフであったにもかかわらず、無条件に割り込みを有効にします。代わりに、割り込みを以前の状態に復元するためのメカニズムが必要です。呼び出しチェーンに応じて、割り込みを有効にした場合と有効にしない場合の両方でカーネル内の特定のコードパスに到達できるため、これは一般的な懸念事項です。たとえば、前のコードスニペットがより大きな関数の一部であると想像してください。この関数が他の2つの関数によって呼び出されていると想像してください。1つは割り込みを無効にし、もう1つは無効にしません。カーネルのサイズと複雑さが増すにつれて、関数に至るまでのすべてのコードパスを知ることが難しくなっているため、割り込みシステムを無効にする前に、割り込みシステムの状態を保存する方がはるかに安全です。次に、割り込みを再度有効にする準備ができたら、単に元の状態に復元します。
unsigned long flags;
local_irq_save(flags); /* interrupts are now disabled */ /* ... */
local_irq_restore(flags); /* interrupts are restored to their previous
state */
これらのメソッドは少なくとも部分的にマクロとして実装されているため、flagsパラメーター(unsigned longとして定義する必要があります)は値によって渡されているように見えることに注意してください。このパラメータには、割り込みシステムの状態を含むアーキテクチャ固有のデータが含まれています。サポートされているアーキテクチャの少なくとも1つがスタック情報を値(ahem、SPARC)に組み込んでいるため、フラグを別の関数に渡すことはできません(具体的には、同じスタックフレームに保持する必要があります)。このため、saveの呼び出しとrestoreの呼び出しは、同じ関数で発生する必要があります。
以前のすべての関数は、割り込みコンテキストとプロセスコンテキストの両方から呼び出すことができます。
割り込みコンテキストで実行されているカーネルコード/スレッドがスリープできないのはなぜですか?これはRobertLovesの記事にリンクしています、私はこれを読みました:
一部の割り込みハンドラー(Linuxでは高速割り込みハンドラーとして知られています)は、ローカルプロセッサ上のすべての割り込みを無効にして実行されます。これは、割り込みハンドラーが可能な限り迅速に中断することなく実行されるようにするために行われます。さらに、すべての割り込みハンドラは、すべてのプロセッサで現在の割り込みラインを無効にして実行されます。これにより、同じ割り込みラインの2つの割り込みハンドラが同時に実行されなくなります。また、デバイスドライバーの作成者が、プログラミングを複雑にする再帰的な割り込みを処理する必要がなくなります。
以下は、Linuxカーネル4.15.18のコードの一部であり、spiin_lock_irq()が__raw_spin_lock_irq()を呼び出すことを示しています。ただし、コードの以下の部分に示されているように、フラグは保存されませんが、割り込みは無効になります。
static inline void __raw_spin_lock_irq(raw_spinlock_t *lock)
{
local_irq_disable();
preempt_disable();
spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);
LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock);
}
以下のコードは、spin_lock_irqsave()を示しています。これは、フラグの現在のステージを保存してから、無効化をプリエンプトします。
static inline unsigned long __raw_spin_lock_irqsave(raw_spinlock_t *lock)
{
unsigned long flags;
local_irq_save(flags);
preempt_disable();
spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);
/*
* On lockdep we dont want the hand-coded irq-enable of
* do_raw_spin_lock_flags() code, because lockdep assumes
* that interrupts are not re-enabled during lock-acquire:
*/
#ifdef CONFIG_LOCKDEP
LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock);
#else
do_raw_spin_lock_flags(lock, &flags);
#endif
return flags;
}
この質問は、誤った主張から始まります。
On an SMP machine we must use spin_lock_irqsave and not spin_lock_irq from interrupt context.
これらのいずれも、割り込みコンテキストから、SMPまたはUPで使用しないでください。とspin_lock_irqsave()
はspin_lock()
いえ、より普遍的であるため(割り込みコンテキストと通常のコンテキストの両方で使用できます)、割り込みコンテキストから使用できますが、割り込みコンテキストから、spin_lock_irq()
または通常のコンテキストから使用することになっていspin_lock_irqsave()
ます。このSMPまたはUPの場合、割り込みコンテキストでの使用spin_lock_irq()
はほとんどの場合間違っています。ほとんどの割り込みハンドラーはローカルでIRQを有効にして実行されるため、機能する可能性がありますが、試してはいけません。
更新:この回答を誤解している人がいるので、割り込みコンテキストロックの対象と対象外を説明しているだけであることを明確にしておきます。ここでは、割り込みコンテキストでのみspin_lock()
使用する必要
があるという主張はありません。プロセスコンテキストでも使用できます。たとえば、割り込みコンテキストでロックする必要がない場合などです。