2

spin_lock_irqsaveローカル割り込みを無効にした後、プリエンプションを無効にする必要があるのはなぜですか。

static inline unsigned long __raw_spin_lock_irqsave(raw_spinlock_t *lock)
{
    unsigned long flags;

    local_irq_save(flags);
    preempt_disable(); ===> can preemption happen with interrupt disabled?
    spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);
    ...
}

プリエンプションは、割り込みが有効になっている場合にのみ可能であるべきです。したがって、割り込みを無効にした後のプリエンプションについて心配する必要はありません。

4

1 に答える 1

1

割り込みの状態に関係なく、プリエンプションが明示的に無効にされていない限り、プリエンプションを引き起こす関数が存在するためです。プリエンプションが許可されていない場合は、明示的に無効にされ、関数はプリエンプトされないという前提があります。代わりに割り込みを使用してプリエンプションを無効にすると、この仮定に違反します。

そのような関数の 1 つが cond_resched() で、core.c の _cond_resched() を呼び出します ( https://elixir.bootlin.com/linux/v5.9-rc5/source/kernel/sched/core.c#L6116 ) 。

プリエンプションが有効になっているかどうかを確認し、スケジューラを呼び出します。この関数はカーネル内のさまざまな場所から呼び出され、そのうちの 1 つを誤ってトリガーして、スピンロックで保護されたクリティカル セクションを壊してしまう可能性があります。

さらに、スピンロックを無効にする割り込みは、クリティカルセクションが割り込みハンドラーからアクセスされる可能性があることを意味します。cond_resched() を使用して誤ってプリエンプションをトリガーした場合、プロセスがスケジュールされたバック割り込みを取得すると、再び有効になります。ロックを取得しようとする割り込みが発生すると、デッドロックが発生します。

于 2020-09-17T13:50:46.510 に答える