首页 > 解决方案 > 操作系统:在中断被阻塞的情况下切换到另一个进程不是错误的做法吗?

问题描述

我在 Linux 0.11 内核中看到磁盘上读取的这段代码:

static inline void lock_buffer(struct buffer_head * bh)
{
    cli();
    while (bh->b_lock)
        sleep_on(&bh->b_wait);
    bh->b_lock=1;
    sti();
}

IIUC,cli()将阻止中断(不阻止所有如这里解释:https ://c9x.me/x86/html/file_module_x86_id_31.html,但仍然阻止一些中断,这意味着它改变了默认行为)。

并将sleep_on调用schedule,它将控制流传递给另一个进程。

然而,让我感到困惑的是,在这里我们将切换到另一个进程,其中一些中断被阻塞,这似乎很容易出错,因为另一个进程应该期待默认行为。那么这是一段正确编写的代码(如果是,为什么?)还是只是一个错误编写的代码,会导致意外行为?

标签: clinuxoperating-systeminterrupt

解决方案


我假设磁盘驱动器的中断处理程序将是唤醒(&bh->b_wait)的中断处理程序,如果在等待此块的进程中未禁用中断,则可能导致错过唤醒。

请记住,条件变量(sleep_on、wakeup)没有记忆:sleep_on 将挂起直到调用 wakeup;如果在 sleep_on 之前调用唤醒并不重要。

从测试 bh->b_lock 的时间点开始,调用者正在与中断处理程序竞争;因此 cli(或者,更典型的 unix splbio())会阻塞中断处理程序,从而防止竞争。

由于内核将中断状态(掩码、优先级、...)与进程状态一起保存,所以当 sleep_on 导致重新调度时,很可能会重新启用中断;或者至少最终会。磁盘中断最终会运行,唤醒这个进程。

当这个进程被重新调度时,它保存的中断状态(禁用)将被恢复,这样 b_lock 的测试和分配也将防止磁盘中断处理程序的干扰。


推荐阅读