中断处理原则 1:不能嵌套
原因:中断处理函数需要调用 C 函数,这就需要用到栈。如果中断嵌套突然暴发,那么栈将越来越大,栈终将耗尽,最终可能导致栈溢出。 所以,为了防止这种情况发生,也是为了简单化中断的处理,在 Linux 系统 上中断无法嵌套:即当前中断 A 没处理完之前,不会响应另一个中断 B(即使它 的优先级更高)。
中断处理原则 2:越快越好
原因:在 SMP 系统中,假设中断处理很慢,那么正在处理这个中断的 CPU 上的其他线程也无法执行。 在中断的处理过程中,该 CPU 是不能进行进程调度的,所以中断的处理要越快越好,尽早让其他中断能被处理──进程调度靠定时器中断来实现。
中断处理原则3:中断服务程序中不能有阻塞操作。
原因:中断期间是完全占用CPU的(即不存在内核调度),中断被阻塞住,其他进程将无法操作。
ps:中断服务程序注意返回值,要用操作系统定义的宏做为返回值,而不是自己定义的。
如果中断产生之后要做比较多的事情,有一下策略:(中断可以分为上下部分,主要事情交给下半部分处理)
1.下半部要做的事情耗时不是太长:tasklet(软件中断)
2.下半部要做的事情太多并且很复杂:
2.1 work 工作队列 work, work queue(系统默认工作队列:system_wq)
下半部 tasklet,它们都是在中断上下文中执行,它们无法休眠。当要处理更复杂的事情时,往往更耗时。这些更耗时的工作放在定时器 或是下半部中,会使得系统很卡;并且循环等待某件事情完成也太浪费 CPU 资源了。 如果使用线程来处理这些耗时的工作,那就可以解决系统卡顿的问题:因为线程可以休眠。因此应该用内核线程来做:在中断上半部唤醒内核线程(kworker)。内核线程和 APP 都 一样竞争执行,APP 有机会执行,系统不会卡顿。kworker 线程要去“工作队列”(work queue)上取出一个一个“工作”(work), 来执行它里面的函数。
2.2 threaded irq
用 work 来线程化地处理中断,一个 worker 线程只能由一个 CPU 执行, 多个中断的 work 都由同一个 worker 线程来处理,在单 CPU 系统中也只能忍着 了。但是在 SMP 系统中,明明有那么多 CPU 空着,你偏偏让多个中断挤在这个 CPU 上? 新技术 threaded irq,为每一个中断都创建一个内核线程;多个中断的内核线程可以分配到多个 CPU 上执行,这提高了效率。