翻看笔记发现之前的面试不会题目,搜索一下很有学问。
中断跟函数栈很像,都需要保存现场,然后恢复现场,那区别在哪里呢?对中断的理解,之前在听一个中断培训的时候,想到这个有意思的问题。
中断跟函数栈区别在于中断是不可预料的,所以发生中断时要全部保存当前现场,中断处理完恢复现场。而函数栈是可预料的,什么时候调用,从哪里调用都是已知的,那只需要保存必要的信息即可。
中断的概念:一个"中断"仅仅是一个信号,当硬件需要获得处理器对它的关注时,就可以发送这个信号。内核维护了一个中断信号线的注册表,该注册表类似于I/O端口的注册表。
上半部的功能是响应中断。下半部的功能是处理比较复杂的过程。下半部和上半部最大的区别是可中断,而上半部却不可中断。
上半部只是将下半部排到了它们所负责的设备中断的处理队列中去,然后就不做其它的处理了。上半部之所以快,是因为它是完全屏蔽中断的,如果它没有执行完,其他中断就不能及时地处理,只能等到这个中断处理程序执行完毕以后。所以要尽可能多的对设备产生的中断进行服务和处理,中断响应程序就一定要快。
经典网卡来举例,在linux内核中,当网卡一旦接受到数据,网卡会通过中断告诉内核处理数据,内核会在网卡中断处理函数(上半部)执行一些网卡硬件的必要设置,因为这是在中断响应后急切要干的事情。接着,内核调用对应的下半部函数来处理网卡接收到的数据,因为数据处理没必要在中断处理函数里面马上执行,可以将中断让出来做更紧迫的事情。
可以有三种方法来实现下半部:软中断、tasklet和等待队列。
- 软中断
软中断一般很少用于实现下半部,但tasklet是通过软中断实现的,所以先介绍软中断。字面理解,软中断就是软件实现的异步中断,它的优先级比硬中断低,但比普通进程优先级高,同时,它和硬中断一样不能休眠。
软中断是在编译时候静态分配的,要用软中断必须修改内核代码。 - tasklet
上面的介绍看到,软中断实现下半部的方法很麻烦,一般是不会使用的。一般,我们使用tasklet——利用软中断实现的下半部机制。
在介绍软中断索引号的时候,有两个用于实现tasklet的软中断索引号:HI_SOFTIRQ和TASKLET_SOFTIRQ。两个tasklet唯一的区别就是优先级的大小,一般使用TAKSLET_SOFTIRQ。
通过软中断(tasklet也是软中断的一种实现形式)机制来实现中断下半部。使用软中断实现的优缺点很明显:
优点:运行在软中断上下文,优先级比普通进程高,调度速度快。
缺点:由于处于中断上下文,所以不能睡眠。
也许有人会问,那软中断和tasklet有什么区别?
个人理解,tasklet是基于软中断实现的,基本上和软中断相同。但有一点不一样,如果在多处理器的情况下,内核不能保证软中断在哪个处理器上运行(听起来像废话),所以,软中断之间需要考虑共享资源的保护。而在tasklet,内核可以保证,两个同类型(TASKLET_SOFTIRQ和HI_SOFTIRQ)的tasklet不能同时执行,那就说明,同类型tasklet之间,可以不考虑同类型tasklet之间的并发情况。
一般的,优先考虑使用tasklet。 - 工作队列完全不同,它是靠内核线程实现的。
简单来说,软中断和tasklet优先级较高,性能较好,调度快,但不能睡眠。而工作队列是内核的进程调度,相对来说较慢,但能睡眠。所以,如果你的下半部需要睡眠,那只能选择动作队列。否则最好用tasklet。
网卡中断理解
参考:从中断说起
从kernel层面将,事件产生有可能不是由硬件中断触发的,在一定情况下kernel的确会轮询,因为响应硬件中断是一个成本比较高的操作。
以网卡为例,当数据量很少的时候,每来一个数据包网卡都回产生一个中断,kernel响应这个中断,从网卡缓冲区中读出数据放进协议栈处理,当满足一定条件时,kernel回调用户代码,这里的"回调"一般情况下是指从一个kernel syscall中返回(在此之前用户代码一直处于block状态)。
当数据量很大时,每个包都产生一个中断就划不来了,此时kernel可以启动interrupt coalescing机制,让网卡做中断合并,也就是说来足够多的数据包或者等待一个timeout才会产生一个中断,kernel在响应中断时会把所有数据一起读出来处理,这样可以有效的降低中断次数。
当数据量更大时,网卡缓冲区里几乎总是有未处理的数据,此时kernel干脆会禁掉网卡的中断,切换到轮询处理的模式,说白了就是跑一个忙循环不停地读网卡缓冲区里的数据,这样综合开销更低