简析 Linux 的 CPU 时间( 三 )


软中断中断就是一种插队机制,可以让操作系统优先处理一些紧急的任务 。当硬件设备(例如,网卡)需要向 CPU 发出信号时(例如,数据已到达),就会产生硬件中断 。
CPU 接收到中断时,会切换到内核态执行特定的中断服务,并且期间不允许其他中断抢占(关中断) 。当中断服务需要执行较长时间时,可能会导致且其他的中断得不到及时的响应 。
为了提高中断处理效率,操作系统在之前的基础上把中断处理分成两部分:

  • 上半部top half:在屏蔽中断的上下文中运行,用于完成关键性的处理动作
  • 下半部bottom half:不在中断服务上下文中执行,主要处理不那么急迫但耗时的任务
内核在处理完中断上半部后,可以延期执行下半部,该机制被称为软中断softirq 。软中断处理的过程是不会关中断的,因此当有硬中断到来的时候,可以及时响应 。
构成软中断机制的核心元素包括:
  • 注册: 软中断状态寄存器 irq_stat
  • 处理: 软中断向量表 softirq_vec
  • 触发: 软中断守护线程 daemon

简析 Linux 的 CPU 时间

文章插图
  1. 调用open_softirq()将软中断服务程序注册到软中断向量表softirq_vec(可选)
  2. 调用raise_softirq()触发软中断事务
    • 中断关闭的情况下,设置软中断状态位irq_stat
    • 如果调用者不在中断上下文(普通进程调用),那么直接唤醒daemon线程
  3. daemon线程被唤醒后会运行do_softirq()处理软中断
    • 检查 irq_stat 是否存发生软中断事件
    • 调用 softirq_vec 中对应的软中断服务程序
    • 再次检查 irq_stat,如果发现新的软中断,就会唤醒ksoftrqd线程来处理
ksoftrqd 机制我们知道 CPU 执行的优先级为:硬中断 > 软中断 > 普通进程 。这意味着:
  • 一个软中断不会去抢占另一个软中断,只有硬件中断才可以抢占软中断
  • 如果软中断太过频繁,用户进程可能永远无法获得 CPU 时间
为了保证公平性,内核为每个 CPU 都配置一个ksoftrqd线程 。如果所有的软中断在短时间内无法被处理完,内核就会唤醒ksoftrqd处理剩余的软中断 。以下面这张图为例:
简析 Linux 的 CPU 时间

文章插图
  • 网卡数据就绪,通过硬中断通知 CPU 进行处理
  • 硬中断服务程序调用raise_softirq()触发软中断,唤醒daemon
  • 硬中断服务程序退出后,daemon被唤醒开始处理软中断
  • 遍历过一遍向量表后,daemon发现仍有未处理的软中断,唤醒ksoftrqd
  • ksoftrqd获得 CPU 时间片后,继续处理未完成的软中断
由于 ksoftrqd 其实是一个 nice 值为 0 的普通线程,会进入 cfs_rq 参与调度,可以和普通进程公平地使用 CPU 。
但如果 ksoftrirqd 长时间得不到 CPU,就会致使软中断的延迟变得很大,因此 ksoftirqd 的实时性是很难得到保障 。
典型问题是 ping 延迟:如果 ping 包无法在软中断里得到处理,就会被 ksoftirqd 处理,导致 ping 延迟变得很大 。
中断的影响【简析 Linux 的 CPU 时间】硬中断的优先级很高,但是需要的 CPU 时间极少 。当出现大量硬中断时,可能会引起较多的 CPU 用户态与内核态的切换,但是

经验总结扩展阅读