一、中断


中断是外设(device)与内核通信的方式。外设发出中断,内核中相应驱动(driver: ISR and buttom half)做出处理。

内核需要快速的对中断做出反应(网络包,键盘输入等等)。对此,内核做出了两方面的设计:

为了将函数加以区分,内核为每个处理器分配一个中断栈(interrupt stack)。整个中断的处理都在中断栈中(除了workqueue)。还有一个概念: 中断上下文。

关于中断上下文和进程上下文的概念,LKD 也没有解释很清除。下面是书中较为比较性的一个解释:

(1)In user-space, executing user code in a process. (2)In kernel-space, in process context(CPU在进程上下文,指的是通过系统调用进入内核后的状态,或者执行内核线程/进程), executing on behalf of a specific process. (3)In kernel-space, in interrupt context, not associated with a process, handling an interrupt.

为了让中断能够快速的执行,所以就不能让中断栈与进程有任何联系(这样就可以不被调度)。整个中断过程只运行在中断上下文中。正因为不被调度,所以在中断上下文中,不能 sleep,一旦 sleep 就无法醒来。

假设在一段时间内,接受到大量的网络包,需要将网络包的数据拷贝到内存。这个工作相当耗时。内核先对网卡做出回应(acknowladge),这个过程的处理函数叫做中断服务例程(Interrupt Servive Routine,ISR)。也称为 top half(上半部)。然后再进行网络包处理的工作,这个过程称为 bottom half(下半部)。

 

二、Top Half


top half 主要由 ISR 来完成,下面以 RTC 为例:

2.1、编写 ISR

static irqreturn_t rtc_interrupt(int irq, void *dev_id)
{
    ...
}

第一个参数为中断号。由于多个设备可能使用同一个中断号,这种情况用第二个参数 dev_id 加以区分。ISR 的返回值有 3 中情况:

/**
 * enum irqreturn
 * @IRQ_NONE		interrupt was not from this device
 * @IRQ_HANDLED		interrupt was handled by this device
 * @IRQ_WAKE_THREAD	handler requests to wake the handler thread
 */
enum irqreturn {
	IRQ_NONE,
	IRQ_HANDLED,
	IRQ_WAKE_THREAD,
};
typedef enum irqreturn irqreturn_t;

ISR 被标记为 static,因为它通常不会被其它文件使用。

2.2、注册 ISR

下面是注册 ISR 的函数原型:

int request_irq(unsigned int irq, 
                irq_handler_t handler, 
                unsigned long flags, 
                const char *name, 
                void *dev)

通过下面的方式注册 rtc_interrupt 函数:

static int __init rtc_init(void)
{
    ...
	if (request_irq(rtc_irq, rtc_interrupt, IRQF_SHARED, "rtc",
			(void *)&rtc_port)) {
		rtc_has_irq = 0;
		printk(KERN_ERR "rtc: cannot register IRQ %d\n", rtc_irq);
		return -EIO;
	}
    ...
	printk(KERN_INFO "Real Time Clock Driver v" RTC_VERSION "\n");

	return 0;
}

2.3、执行 ISR

当 CPU 接受到中断后,根据中断号查表:

下面是调用流程,主要功能由 handle_irq() 完成:

              +------------------+
              | common_interrupt |
              +--------+---------+
                       |
                       | call do_IRQ
                       v
        +--------------+---------------+
        | do_IRQ(struct pt_regs *regs) |
        +--------------+---------------+
                       |
                       |
                       v
+----------------------+-------------------------+
| handle_irq(unsigned irq, struct pt_regs *regs) |
+------------------------------------------------+

 

三、Bottom Half


linux 提供 3 中下半部的实现机制:

3.1、softirq

3.2、tasklets

3.1、workqueue