我怀疑,为什么我们需要中断上下文?一切都说明了什么是属性,但没有人解释为什么我们想出这个概念?
与同一概念相关的另一个疑问是,如果我们没有在中断处理程序中禁用中断,那么在中断上下文中运行这个中断处理程序代码有什么用?
答案 0 :(得分:4)
为什么我们需要中断上下文?
首先,中断上下文是什么意思?上下文通常是一种状态。有两个独立的国家概念。
每个CPU架构都有一个处理中断的机制。可能有一个单中断向量调用每个系统中断,或者CPU /硬件可能能够根据中断源将CPU调度到特定地址。还有用于屏蔽/取消屏蔽中断的机制。每个中断可以单独屏蔽,也可以为整个CPU设置全局屏蔽。最后,有一个实际的CPU状态。有些可能有单独的堆栈,寄存器集和CPU模式,这意味着一些内存和其他权限。你的问题一般是Linux,它必须处理所有情况。
通常,所有体系结构都为每个进程分别具有内核堆栈,进程上下文(ala ps
)和 VM (虚拟内存)上下文。 VM 对用户和内核模式具有不同的权限。为了使内核始终运行,必须为设备上的所有进程保持映射。 内核线程是一个特殊情况,它不关心 VM ,因为它具有特权并且可以访问所有内核内存。但是,它确实有一个单独的堆栈和进程上下文。当发生 exception 时,用户寄存器通常存储在内核堆栈中。例外情况至少是页面错误,系统调用和中断。这些物品可能会嵌套。即,您可以从用户空间调用write()
,而在内核正在传输用户缓冲区时,它可能会页面错误以读取一些换出的用户空间数据。 页面错误可能必须再次服务中断。
Linux general希望您将中断屏蔽为 VM ,execptions和进程管理(上下文和上下文切换)必须协同工作。为了使 VM 保持简单,内核堆栈和进程上下文通常植根于单个4k(或8k)区域,这是一个 VM 页面。此页面始终映射。通常,在处理中断时,所有CPU都将从中断模式切换到系统模式,并使用与所有其他异常相同的内核堆栈。堆栈很小,所以允许递归(和大堆栈分配)可以炸毁堆栈,导致内核级别的堆栈溢出。这很糟糕。
许多内核结构需要在多个总线周期内保持一致;即,链接列表在添加元素时必须更新prev
和next
节点链接。执行此操作的典型机制可能是屏蔽中断,以确保代码是原子的。某些CPU可能允许总线锁定,但这不是通用的。上下文切换代码也必须是原子的。中断的后果通常是重新安排。即,内核中断处理程序可能确认磁盘控制器并启动写操作。然后内核线程可以安排从原始用户空间write()
写入更多缓冲数据。
任何时候发生的中断都可能会破坏某些子系统对原子行为的假设。不允许中断使用子系统,禁止使用它。
sleep()
等会使随机进程进入休眠状态。允许在中断中进行大量堆栈分配可能会破坏有限的堆栈。这些设计选择限制了Linux中断处理程序中可能发生的情况。各种配置选项可以允许重入中断,但这通常是CPU特定的。
保持上半部分的好处,现在主要的中断处理程序很小,中断延迟减少了。繁忙的工作应该在内核线程中完成。需要取消屏蔽中断的中断服务程序已经对Linux生态系统有些反社会性。该工作应该放在内核线程中。
Linux中断上下文在某种意义上确实不存在。它只是一个可能在任何进程上下文中发生的CPU中断。 Linux中断上下文实际上是由此产生的一组编码限制。
答案 1 :(得分:3)
中断上下文与进程上下文根本不同:
它与流程无关;一个特定的进程不会中断,内核就是这样。即使进程将被中断,它对中断本身的任何参数或将为其提供服务的例程都没有意义。因此,中断上下文至少必须与过程上下文概念不同。
此外,如果要在进程上下文中处理中断,并且(重新)计划某些工作稍后进行,那么会运行什么上下文?原来的过程甚至可能不会在以后存在。因此,我们需要一些上下文,它独立于实际原因的流程。
中断处理必须快速;你的中断处理程序已经中断(d'哦)其他一些代码。重要的工作应该被推到中断处理程序之外的#34;下半部分"。阻止在用户或内核空间中甚至无法远程关注的工作流程是不可接受的。
在注册ISR时,您可以禁用中断(实际上可以,在2.6.36之前)。回想一下,处理程序可以同时为多个CPU提供中断,因此可以自行竞争。不能禁用非屏蔽中断(NMI)。