中断上半部与下半部设计:在 ARM Cortex-A 上的 tasklet 与工作队列

封面信息图

在基于 ARM Cortex-A 多核处理器的 Linux 内核驱动开发中,硬件中断处理是连接物理外设与操作系统的大门。由于硬件中断发生时,CPU 会暂停当前正在执行的用户进程并禁用当前核心的中断响应(在硬中断上下文中),系统在此期间对外界的一切其他请求均处于“失聪”状态。

如果驱动开发者在中断处理函数中编写了耗时较长的数据解析、复杂浮点计算,甚至调用了可能导致睡眠阻塞的函数(如 kmalloc(..., GFP_KERNEL) 或获取 mutex 互斥锁),系统就会立即触发著名的 BUG: scheduling while atomic 内核崩溃,或者造成网络与串口的严重溢出丢包。

为了化解“中断处理必须极速完成”与“外设数据吞吐计算量巨大”之间的物理矛盾,Linux 内核设计了经典的中断分层机制:上半部(Top Half)与下半部(Bottom Half)

本文深入拆解 ARM Cortex-A 架构下下半部的两大核心承载机制——tasklet(软中断上下文)workqueue(工作队列/进程上下文) 的内部运作机理与工程选型边界。

中断分层的职责划分与执行契约

Linux 中断分层执行状态机:

外部硬件信号触发 (如千兆网卡 DMA 接收满)
       │
       ▼
【中断上半部 (Top Half / HardIRQ)】
  - 运行环境: 硬中断上下文 (Hard Interrupt Context)
  - 核心职责: 1. 读取硬件中断寄存器;2. 快速清除物理中断标志 (ACK);3. 将数据描述符指针压入内存队列
  - 执行约束: 极快!(通常 < 5微秒);绝对禁止睡眠、禁止调用可阻塞 API!
  - 动作: 登记下半部处理任务,随后立即退出并重新开启硬件中断!
       │
       ▼
【中断下半部 (Bottom Half / Deferred Execution)】
  - 运行环境: 软中断上下文 (SoftIRQ/tasklet) 或 内核线程上下文 (Workqueue)
  - 核心职责: 执行耗时的数据包协议解析、内存动态分配、业务逻辑通知
  - 恢复正常: 此时系统中断已全面开放,不影响其他紧急硬件事件的响应!

tasklet 与 workqueue 的微观机制对决

在 Linux 内核中,实现下半部最主流的两种工具是 taskletworkqueue,两者的底层物理宿主截然不同:

+-------------------+-----------------------------------+-----------------------------------+
| 核心对比维度      | tasklet (基于 SoftIRQ)            | workqueue (工作队列)              |
+-------------------+-----------------------------------+-----------------------------------+
| 执行宿主上下文    | 软中断上下文 (SoftIRQ Context)    | 内核线程上下文 (kworker 守护进程) |
| 是否允许睡眠阻塞  | 绝对禁止睡眠!(禁止 mutex, 延时)  | 允许任意睡眠!(可调用 msleep, mutex)|
| 多核并发特性      | 同一个 tasklet 绝不会在多核并发! | 同一个工作项可根据调度分配到各核  |
| 调度响应优先级    | 极高!在硬中断退出瞬间立即执行    | 正常!参与 Linux CFS 进程调度竞争 |
| 适合的业务场景    | 毫秒级内完成、无阻塞的轻量数据搬运| 复杂协议解析、大内存分配、I/O 读写|
+-------------------+-----------------------------------+-----------------------------------+

工业驱动代码实战:tasklet 与工作队列双重实现

1. 使用 tasklet 处理极低延迟无阻塞数据包
#include <linux/module.h>
#include <linux/interrupt.h>

struct custom_device {
    int irq;
    struct tasklet_struct rx_tasklet;
    uint8_t rx_buffer[1024];
};

// 下半部: tasklet 回调函数 (运行于软中断上下文,禁止睡眠!)
static void custom_rx_tasklet_handler(unsigned long data) {
    struct custom_device *dev = (struct custom_device *)data;
    
    // 执行快速的校验和计算与环形缓冲区数据提取 (耗时 < 50us)
    process_rx_packet_fast(dev->rx_buffer);
}

// 上半部: 硬中断服务例程
static irqreturn_t custom_hard_irq_handler(int irq, void *dev_id) {
    struct custom_device *dev = (struct custom_device *)dev_id;
    
    // 1. 读取并清除硬件中断标志
    uint32_t status = read_hw_irq_status();
    clear_hw_irq_status(status);

    // 2. 调度 tasklet (将 tasklet 挂入当前 CPU 的 tasklet_vec 链表)
    tasklet_schedule(&dev->rx_tasklet);

    return IRQ_HANDLED; // 瞬间退出硬中断!
}
2. 使用 workqueue 处理需要睡眠或申请互斥锁的长任务
#include <linux/workqueue.h>
#include <linux/delay.h>

struct custom_storage_device {
    int irq;
    struct work_struct flash_write_work;
    struct mutex lock;
};

// 下半部: workqueue 回调函数 (运行于内核线程 kworker 上下文,允许任意睡眠!)
static void custom_flash_work_handler(struct work_struct *work) {
    struct custom_storage_device *dev = container_of(work, struct custom_storage_device, flash_write_work);

    // 允许安全使用互斥锁与动态内存分配
    mutex_lock(&dev->lock);
    
    // 允许调用可能引起等待的 I2C/SPI 慢速总线操作
    msleep(5); // 模拟耗时等待
    write_data_to_spi_flash();
    
    mutex_unlock(&dev->lock);
}

// 上半部: 硬中断中调度工作项
static irqreturn_t custom_storage_irq_handler(int irq, void *dev_id) {
    struct custom_storage_device *dev = (struct custom_storage_device *)dev_id;
    
    clear_hw_irq_status();
    // 将工作项推入 Linux 系统默认工作队列 (system_wq)
    schedule_work(&dev->flash_write_work);

    return IRQ_HANDLED;
}

工业选型黄金决策链

在编写 Linux 设备驱动时,下半部选型必须遵循以下判断:

下半部选型决策树:

1. 下半部业务代码中是否包含任何可能引发睡眠的操作?
   (如: mutex_lock, msleep, kmalloc(GFP_KERNEL), 访问 slow I2C/SPI 总线)
   ├─► 是: 必须且只能选用【工作队列 (workqueue)】!
   │
   └─► 否 (纯内存计算、自旋锁保护、无阻塞):
         │
         ▼
2. 业务对延迟是否具有严苛的微秒级要求?
   ├─► 是: 选用【tasklet】以获取极高的软中断调度优先级!
   └─► 否: 优先选用【workqueue】,让出 CPU 资源给其他高优先级任务。

合理划分上半部与下半部的职责边界,才能保证操作系统在承受千兆网络与高频外设冲击时,依然保持轻盈灵敏的中断响应。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐