Interrupts and Interrupt Handlers [LKD 07]

Interrupts


中断是hardware device用来通知CPU的一种机制。在系统上,连接着很多的外设,这些外设速度很慢,并且随时会产生数据需要CPU处理,CPU作为高速运行的部件,不能一直等着外设产生数据,为了提高效率,采用了中断这种机制。当外设需要CPU处理数据时,就向CPU发送电信号,CPU收到电信号以后,就知道哪个设备需要处理了,这个电信号就是中断。

中断并不是直接发送给CPU,而是先发送到interrupt controller,也就是中断控制器(一般是8259A),所有的外设都把中断发送到这里,再由中断控制器把中断信号发送给CPU,CPU收到中断信号,就会停下正在执行的任务,开始执行中断处理函数。

CPU收到的中断,都有对应的中断号,每个外设的中断号都是有区别的,这样CPU根据中断号就能直到是哪些设备产生了中断,进而可以调用对应的中断处理程序。这个中断号一般称为IRQ number。

这里提到了异常,异常和中断非常类似,实际上,异常就是软中断,是CPU在执行指令的过程中发生了异常事件,比如除0错误,或者遇到了page fault,此时都需要中断当前程序的执行,并上报错误。异常和硬件中断的一个很大的区别是,异常是同步产生的,因为执行CPU在执行指令的过程中产生异常,因此是和软件指令同步产生,而硬件中断是异步的,CPU此时可能在执行任何代码。

Interrupt Handlers


用来处理IRQ的处理函数通常称为ISR,也就是interrupt service routine,每个会产生中断的hardware device都有对应的ISR,在kernel中,ISR是device driver的一部分。ISR和普通的kernel code有相同之处,也有不同之处,相同之处在于都是C写的function,不同之处在于ISR只有中断产生时才会执行,并且运行在interrupt context,这是特殊的context,执行时不允许block,即不允许被调度。

因为硬件的中断是异步的,当中断产生时,CPU可能在执行任何代码,所以ISR一定是执行的越快越好,否则被抢占的代码会等待很长时间。因此,ISR中就不能处理很多东西,可以把这些费时的操作放到将来的某个时刻再做,ISR尽快返回。

Top Halves Versus Bottom Halves


接上文,ISR中可能要处理很多事情,但是又不能占用太多CPU的时间,所以OS中一般把ISR分为上下两个部分,即top half和bottom half。top half只处理一些紧急的事情,比如从hardware copy数据,然后调度别的task,ISR就可以结束返回;bottom half里就可以处理剩下的比较费时的操作。

Registering an Interrupt Handler


上面提到过,interrupt handler,也即ISR,是device driver的一部分,应当由device driver负责实现。

driver可以注册interrtupt handler,kernel提供了接口来实现:

static inline int __must_check
request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
	    const char *name, void *dev)
{
	return request_threaded_irq(irq, handler, NULL, flags, name, dev);
}

第一个参数,irq,指定要给哪个IRQ line注册handler,对于kernel的timer或者键盘来说,这个irq是固定死的,其他比如PCI设备等,都是动态分配的;第二个参数,handler,是一个函数指针,指向driver自己的interrupt handler函数,当中断发生时,kernel就会调用这个handler;这个handler的类型如下:

typedef irqreturn_t (*irq_handler_t)(int, void *);

第三个参数是flag,要么是0,要么是一些bitmask,这些bitmask定义在<linux/interrupt.h>。下面介绍一下这些flag,注意,下面对flag的描述只适用于kernel 2.6,在kernel4.15中已经发生了明显的变化。

Interrupt Handler Flags

IRQF_DISABLED

如果设置了这个flag,那么这个handler在执行的时候,所有的中断都被disable。一般情况下,在注册handler时都不会设置这个flag,除非handler对performance特别敏感,必须马上执行。在kernel 4.15中,已经没有这个 flag 了。

IRQF_SAMPLE_RANDOM

如果设置这个flag,说明这个device产生的中断是随机的,那么可以作为随机池的熵参与随机值的生成。在kernel 4.15中,已经没有这个flag了。

IRQF_TIMER

如果设置这个flag,说明这个handler是一个处理timer中断的handler。

IRQF_SHARED

如果设置这个flag,说明这个IRQ line是share的。也就说,要处理的IRQ line是share的,可能有多个device共享了这个IRQ line,因此在kernel中,同一个IRQ line可能存在多个handler。

这本书只列举了上面这几个flag。在kernel 4.15中,还有别的几个flag,这里也列举一下,但是不做深入说明:

/*
 * These flags used only by the kernel as part of the
 * irq handling routines.
 *
 * IRQF_SHARED - allow sharing the irq among several devices
 * IRQF_PROBE_SHARED - set by callers when they expect sharing mismatches to occur
 * IRQF_TIMER - Flag to mark this interrupt as timer interrupt
 * IRQF_PERCPU - Interrupt is per cpu
 * IRQF_NOBALANCING - Flag to exclude this interrupt from irq balancing
 * IRQF_IRQPOLL - Interrupt is used for polling (only the interrupt that is
 *                registered first in an shared interrupt is considered for
 *                performance reasons)
 * IRQF_ONESHOT - Interrupt is not reenabled after the hardirq handler finished.
 *                Used by threaded interrupts which need to keep the
 *                irq line disabled until the threaded handler has been run.
 * IRQF_NO_SUSPEND - Do not disable this IRQ during suspend.  Does not guarantee
 *   
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值