Linux kernel 为什么我们需要中断上下文?

Linux kernel 为什么我们需要中断上下文?,linux-kernel,kernel,interrupt-handling,Linux Kernel,Kernel,Interrupt Handling,我有疑问,为什么我们需要中断上下文?一切都告诉我们什么是属性,但没有人解释我们为什么提出这个概念 与同一概念相关的另一个疑问是,如果我们不在中断处理程序中禁用中断,那么在中断上下文中运行此中断处理程序代码有什么用?中断上下文与进程上下文有根本不同: 它与过程无关;特定进程不提供中断服务,内核提供。即使进程将被中断,它对中断本身或为其服务的例程的任何参数都没有意义。因此,中断上下文至少在概念上必须不同于进程上下文 另外,如果一个中断在一个进程上下文中被服务,并且(重新)在以后的时间安排一些工作,那

我有疑问,为什么我们需要中断上下文?一切都告诉我们什么是属性,但没有人解释我们为什么提出这个概念


与同一概念相关的另一个疑问是,如果我们不在中断处理程序中禁用中断,那么在中断上下文中运行此中断处理程序代码有什么用?

中断上下文与进程上下文有根本不同:

  • 它与过程无关;特定进程不提供中断服务,内核提供。即使进程将被中断,它对中断本身或为其服务的例程的任何参数都没有意义。因此,中断上下文至少在概念上必须不同于进程上下文

  • 另外,如果一个中断在一个进程上下文中被服务,并且(重新)在以后的时间安排一些工作,那么它将在什么上下文中运行?最初的过程可能在以后的时间甚至不存在。因此,出于实际原因,我们需要一些独立于过程的上下文

  • 中断处理必须快速;您的中断处理程序已中断(d'oh)其他一些代码。重要的工作应该被推到中断处理程序之外的“下半部分”。无论是在用户空间还是在内核空间,阻止进程进行与其无关的工作都是不可接受的

  • 禁用中断是指在注册ISR时,您可以(实际上是在2.6.36之前)请求禁用中断。回想一下,处理程序可以同时在多个CPU上提供中断服务,因此可以与自身竞争。无法禁用不可屏蔽中断(NMI)

  • 为什么我们需要中断上下文

    首先,我们所说的中断上下文是什么意思?上下文通常是一种状态。国家有两个不同的概念

    CPU上下文 每个CPU架构都有一个处理中断的机制。每个系统中断都可能有一个单独的中断向量,或者CPU/硬件可能能够根据中断源将CPU分配到特定地址。还有屏蔽/取消屏蔽中断的机制。每个中断可能单独屏蔽,或者整个CPU可能有一个全局屏蔽。最后,还有一个实际的CPU状态。有些可能有单独的堆栈、寄存器集和CPU模式,这意味着一些内存和其他特权。您的问题是关于Linux的,它必须处理所有情况

    Linux上下文 通常,所有架构都有一个单独的内核堆栈、进程上下文(ala
    ps
    )和每个进程的VM(虚拟内存)上下文。VM对用户和内核模式具有不同的权限。为了使内核始终运行,它必须为设备上的所有进程保持映射。内核线程是一种特殊情况,它不太关心VM,因为它具有特权,可以访问所有内核内存。但是,它有一个单独的堆栈和进程上下文。发生异常时,用户寄存器通常存储在内核堆栈上。例外情况至少包括页面错误、系统调用和中断。这些项目可能会嵌套。也就是说,您可以从用户空间调用
    write()
    ,当内核传输用户缓冲区时,读取一些交换的用户空间数据可能会出现页面错误。页面错误可能再次需要为中断提供服务

    中断递归 Linux general希望您将中断屏蔽为VM,执行和进程管理(上下文和上下文切换)必须协同工作。为了使VM保持简单,内核堆栈和进程上下文通常根于单个4k(或8k)区域,该区域是单个VM页面。始终映射此页面。通常,在为中断提供服务时,所有CPU都将从中断模式切换到系统模式,并使用与所有其他异常相同的内核堆栈。堆栈很小,因此允许递归(以及较大的堆栈分配)可能会炸毁堆栈,从而导致内核级别的堆栈溢出。这很糟糕

    原子性 许多内核结构需要在多个总线周期内保持一致;也就是说,添加元素时,链表必须同时更新
    prev
    next
    节点链接。这样做的典型机制可能是屏蔽中断,以确保代码是原子的。某些CPU可能允许总线锁定,但这不是通用的。上下文切换代码也必须是原子的。中断的结果通常是重新调度。也就是说,内核中断处理程序可能已确认磁盘控制器并开始写入操作。然后内核线程可以计划从原始用户空间写入更多缓冲数据
    write()

    任何时候发生的中断都可能打破某些子系统对原子行为的假设。禁止他们使用子系统,而不是允许中断使用子系统

    总结 Linux必须处理三件事。当前进程执行上下文、当前虚拟内存布局和硬件请求。他们都需要共同努力。由于中断可能随时发生,因此它们发生在任何流程上下文中。在中断中使用
    sleep()。允许在中断中分配大堆栈可能会破坏有限的堆栈。这些设计选择限制了Linux中断处理程序中可能发生的情况。各种配置选项可以允许重入中断,但这通常是特定于CPU的

    保持上半部分(现在的主中断处理程序)较小的好处是减少了中断延迟。繁忙的工作应该在内核线程中完成。一种中断服务程序