第七章 中断与中断处理
小结:
- 中断和异常
- 中断处理程序,注册(request_irq())、注销、禁止(local_irq_disable())、屏蔽(disable_irq())、检查中断(irqs_disable(), in_interrupt())
- 中断处理机制的实现
设备产生中断 -> 总线将电信号发给中断控制器 -> 发给处理器 -> 处理器关中断 -> 中断处理程序入口 -> 返回内核运行中断的代码(每个中断线都有唯一的位置) - 下半部
软中断、tasklet、工作队列和内核定时器
下半部 | 注册时间 | 上下文 | 顺序执行保障 | 场景 | 是否响应中断 |
---|---|---|---|---|---|
软中断 | 编译时静态注册 | 中断 | 没有,即使相同类型也可以同时在其他处理器上执行,锁保护或单处理器 | 给系统中对时间要求严格以及最重要的下半部使用 | 允许响应中断,但自己不能休眠 |
tasklet | 动态注册,通过软中断实现 | 中断 | 相同类型的不能同时执行,锁保护要求低 | 不需休眠的场景 | 不能睡眠,调度时会禁止本地中断 |
工作队列 | 可动态注册,通过内核线程实现 | 进程 | 没有(和进程上下文一样被调度) | 需要睡眠的场景 | 允许重新调度甚至是睡眠,不能访问用户空间,因为没有相关内存映射 |
软中断:do_softirq(),内核定时器和tasklet都是建立在软中断之上
tasklet:tasklet调度时会禁止本地中断
workqueue_struct:每个CPU一个,系统有默认的event/n
ksoftirq:一组辅助处理软中断(和tasklet)的内核线程,ksoftirqd/n
选择标准:需要睡眠,选工作队列;不需要睡眠,选软中断或tasklet。
- 下半部的加锁
同步问题???还是不太懂
记住,一个下半部实体可能在任何时候运行。
tasklet:intra_tasklet加锁
工作队列:任何共享数据都要加锁。
void local_bh_disable()
禁止下半部
文章目录
处理器和外部慢设备通过 轮询和 中断协同工作。
7.1 中断
中断使得硬件得以发出通知给处理器,处理器收到中断后,会马上向操作系统反馈此信号的到来,然后由操作系统处理。硬件设备生成中断的时候并不考虑与处理器的时钟同步(中断随时可以产生)。
特定的中断总是与特定的设备相关联。每个IRQ线都会被关联一个数值量。
异常:异常与中断不同,产生时必须考虑处理器时钟同步。异常也称为同步中断。
7.2 中断处理程序
内核执行中断处理函数来相应中断,一个设备的中断处理程序是设备驱动程序的一部分。
中断处理程序与内核函数的区别:中断处理程序是被内核调用来响应中断的,他们运行在中断上下文(不可阻塞)
7.3 上半部与下半部的对比
中断处理切为2个部分:
中断处理程序是上半部:接到中断立即执行,只做严格实现的工作,此时中断被禁止。
下半部:被允许稍后完成的工作,此时为开中断。
7.4 注册中断处理程序
-
设备如果使用中断,则需要注册一个中断处理程序。
驱动程序通过request_irq()
注册一个中断处理程序,并激活给定的中断线:int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char* name, void *dev) irq:要分配的中断号(预定或动态分配) handler:指向实际中断处理程序 typedef irqreturn_t (*irq_handler_t)(int, void*);这是handler的原型,接受两个参数
-
中断处理程序标志
第三个参数flags是标识:- IRQF_DISABLED - 在中断处理程序本身期间,禁止所有其他中断
- IRQF_SAMPLE_RANDOM - 来自该设备的中断间隔时间会作为熵填充到熵池
- IRQF_TIMER - 系统定时器的中断处理准备
- IRQF_SHARED - 可以在多个中断处理程序之间共享中断线。