Linux内核18-中断和异常的嵌套处理

2022-08-15 15:49:31 浏览数 (1)

讲解这部分之前,我们先阐述一个概念-内核控制路径:就是一段在内核态执行的代码,比如说,异常处理程序,中断处理程序,系统调用处理,内核线程等等在内核态执行的代码。所以,内核态程序被激活的方式有:

  1. 系统调用(异常的一种)
  2. 异常
  3. 中断
  4. 内核线程

上面的任意一种方式,都可以让CPU执行内核态的代码。比如,I/O设备引发一个中断,相应的内核态程序,首先,应该是保存内核态堆栈中的CPU寄存器的内容;然后,执行中断处理程序;最后,再恢复这些寄存器的内容。所以,在后面的描述中,我们使用内核控制路径这个术语代替一段可执行的内核态代码这种表述。使用内核控制路径的好处就是,它是从英语直译过来的,可能会更好地表达程序代码执行的顺序性,是一个过程;这样在描述中断嵌套时更有意义。

内核控制路径可以任意嵌套;如下图所示,用户态的程序被中断打断,进入内核态响应中断;而这时候又来了其它中断,就会响应最新的中断,以此类推;但是,执行完一个中断处理程序之后,会回到之前的状态执行。这样,最后又回到了用户态。

图4-3 内核控制路径的一个嵌套异常的示例

允许内核控制路径嵌套的代价就是中断处理程序不能阻塞,也就是说,中断处理程序运行时不能发生进程切换。恢复执行嵌套内核控制路径的所有数据都存储在内核态堆栈中,而该堆栈又和当前进程紧紧绑定在一起。通俗的说,中断处理程序相当于当前进程的资源,切换进程之前该中断资源必须释放掉。

假设内核没有bug,那么大部分的异常发生在用户态。实际上,要么是编程错误,要么是调试器故意触发的。而页错误异常发生在内核态,它是内核在访问物理地址时不存在引发的异常。处理这样的异常,内核挂起当前进程,切换到新进程,直到该请求页可用。因为页错误异常绝不会引发进一步的异常,所以,有关联的内核控制路径最多是2个(第一个是系统调用造成的,第二个是页错误造成的)。也就是说,页错误的异常最多嵌套2层。

和异常相反,尽管内核代表当前进程处理这些中断,但是,I/O设备引发的中断和当前进程没有直接数据引用的关系。事实上,给定一个中断,无法推断出是哪个进程在运行。所以,中断的执行不会引起进程的切换,也就可以无限嵌套处理。

中断处理程序可以打断中断或异常处理程序执行,但是反过来,异常不能打断中断处理程序。中断处理程序绝对不能包含页错误的操作,因为这会诱发进程切换。

Linux嵌套执行中断或异常处理程序的两个主要原因是:

  • 为了提高可编程中断控制器和设备控制器的吞吐量。内核正在处理一个中断的时候,能够及时响应另一个中断。
  • 实现没有中断优先级的模型。这可以简化内核代码并提高可移植性。

在多核系统中,几个中断或异常处理程序可能会并发执行。更重要的是,异常处理程序可能由于进程切换,造成在一个CPU上启动,然后迁移到另一个CPU上执行。

0 人点赞