irqs_disabled()がプリエンプションを無効にする安全でない方法であるのはなぜですか?

irqs_disabled()がプリエンプションを無効にする安全でない方法であるのはなぜですか?

プリエンプティブカーネルでの適切なロック:カーネルコードのプリエンプションを安全に保つ記事によると、

しかし、「irqsを無効にする」は、プリエンプションを無効にする基本的に安全ではない方法であることに注意してください。プリエンプション数を0に減らすspin_unlock()は、スケジュール変更をトリガーできます。単純な printk() がスケジュール変更を引き起こす可能性があります。

IRQがディセーブルの場合、そのCPUコアのタイマー割り込みもディスエーブルにする必要があります。当然、スケジューラを無効にする必要があります(プリエンプション)。プリエンプションを無効にする安全でない方法でirqsdisabled()を呼び出すのはなぜですか?

また、printk()はどのようにスケジュール変更をトリガーしますか?

答え1

はい、IRQ がディセーブルの場合、タイマ割り込みはディセーブルになり、ジョブのスケジュールはもはや発生しません。安全でない部分は「if」です。無効なIRQ​​に依存する場合は、IRQが無効になっているときに実行されるすべてのコードがそれに準拠していることを絶対に確認する必要があります。これはカーネルでは非常に難しいかもしれません。Spinlockはそれ自体でプリエンプションを無効にして有効にします。(場合によってはIRQと一緒に)多くのコードがロックを使用します。printk(ログメッセージが混乱しないようにするために)ロックが解除されるたびにIRQが無効になっていても、スケジュールをキャッチする危険があります(ロックを待つコードの実行)。preempt_enable()明示的な呼び出し__preempt_schedule()カウンタが0に達すると、タイマ割り込みは不要です。

したがって、特に将来の保証の観点から適切なプリエンプションサポートを使用する方が安全です。現在作成中のコードの制約に精通しているかもしれませんが、他の人はそれを変更できません(そして「他の人」には「6」が含まれます)。数ヶ月以内にあなたは”)。

答え2

これは、タイマー割り込み(または通常は割り込み)がカーネルプリエンプションの唯一の原因ではないためです。プリエンプションは、明示的に無効になることを期待するいくつかの関数(cond_resched()など)によって引き起こされる可能性があります。

関連情報