相关的源代码文件是的hardirq.h,softirq.h和softirq.c。
bottom half是Linux提高系统中断响应和处理能力的有效机制。
我们知道,发生中断时,处理器要停止当前正在执行的指令,而操作系统负责将中断发送到对应的设备驱动程序去处理。在中断的处理过程中,系统不能进行其他任何工作,因此,在这段时间内,设备驱动程序要以最快的速度完成中断处理,而其他大部分工作在中断处理过程之外进行。Linux 内核利用bottom half处理过程帮助实现中断的快速处理。
bh_base 数组的索引是静态定义的,定时器bottom half处理过程的地址保存在第 0 个元素中,控制台bottom half处理过程的地址保存在第 1 个元素中等等。典型来说,每个bottom half处理过程和相应的任务队列关联。当 bh_mask 和 bh_active 表明第 N 个bottom half处理过程已被安装且处于活动状态,则调度程序会调用第 N 个bottom half处理过程,该bottom half处理过程最终会处理与之相关的任务队列中的各个任务。因为调度程序从第 0 个元素开始依次检查每个bottom half处理过程,因此,第 0 个bottom half处理过程具有最高的优先级,第 31 个bottom half处理过程的优先级最低。
内核中的某些bottom half处理过程是和特定设备相关的,而其他一些则更一般一些。下面列出了内核中通用的bottom half处理过程。
Linux 中通用的bottom half处理过程
TIMER(定时器) |
在每次系统的周期性定时器中断中,该bottom half处理过程被标记为活动状态,并用来驱动内核的定时器队列机制。 |
CONSOLE(控制台) |
该处理过程用来处理控制台消息。 |
TQUEUE(TTY 消息队列) |
该处理过程用来处理 tty 消息。 |
NET(网络) |
该处理过程用于一般网络处理。 |
IMMEDIATE(立即) |
这是一个一般性处理过程,许多设备驱动程序利用该过程对自己要在随后处理的任务进行排队。 |
当某个设备驱动程序,或内核的其他部分需要将任务排队进行处理时,它将任务添加到适当的系统队列中(例如,添加到系统的定时器队列中),然后通知内核,表明需要进行bottom half处理。
static
inline void run_bottom_halves(void)
unsigned long active;
void (**bh)(void);
active = get_active_bhs();
clear_active_bhs(active);
bh = bh_base;
do {
if (active & 1)
(*bh)();
bh++;
active >>= 1;
} while (active);
}
asmlinkage
void do_bottom_half(void)
{
int cpu = smp_processor_id();
if (softirq_trylock(cpu)) {
if
(hardirq_trylock(cpu)) {
__sti();
run_bottom_halves();
__cli();
hardirq_endlock(cpu);
}
softirq_endlock(cpu);
}
}
为了通知内核,使用mark_bh(irq)将 bh_active 的相应数据位置为 1。例如,如果驱动程序在 immediate 队列中将某任务排队,并希望运行 IMMEDIATE bottom half处理过程来处理排队任务,则只需将 bh_active 的第 8 位置为 1。
在每个系统调用和中断调用结束并返回之前,调度程序要检验 bh_active 中的每个位,如果有任何一位为 1,则相应的bottom half处理过程被调用。(根据开发者的计划,将来的处理方法可能是可以由用户程序或中断处理例程指示是否在此时执行bottom half。)
每个bottom half处理过程被调用时,bh_active 中的相应为被清除。bh_active 中的置位只是暂时的,在两次调用调度程序之间 bh_active 的值才有意义,如果 bh_active 中没有置位,则不需要调用任何bottom half处理过程。