中断小结
- 中断管理
- 2023-03-11
- 73热度
- 0评论
上下文 | 是否抢占 | |
---|---|---|
顶半部 | 中断 | 否 |
Softirq/tasklet | 软中断 | 是 |
workqueue | 进程 | 是 |
threaded_irq | 进程 | 是 |
- Tasklet:底半部,优先级比较高,处理函数中不能睡眠。
- workqueue:底半部,处理函数可以睡眠,也可以执行比较长的应用。
- threaded_irq:底半部,处理函数可以睡眠,也可以执行比较长的应用,支持IRQ_ONESHOT。
中断处理过程
为什么软中断中不能睡眠
软中断的触发是在中断执行irq_exit的时候,软中断可以线程化和非线程化处理,当软中断是非线程化时,还是处于中断上下文的,尽管进入软中断会打开本地cpu中断响应,但是但是其他寄存器的值是没有恢复的,如果此时进入睡眠将会触发调度,那么上一个任务就无法返回。
中断是否会丢失
会,使用边沿触发时容易丢失。因为CPU响应一个中断时会屏蔽掉CPU的本地响应,无法进行再响应其他中断,但是中断控制器只会pengding一个信号,没法叠加信号,即在CPU响应处理A中断时,B中断要是触发了1次以上,那么等A中断处理完后再响应B中断时也只会处理1次,本质上还是中断控制器没法叠加信号。因此在驱动编写时,如果不想丢中断,建议使用电平触发,因为电平触发如果没有与外设进行同步清除触发源时,电平会一直触发中断响应。
如何解决电平触发中断洪泛
可使用request_thread_irq(irq,irq_default_primary_handler,xx_isr,IRQF_ONESHOT)。对于电平触发的外设,如果需要使用睡眠的API接口操作外设写相关寄存器才能清除中断就可使用request_thread_irq。如下图的场景,当点击触摸屏LCD触发高电平中断时,当CPU收到高电平触发时需要通过I2C接口写触摸屏的寄存器清除中断,高电平才会拉低进入下一流程。此时就会面临一个问题,当CPU响应中断处理时,在顶半部是无法调用I2C的接口写寄存器清除的,因为I2C的接口可能是睡眠,在中断上下文中是无法进行睡眠,那么处理写I2C的操作需要移到底半部去处理,但是一进入底半部就会开中断,因为是高电平,那么就又会触发中断,因此就引入IRQF_ONESHOT,当注册中断是声明了该参数,中断响应从顶半部退出,直到底半步结束才会打开中断控制器对该外设的中断响应,这就解决了中断洪泛的问题。irq_default_primary_handler是默认的顶半部处理函数,不做任何处理,直接返回IRQ_WAKE_THREAD进入底半部,当然用户也可以自定义声明函数,但是返回值要使用IRQ_WAKE_THREAD,如果自定义声明的顶半部为NULL,那么系统会默认设定irq_default_primary_handler。
为什么linux不是实时操作系统
进入中断处理时,CPU就关闭了本地中断响应,没法再响应其他中断,即linux的中断时没法嵌套的,即使有再高优先级的中断也是没法处理。另外软中断的处理要比任何进程优先级高,因为软中断是可以在中断上下文中运行。
除了中断,软中断外,spinlock在处理过程中是关闭抢占调度的,所以在spinlock期间也是也没法调度的。看下下面的场景:
- T0时刻normal task执行系统调用进入到内核。
- T1时刻获取到了spin lock,进入临界区保护阶段。
- T2时刻产生了IRQ1中断,进而进行处理IRQ1中断。
- T3时刻唤醒了高优先级的RT task,但此时系统处于中断中无法进行调度。
- T4时刻IRQ1中断处理结束,但接着又触发了IRQ2中断,进入IRQ2中断处理。
- T5时刻IR2中断处理结束,但仍处于spin lock临界区,依旧无法调度RT task。
- T6时刻,spin lock释放,高优先级的RT task得到调度运行。
- T7时刻,RT task运行结束,normal task继续得到运行。
- T8时刻,从内核态返回用户态。
如何让linux变成实时操作系统
打上RTlinux的patch:https://mirrors.edge.kernel.org/pub/linux/kernel/主要的改进是将spinlock改完可抢占,将所有中断处理改完线程化等等。中断处理线程化,其核心原理比较简单,就是顶半部不处理,直接返回IRQ_WAKE_THREAD,这样所有的操作都进入到中断线程中处理。
如何调试?
cat /proc/interrupts
/proc/irq/xx/smp_affinity
root@TinaLinux:/# cd /sys/kernel/debug/tracing/
root@TinaLinux:/sys/kernel/debug/tracing# echo irqsoff > current_tracer
root@TinaLinux:/sys/kernel/debug/tracing# echo 1 > tracing_on
root@TinaLinux:/sys/kernel/debug/tracing# echo 0 > tracing_on
root@TinaLinux:/sys/kernel/debug/tracing# cat trace
pinctrl/*/pins
参考文献
1.GICv3_Software_Overview_Official_Release_B.pdf
2.aarch64_exception_and_interrupt_handling_100933_0100_en.pdf
3.ARM64体系结构编程与实践
4.奔跑吧 Linux内核:基于Linux 4.x内核源代码问题分析
5.http://www.wowotech.net/
6.https://www.cnblogs.com/LoyenWang/