spin lock は単純な排他制御機能です。排他制御をしたい一連の処理の前後に spin_lock*(), spin_unlock*() 関数を置いて使います。排他制御をしている時間が短い場合、効率的に使用できます。排他制御を獲得するまで状態変数を操作し続け(特殊な読み書き手順を続け)ます。排他制御時間が長いか、頻度が高い場合、状態変数を操作する時間が長くなり、本来行うべき演算のための時間を失います。使い分けと詳細なドキュメントは Documentation/locking/spinlocks.txt, Documentation/DocBook/kernel-locking/index.html にあります。
spin lock には次のような種類があります。排他制御を必要とするコンテキストに応じて使い分けてください。/Documentation/DocBook/kernel-locking/cheatsheet.html に早見表があります。
lock | unlock | ハードウエア割り込み[*3] | softirq[*3] | プリエンプション[*3] |
spin_lock_irqsave() | spin_unlock_irqrestore() | 退避 - 復旧 禁止 - 許可 | 禁止 - 許可[*1] | 禁止 - 許可[*2] |
spin_lock_irq() | spin_unlock_irq() | 禁止 - 許可 | 禁止 - 許可[*1] | 禁止 - 許可[*2] |
spin_lock() | spin_unlock() | そのまま | そのまま | 禁止 - 許可[*2] |
spin_lock_bh() | spin_unlock_bh() | そのまま | 禁止 - 許可[*2] | 禁止 - 許可[*2] |
[*1] ハードウエア割り込み禁止に連動しています。
[*2] カウンタを up/down しています。カウンタが初期値(多くの場合 0)より大きければ禁止、初期値に一致すれば許可となります。
[*3] {割り込み|softirq|プリエンプション} の禁止/許可はローカル CPU (spin lock 関数を実行した CPU)が対象です。
数多く有る spin lock のうちどのコンテキストでも使える spin_lock_irqsave(), spin_unlock_irqrestore() を主に使っています。spin_lock_irqsave() spin_unlock_irqrestore() は状況によってはしなくても良い割り込み許可フラグの保存・復帰を無条件にします。無駄な処理かもしれません。それでも、実行時間の無駄よりは、spin_lock_irqsave(), spin_unlock_irqrestore() を呼び出した元のコンテキストが何か留意しながらコードを書くより安全な方法を選んでいます。
spin_lock_irqsave() を呼び出し、関数から戻ってくると次の様な状態になっています。
spin_unlock_irqrestore() を呼び出し、関数から戻ってくると次の様な状態になっています。
spin_lock_irqsave(), spin_unlock_irqrestore() の注意点を列挙します。