中断概念
什么是中断
- 硬件与CPU通信的异步机制
- 打断当前执行流程,处理紧急事件
- 分类:外部中断、异常、软中断
中断号(IRQ)
- 唯一标识中断源的数字
- 在
/proc/interrupts
中查看分配情况
中断处理流程
// 典型中断处理函数原型
irqreturn_t handler(int irq, void *dev_id);
- 硬件触发中断信号
- CPU保存当前上下文
- 跳转到中断向量表指定位置
- 调用对应中断服务程序(ISR)
- 恢复被中断的上下文
上半部与下半部
特性 | 上半部(Top Half) | 下半部(Bottom Half) |
---|---|---|
执行时机 | 立即响应 | 延迟执行 |
允许操作 | 必要硬件操作 | 复杂处理 |
中断状态 | 禁用中断 | 启用中断 |
实现机制 | 中断处理函数 | tasklet/workqueue等 |
中断上下文
- 原子性:不能睡眠/调度
- 栈限制:使用独立中断栈(x86_64通常16KB)
- 注意事项:
- 不能调用可能阻塞的函数
- 不能与用户空间交互
- 处理时间应尽可能短
中断API
// 注册中断
int request_irq(unsigned int irq, irq_handler_t handler,
unsigned long flags, const char *name, void *dev);
// 释放中断
void free_irq(unsigned int irq, void *dev_id);
// 禁用本地CPU中断
local_irq_disable();
local_irq_enable();
中断共享
实现要点:
- 注册时指定
IRQF_SHARED
标志 - 每个处理程序必须验证设备是否触发中断
- 使用
dev_id
参数区分设备
实践案例
按键中断驱动
static irqreturn_t button_isr(int irq, void *dev_id)
{
struct timeval tv;
do_gettimeofday(&tv);
printk("Button pressed at %ld.%06ld\n", tv.tv_sec, tv.tv_usec);
return IRQ_HANDLED;
}
// 模块初始化时:
request_irq(IRQ_BUTTON, button_isr, IRQF_SHARED, "my_button", NULL);