linux打电话命令 shell命令拨打电话( 九 )


特别是,中断处理程序在响应中断时,还会临时关闭中断 。这就会导致上一次中断处理完成之前,其他中断都不能响应,也就是说中断有可能会丢失 。
那么还是以取外卖为例 。假如你订了 2 份外卖 , 一份主食和一份饮料,并且是由 2 个不同的配送员来配送 。这次你不用时时等待着,两份外卖都约定了电话取外卖的方式 。但是,问题又来了 。
当第一份外卖送到时,配送员给你打了个长长的电话,商量发票的处理方式 。与此同时 , 第二个配送员也到了,也想给你打电话 。
但是很明显,因为电话占线(也就是关闭了中断响应),第二个配送员的电话是打不通的 。所以 , 第二个配送员很可能试几次后就走掉了(也就是丢失了一次中断) 。
如果你弄清楚了“取外卖”的模式,那对系统的中断机制就很容易理解了 。事实上,为了解决中断处理程序执行过长和中断丢失的问题,Linux 将中断处理过程分成了两个阶段,也就是 上半部和下半部:
比如说前面取外卖的例子,上半部就是你接听电话,告诉配送员你已经知道了,其他事儿见面再说 , 然后电话就可以挂断了;下半部才是取外卖的动作,以及见面后商量发票处理的动作 。
这样,第一个配送员不会占用你太多时间,当第二个配送员过来时,照样能正常打通你的电话 。
除了取外卖,我再举个最常见的网卡接收数据包的例子,让你更好地理解 。
网卡接收到数据包后,会通过 硬件中断 的方式,通知内核有新的数据到了 。这时,内核就应该调用中断处理程序来响应它 。你可以自己先想一下,这种情况下的上半部和下半部分别负责什么工作呢?
对上半部来说 , 既然是快速处理,其实就是要把网卡的数据读到内存中,然后更新一下硬件寄存器的状态(表示数据已经读好了) , 最后再发送一个 软中断 信号 , 通知下半部做进一步的处理 。
而下半部被软中断信号唤醒后,需要从内存中找到网络数据,再按照网络协议栈,对数据进行逐层解析和处理,直到把它送给应用程序 。
所以,这两个阶段你也可以这样理解:
实际上,上半部会打断 CPU 正在执行的任务 , 然后立即执行中断处理程序 。而下半部以内核线程的方式执行,并且每个 CPU 都对应一个软中断内核线程,名字为 “ksoftirqd/CPU 编号” , 比如说 ,  0 号 CPU 对应的软中断内核线程的名字就是 ksoftirqd/0 。
不过要注意的是,软中断不只包括了刚刚所讲的硬件设备中断处理程序的下半部,一些内核自定义的事件也属于软中断,比如内核调度和 RCU 锁(Read-Copy Update 的缩写 , RCU 是 Linux 内核中最常用的锁之一)等 。
不知道你还记不记得,前面提到过的 proc 文件系统 。它是一种内核空间和用户空间进行通信的机制,可以用来查看内核的数据结构,或者用来动态修改内核的配置 。其中:
运行下面的命令,查看 /proc/softirqs 文件的内容,你就可以看到各种类型软中断在不同 CPU 上的累积运行次数:
在查看 /proc/softirqs 文件内容时,你要特别注意以下这两点 。
第一,要注意软中断的类型,也就是这个界面中第一列的内容 。从第一列你可以看到,软中断包括了 10 个类别,分别对应不同的工作类型 。比如 NET_RX 表示网络接收中断,而 NET_TX 表示网络发送中断 。
第二,要注意同一种软中断在不同 CPU 上的分布情况,也就是同一行的内容 。正常情况下 , 同一种中断在不同 CPU 上的累积次数应该差不多 。比如这个界面中,NET_RX 在 CPU0 和 CPU1 上的中断次数基本是同一个数量级,相差不大 。

推荐阅读