Linux 内核|中断
本文最后更新于:4 years ago
1.中断
中断是系统用来响应硬件设备请求的一种机制,操作系统收到硬件的中断请求,会打断正在执行的进程,然后调用内核中的中断处理程序来响应请求。
举例:敲击键盘时,键盘控制器会发送一个中断,通知操作系统有键按下。
中断处理请求应该短且快。
响应中断请求的程序,也就是中断处理程序,要尽可能快的执⾏完,这样可以减少对正常进程运⾏调度地影响。
否则会造成 临时关闭中断。
当前中断处理程序未执行完,系统内其他设备的中断请求无法被响应,即其他中断会丢失。
举例:当一个电话打进来,如果不迅速沟通完,其他人打电话给你,你就无法接到。
类比到系统中,例如网卡有数据包进来,系统需要迅速将数据包先拷到内存中,避免网卡因为缓存不够,发生丢包。
2.同步中断和异步中断
改变处理器执行指令的顺序的一个事件都是中断,分为同步中断和异步中断。
同步中断(synchronous):即异常,一条指令终止后,CPU 才发生中断,所以是同步。异常通常可分为错误(Faults)、陷阱(Traps)和中止(Aborts)。
异步中断(asynchronous):即通常所说的中断(interrupt),由其他硬件设备依照CPU时钟信号随机产生。
3.硬中断与软中断
中断实际上有两种:
- 外部或硬件引起的中断,硬中断。
- 软件引起的中断,软中断。
硬件引起的中断,由 Local APIC
或与 Local APIC
连接的处理器针脚接收。
软件引起的中断,由处理器自身的特殊情况引起(有时使用特殊架构的指令)。一个常见特殊情况的例子就是 除数为零,另一个例子就是使用 系统调用(system call)。
4.为何需要软中断
主要是为解决 中断处理程序执行时间过长 和 中断丢失 的问题,将中断分为两个阶段,分别是 上半部分(硬中断完成) 和 下半部分(软中断完成)。
上半部,由硬件触发中断,用来快速处理中断。
一般会暂时关闭中断请求,主要负责处理跟硬件紧密相关或者时间敏感的事情。硬中断处理程序完成耗时短的工作,快速执行。
下半部,由内核触发中断,用来异步处理上半部未完成的工作。
一般以「内核线程」的方式运行。软中断处理程序完成耗时长的工作,延迟执行。
硬中断会打断 CPU 正在执行的任务,然后立即执行中断处理程序;而软中断以内核线程的方式执行,每个 CPU 对应一个软中断内核线程,名称通常为 「ksoftirqd/CPU编号」,如 0 号 CPU 对应的软中断内核线程名称是 「ksoftirqd/0」。
软中断除了包含硬件设备中断处理程序的下半部分,一些内核自定义事件也是软中断,比如:内核调度、RCU锁(内核中常用的一种锁)。
5.查看软中断
Linux 中,在
/proc/softirqs
中可查看软中断的运行情况;在
/porc/interrupts
中可查看硬中断的运行情况。
porc:一个指向内核数据结构的接口,通过它能够查看和改变各种系统属性。

- 第一列表示软中断的类型, 比如
NET_RX
表示网络接收中断,NET_TX
表示网络发送中断,TIMER
表示
定时中断、RCU
表示 RCU 锁中断、SCHED
表示内核调度中断。 - 数值显示的是每个 CPU 对应的不同类型的软中断的 累计运行次数。同一种类型的软中断在不同 CPU 的累计次数相差不多。
- 累计次数无需关注,中断次数的变化速率 是重点。
watch -d cat /proc/softirqs
查看中断次数的变化速率。
内核线程的名字外面都有有中括号,这说明 ps 无法获取它们的命令行参数。一般来说,名字在中括号里,都可以认为是内核线程。
6.软中断CPU使用率过高
top
查看 CPU 使用情况,按 1 即可显示 CPU 核心。倒数第 2 列,si 表示 CPU 在软中断上的使用率。
如何判断是由哪个类型软中断导致的 CPU 使用率过高?
使用 watch -d cat /proc/softirqs
查看每个软中断类型的中断次数的变化速率。
对于网络 I/O 比较高的 Web 服务器,
NET_RX
网络接收中断的变化速率相比其他中断类型快很多。若
NET_RX
网络接收中断次数的变化速率过快,需要使用sar -n DEV
查看网卡的网络包接收速率情况,然后分析是哪个网卡有大量的网络包进来。再通过 tcpdump 抓包,分析这些包的来源,如果是非法的地址,可以考虑加防火墙,如果是正常流量,则要考虑硬件升级等。
7.中断的发生流程
假设每一个物理硬件都有一根中断线,设备可通过它对 CPU 发起中断信号,中断信号先通过中断控制器,然后发到 CPU 上执行。中断控制器:Advanced Programmable Interrupt Controller,简称 APIC。一个 APIC 包括两个独立的设备:
- Local APIC
- I/O APIC
Local APIC 存在于每个 CPU 核心中,Local APIC 负责处理特定于 CPU 的中断配置,常被用于管理来自 APIC 时钟(APIC-timer)、热敏元件和其他与 I/O 设备连接的设备的中断。
I/O APIC 提供了多核处理器的中断管理。它被用来在所有的 CPU 核心中分发外部中断。
中断的发生流程:
外部设备给中断控制器发送物理中断信号。
中断控制器将物理中断信号转换成为中断向量
interrupt vector
,发给各个 CPU。每个 CPU 都会有一个中断向量表,根据
interrupt vector
调用一个 IRQ 处理函数。IRQ 处理函数中,将
interrupt vector
转化为抽象中断层的中断信号irq
,调用中断信号irq
对应的中断描述结构(IDT)里面的irq_handler_t
。IDT 表 :中断描述符表,CPU执行中断指令时,会去 IDT 表中查找对应的中断服务程序(interrupt service routine ,ISR)。
8.中断结构体
对于每一个中断,我们都有一个对应的描述结构体irq_desc
,有一个重要的成员变量是 struct action
*action`,用于表示处理这个中断的动作。
1 |
|
每一个中断处理动作的结构 struct irqaction
,都有以下成员:
- 中断处理函数
handler
- 设备 id
void *dev_id
- 中断信号
irq
- 如果中断处理函数在单独的线程运行,则有
thread_fn
是线程的执行函数,thread
是线程的task_struct
。
多个 irqaction
组成一个链表,对于这个中断的所有处理动作,都串在这个链表上。
1 |
|
众多的中断 irq_desc
则采取类似于内存管理中所用到的基数树 radix tree
的方式进行管理。这种结构对于从某个整型 key 找到 value 速度很快,中断信号 irq
是这个整数。通过它,我们很快就能定位到对应的 irq_desc
。
1 |
|