LKD 笔记:中断和中断处理函数

进程上下文

进程最重要的一个部分是正在执行的程序代码。程序代码从一个可执行文件中读入,在进程的地址空间中执行。正常的程序执行发生在用户空间。当一个程序执行了一个系统调用或者触发了一个异常后,它进入内核空间。此时,我们说内核正代表着进程在执行,它正处在进程上下文。在进程上下文中,current宏是有效的。

在退出内核空间后,进程重新在用户空间执行,除非有一个更高优先级的进程在退出内核空间时处于可运行状态,在这种情形下,调度器会被触发以选择更高优先级的进程运行。

在进程上下文中,内核能够睡眠(比如系统调用阻塞或者调用了schedule函数)并且是完全可抢占的。

这两点很重要。首先,能够睡眠的能力意味着系统调用能够使用大部分内核功能(函数)。完全可抢占意味着当前的任务可以被另一个任务抢占。由于另一个任务可能执行相同的系统调用,所以需要一些措施来保证系统调用是可重入的。

中断上下文

当在执行一个中断处理函数时,内核处于中断上下文。回忆一下,在进程上下文中,内核代表着进程在执行——比如,执行一个系统调用或者运行一个内核线程(实际上,进程包括进程里的线程都是内核线程)。在进程上下文中,current宏指向关联的任务。另外,进程上下文可以睡眠。

而中断上下文不与任何一个进程关联。current宏是没有意义的(尽管它指向被中断的进程)。由于没有关联的进程,在中断上下文中不能睡眠——如果能睡眠,调度该怎么执行呢?因此,在中断处理函数中,不能调用一些可能会导致睡眠的函数。

中断上下文是与执行时间密切相关的,因为它中断了其他的代码。不建议在中断处理函数中使用忙循环。中断处理函数应该要执行的越快越好。

中断处理函数不与被中断的进程共享栈,他们有自己的栈,称作中断栈。在32位系统中,中断栈的大小为4K。

顶半部 VS 底半部

中断处理函数的两个目标——快速地执行和做大量的工作是有冲突的。为了解决这个冲突,中断的处理分为两个部分。中断处理函数是顶半部。顶半部在收到中断后立即执行,并且只执行对时间要求很严格的工作,比如对接收到的中断进行应答或者重新设置硬件。那些可以延后的工作推迟到底半部。底半部在之后一个更方便的时间运行,并且所有的中断都是打开的。

中断控制

Linux 内核实现了一些接口来控制中断。这些接口能够让你关掉当前处理器上的中断或者屏蔽一个特定的中断。关掉中断后,你能够保证当前执行的代码不会被中断处理函数抢占。另外,关掉中断也会关掉内核抢占。然而,关掉中断或者关掉内核抢占不能阻止从其他处理器的并行访问。因为 Linux 支持多处理器,内核代码通常需要使用锁来避免其他处理器同时对共享资源的访问。获取锁通常是和关掉本地中断组合在一起使用的。锁防止了其他处理器的并行访问,关掉本地中断防止了可能的中断处理函数的并发访问。

中断系统的状态

irqs_disabled()在当前处理器的中断是关闭的状态时返回非0。否则返回0。

in_interrupt()在内核正在处理任何类型的中断处理时返回非0。包括正在执行一个中断处理函数或者一个底半部处理函数。返回0表示内核正处于进程上下文。

in_irq()仅当内核正在执行一个中断处理函数时返回非0。

你可能感兴趣的:(LKD,笔记)