Linux 中断机制深度分析
Linux 中断机制深度分析
1. 中断工作原理
核心流程:
- 设备触发中断信号
- CPU 通过中断控制器接收中断
- 查询中断描述符表 (IDT) 获取处理程序地址
- 保存当前执行上下文
- 执行中断服务例程 (ISR)
- 恢复上下文并返回
类型 | 触发源 | 特点 | 典型场景 | 处理函数示例 |
---|---|---|---|---|
外部硬件中断 | I/O设备、定时器等 | 异步触发,通过中断控制器传递 | 键盘输入、网络包到达 | request_irq() 注册的ISR |
处理器异常 | CPU执行指令错误 | 同步触发,精确异常定位 | 除零错误、缺页异常、非法指令 | do_page_fault() |
软件中断(INT) | 程序显式调用 | 同步触发,用于系统调用 | 用户态调用syscall | entry_SYSCALL_64() |
处理器间中断 | 其他CPU核 | 核间通信机制 | SMP负载均衡、TLB刷新 | smp_call_function() |
不可屏蔽中断 | 硬件故障 | 最高优先级,不可屏蔽 | 内存ECC错误、硬件看门狗超时 | nmi_handler() |
2. 实现机制与代码框架
分层处理:
层级 | 上下文 | 可抢占 | 延迟要求 | 典型应用 |
---|---|---|---|---|
上半部 | 中断上下文 | 不可 | 纳秒级 | 硬件寄存器操作 |
下半部 | 进程/软中断 | 可 | 毫秒级 | 数据处理、协议栈 |
3. 核心数据结构
// 中断描述符 (kernel/irq/internals.h)
struct irq_desc {struct irq_data irq_data;irq_flow_handler_t handle_irq; // 流控处理函数struct irqaction *action; // 中断处理链表raw_spinlock_t lock;// ...
};// 中断处理动作 (include/linux/interrupt.h)
struct irqaction {irq_handler_t handler; // ISR 函数指针void *dev_id; // 设备标识符struct irqaction *next; // 共享中断链表unsigned int irq; // 中断号unsigned long flags; // 标志位// ...
};
4. 中断注册源码示例
// 注册中断处理函数 (kernel/irq/manage.c)
int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev)
{struct irqaction *action;action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);action->handler = handler;action->flags = flags;action->name = name;action->dev_id = dev;return __setup_irq(irq, desc, action);
}
5. 简单实例:GPIO 按键中断
#include <linux/interrupt.h>
#include <linux/gpio.h>#define GPIO_BTN 17
static int irq_num;// 中断处理函数
static irqreturn_t btn_isr(int irq, void *dev_id) {printk("Button pressed!\n");return IRQ_HANDLED;
}static int __init btn_init(void) {int ret;irq_num = gpio_to_irq(GPIO_BTN);ret = request_irq(irq_num, btn_isr, IRQF_TRIGGER_RISING, "my_button", NULL);return ret;
}static void __exit btn_exit(void) {free_irq(irq_num, NULL);
}module_init(btn_init);
module_exit(btn_exit);
6. 调试工具与命令
命令 | 功能描述 |
---|---|
cat /proc/interrupts | 查看所有中断的统计信息 |
cat /proc/irq/<IRQ>/spurious | 查看指定IRQ的伪中断统计 |
irqtop | 动态显示中断频率(需安装) |
trace-cmd record -e irq | 使用ftrace跟踪中断事件 |
调试技巧:
- 中断风暴检测:
watch -n1 "cat /proc/interrupts | grep eth0"
- 软中断监控:
watch -n1 "cat /proc/softirqs"
- 中断绑定CPU:
echo 3 > /proc/irq/128/smp_affinity # 绑定到CPU2 (0x3=二进制0011)
7. 中断处理流程图解
8. 中断聚合核心原理
中断聚合通过以下方式优化性能:
- 时间聚合:设置时间窗口(如 100μs),窗口内事件合并
- 数量聚合:达到预设事件数量(如 32 个数据包)才触发中断
- 智能平衡:动态调整参数实现延迟与吞吐的平衡
8.1 技术实现架构
核心组件交互:
组件 | 作用 | 聚合实现位置 |
---|---|---|
网卡硬件 | 事件检测 | 硬件计数器/计时器 |
驱动层 | 参数配置 | 寄存器设置 |
内核 | 事件处理 | NAPI机制 |
应用层 | 参数调整 | ethtool控制 |
8.3 网络中断聚合实现(以Intel千兆网卡为例)
关键寄存器:
寄存器 | 地址 | 功能 | 位域 |
---|---|---|---|
ITR (中断节流) | 0x00C8 | 控制中断频率 | [15:0] 间隔值 |
RADV (Rx延迟) | 0x282C | Rx中断延迟 | [15:0] 微秒值 |
TADV (Tx延迟) | 0x382C | Tx中断延迟 | [15:0] 微秒值 |
驱动层代码实现:
// drivers/net/ethernet/intel/e1000e/netdev.c
static void e1000e_set_itr(struct e1000_adapter *adapter)
{u32 new_itr = adapter->itr;// 自适应算法计算新ITR值if (adapter->itr_setting == 1) {if (adapter->total_rx_packets < 10000) new_itr = 10000; // 低流量模式else new_itr = max(4000, 2000000 / adapter->total_rx_packets);} else {new_itr = adapter->itr_setting;}// 写入硬件寄存器ew32(ITR, new_itr);
}
9. 下半部机制对比
机制 | 执行上下文 | 并行性 | 睡眠允许 | 适用场景 |
---|---|---|---|---|
SoftIRQ | 中断上下文 | 完全并行 | 否 | 网络接收等高吞吐场景 |
Tasklet | 中断上下文 | 同类型串行 | 否 | 通用设备驱动 |
Workqueue | 进程上下文 | 线程池调度 | 是 | 需要睡眠的操作 |
Threaded IRQ | 进程上下文 | 每个IRQ独立 | 是 | 复杂中断处理 |
10. 高级调试:FTrace 跟踪
# 启用中断跟踪
echo 1 > /sys/kernel/debug/tracing/events/irq/enable
cat /sys/kernel/debug/tracing/trace_pipe
输出示例:
irq/35-iwlwifi-1575 [000] d.h1. 632.123456: irq_handler_entry: irq=35 name=wl_wq
irq/35-iwlwifi-1575 [000] d.h1. 632.123459: irq_handler_exit: irq=35 ret=handled
最佳实践:
- 上半部执行时间控制在 10μs 以内
- 共享中断需设置
IRQF_SHARED
标志- 避免在中断上下文中调用
kmalloc(GFP_KERNEL)
- 高频率中断使用 NAPI 或中断聚合技术