Contexts in Linux Kernel

本文将简单介绍一下 linux 内核中三种主要的上下文(context)。

Players on CPU

在系统启动后的任何时候,CPU 都处于下述四种状态之一:

  1. 处理硬件中断,此时没有与之关联的进程;
  2. 处理软中断(包括 timer,tasklet 等),此时没有与之关联的进程;
  3. 用户上下文(user context),此时仍在内核态,并与一个进程相关联;
  4. 用户态进程。

这些状态有着严格的顺序关系。前三种状态中只有序号小的才可以打断(抢占)序号大的状态,如软中断仅可以被硬中断抢占执行。而后两种状态则可以互相抢占。

User Context

用户上下文(注意与用户态区分,此时仍在内核态执行,但是与一个用户态进程相关联)一般从系统调用进入,如文件的打开、关闭、读写等;此外一个内核模块的加载和卸载函数也是运行在这种上下文。

在用户上下文中可以使用 current 指针来获取与当前上下文关联的进程信息。

Software Interrupt Context

在硬中断退出后和将要返回到用户态时,被标记为 pending 状态的软中断会在这时执行。软中断经常被用来做真正的中断处理工作,因为有些中断的处理过程是比较耗时的,如果都放在硬中断的处理函数中,则会造成内核延时响应其它硬中断。因此通常的做法是在硬中断处理函数中获取必要的信息,然后触发一个软中断(通常是 tasklet 或者 timer 等)来进行真正的处理。这也是 spinlock 系列函数中后缀 _bh 的由来:bottom half,即处理后半段部分的任务。

软中断必须是可重入的,因为同一个软中断可能同时被调度在不同的 CPU 上,因此通常不需要直接使用软中断,而是使用 tasklet 和 timer 等来简化编程复杂度,这些封装好的模型可以保证同一时间只有一个实例运行在某一个 CPU 上。

Hardware Interrupt Context

硬中断包括 ticks,网卡事件,键盘输入等硬件产生的中断。硬中断上下文即内核用来处理这些硬中断的 handler。内核保证同一个硬件中断上下文不会被重入,如果在处理某个中断时同一类型的中断又产生了,那么它会被扔进队列(或者直接忽略)。硬中断的处理函数要保持尽量的简单,通常是标记中断已被处理,然后启动一个 tasklet 来进行后续的处理。