1、中断处理的注意点
(1)中断上下文,不能和用户空间数据交互
(2)不能交出CPU(不能休眠、不能schedule)
(3)ISR运行时间尽可能短,越长则系统响应特性越差
2、中断下半部2种解决方案
(1)为什么要分上半部(top half,又叫顶半部)和下半部(bottom half,又叫底半部)
(2)下半部处理策略1:tasklet(小任务)
(3)下半部处理策略2:workqueue(工作队列)
tasklet使用实战
(1)tasklet相关接口介绍
(2)实战演示tasklet实现下半部
workqueue实战演示
(1)workqueue的突出特点是下半部会交给worker thead,因此下半部处于进程上下文,可以被调度,因此可以睡眠。
(2)include/linux/workqueue.h
3、中断上下半部处理原则
(1)必须立即进行紧急处理的极少量任务放入在中断的顶半部中,此时屏蔽了与自己同类型的中断,由于任务量少,所以可以迅速不受打扰地处理完紧急任务。
(2)需要较少时间的中等数量的急迫任务放在tasklet中。此时不会屏蔽任何中断(包括与自己的顶半部同类型的中断),所以不影响顶半部对紧急事务的处理;同时又不会进行用户进程调度,从而保证了自己急迫任务得以迅速完成。
(3)需要较多时间且并不急迫(允许被操作系统剥夺运行权)的大量任务放在workqueue中。此时操作系统会尽量快速处理完这个任务,但如果任务量太大,期间操作系统也会有机会调度别的用户进程运行,从而保证不会因为这个任务需要运行时间将其它用户进程无法进行。
(4)可能引起睡眠的任务放在workqueue中。因为在workqueue中睡眠是安全的。在需要获得大量的内存时、在需要获取信号量时,在需要执行阻塞式的I/O操作时,用workqueue很合适。
4、ARM架构的CPU异常向量的基址可以是0x00000000,也可以是0xffff0000,Linux内核使用后者,这是一个虚拟地址,当建立了虚拟地址和物理地址的映射之后就可以把异常向量的基址定位到这里来(即把跳转指令复制到这里来)。
5、中断注册函数与卸载函数
注册中断处理函数:request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,const char *name, void *dev_id),其中irq为中断号(在irq.h中定义),handler为处理函数,flags表示上升沿/下降沿等触发方式。它可以完成:分配一个irqaction结构并且调用setup_irq把这它链入链表;设置引脚;使能中断
卸载中断处理函数:free_irq(unsigned int irq, void *dev_id)
它需要用到两个参数:irq和dev_id,它们与通过request_irq注册中断函数时使用的参数 一样。使用中断号irq定位action链表,再使用dev_id在action链表中找到要卸载的表项。 所以,同一个中断的不同中断处理函数必须使用不同的dev_id来区分,这就要求在注册共享中断时参数dev_id必须唯一。它可以完成出链和禁止中断。
6、在proc/interrupts目录下便可看到当前注册的所有中断