c - 操作系统:在中断被阻塞的情况下切换到另一个进程不是错误的做法吗?
问题描述
我在 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
,它将控制流传递给另一个进程。
然而,让我感到困惑的是,在这里我们将切换到另一个进程,其中一些中断被阻塞,这似乎很容易出错,因为另一个进程应该期待默认行为。那么这是一段正确编写的代码(如果是,为什么?)还是只是一个错误编写的代码,会导致意外行为?
解决方案
我假设磁盘驱动器的中断处理程序将是唤醒(&bh->b_wait)的中断处理程序,如果在等待此块的进程中未禁用中断,则可能导致错过唤醒。
请记住,条件变量(sleep_on、wakeup)没有记忆:sleep_on 将挂起直到调用 wakeup;如果在 sleep_on 之前调用唤醒并不重要。
从测试 bh->b_lock 的时间点开始,调用者正在与中断处理程序竞争;因此 cli(或者,更典型的 unix splbio())会阻塞中断处理程序,从而防止竞争。
由于内核将中断状态(掩码、优先级、...)与进程状态一起保存,所以当 sleep_on 导致重新调度时,很可能会重新启用中断;或者至少最终会。磁盘中断最终会运行,唤醒这个进程。
当这个进程被重新调度时,它保存的中断状态(禁用)将被恢复,这样 b_lock 的测试和分配也将防止磁盘中断处理程序的干扰。
推荐阅读
- html - 是否可以在画布内的选定区域内填充图像?
- java - 在循环中使用 if 语句?- 加工
- angular - 我们是否需要付费的 firebase/firestore 帐户来实施条带支付?
- wpf - “在 wpf xaml 中使用或不使用 ResourceDictionary 来包装我的资源”有什么区别吗?
- google-chrome - 如何在chrome中的当前标签之后立即打开一个新标签?
- c# - 区分由用户输入触发的事件与。UWP 背后的代码
- javascript - 当从输入框中删除最后一个字符时,事件未在剑道网格和角度 5 中触发?
- mysql - Mysql 文档 WHERE 子句优化:索引使用的常量表达式只计算一次
- linux - 过滤 perf.data (linux perf profiler) 文件的时间间隔
- mod-rewrite - 将移动文件的请求重定向到子目录