Linux中软中断tasklet任务队列初始化
软中断初始化softirq_init
void __init softirq_init(void)
{open_softirq(TASKLET_SOFTIRQ, tasklet_action, NULL);open_softirq(HI_SOFTIRQ, tasklet_hi_action, NULL);
}
void open_softirq(int nr, void (*action)(struct softirq_action*), void *data)
{softirq_vec[nr].data = data;softirq_vec[nr].action = action;
}
1. 函数功能概述
这两个函数用于初始化 Linux 内核的软中断系统,特别是为任务队列(tasklet
)机制注册对应的软中断处理函数
2. softirq_init
函数分析
2.1. 函数定义
void __init softirq_init(void)
{
void
:函数没有返回值__init
:宏标记,表示该函数只在内核初始化阶段使用,初始化完成后占用的内存会被释放- 函数名表明这是软中断系统的初始化函数
2.2. 注册普通任务队列软中断
open_softirq(TASKLET_SOFTIRQ, tasklet_action, NULL);
open_softirq
:软中断注册函数TASKLET_SOFTIRQ
:软中断号,表示普通优先级任务队列软中断tasklet_action
:软中断处理函数,负责执行普通优先级的任务队列NULL
:没有额外的数据参数传递给处理函数
2.3. 注册高优先级任务队列软中断
open_softirq(HI_SOFTIRQ, tasklet_hi_action, NULL);
}
HI_SOFTIRQ
:软中断号,通常定义为 0,表示高优先级任务队列软中断tasklet_hi_action
:软中断处理函数,负责执行高优先级的任务队列NULL
:没有额外的数据参数
3. open_softirq
函数分析
3.1. 函数定义和参数
void open_softirq(int nr, void (*action)(struct softirq_action*), void *data)
{
void
:没有返回值int nr
:软中断号(0-9),内核预定义了 10 个软中断void (*action)(struct softirq_action*)
:函数指针,指向软中断的处理函数void *data
:可选的数据指针,会传递给处理函数
3.2. 设置软中断数据
softirq_vec[nr].data = data;
softirq_vec[nr]
:访问软中断向量数组中指定编号的软中断.data = data
:将用户数据指针保存到软中断结构中- 作用:允许在处理函数中访问特定的数据
3.3. 设置软中断处理函数
softirq_vec[nr].action = action;
}
.action = action
:将处理函数指针保存到软中断结构中- 作用:当软中断被触发时,内核会调用这个函数来处理
4. 系统整体架构
硬件中断↓
中断处理程序 (top half)↓
触发软中断 ←── softirq_init 初始化↓
软中断处理 (bottom half)├── HI_SOFTIRQ (0) → tasklet_hi_action → 高优先级tasklet├── TIMER_SOFTIRQ (1) → run_timer_softirq → 定时器├── ...└── TASKLET_SOFTIRQ (6) → tasklet_action → 普通tasklet
高优先级任务队列的软中断处理函数tasklet_hi_action
static void tasklet_hi_action(struct softirq_action *a)
{struct tasklet_struct *list;local_irq_disable();list = __get_cpu_var(tasklet_hi_vec).list;__get_cpu_var(tasklet_hi_vec).list = NULL;local_irq_enable();while (list) {struct tasklet_struct *t = list;list = list->next;if (tasklet_trylock(t)) {if (!atomic_read(&t->count)) {if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state))BUG();t->func(t->data);tasklet_unlock(t);continue;}tasklet_unlock(t);}local_irq_disable();t->next = __get_cpu_var(tasklet_hi_vec).list;__get_cpu_var(tasklet_hi_vec).list = t;__raise_softirq_irqoff(HI_SOFTIRQ);local_irq_enable();}
}
1. 函数功能概述
tasklet_hi_action
函数负责处理高优先级任务队列(tasklet
),在软中断上下文中执行延迟的任务,确保高优先级的延迟处理能够得到及时执行
2. 代码逐段分析
2.1. 函数定义
static void tasklet_hi_action(struct softirq_action *a)
{
static
:函数只在当前文件内可见struct softirq_action *a
:软中断动作结构指针,包含处理函数和数据
2.2. 获取并清空当前CPU的任务队列
struct tasklet_struct *list;local_irq_disable();list = __get_cpu_var(tasklet_hi_vec).list;__get_cpu_var(tasklet_hi_vec).list = NULL;local_irq_enable();
struct tasklet_struct *list
:临时链表指针local_irq_disable()
:禁用本地中断,防止并发访问list = __get_cpu_var(tasklet_hi_vec).list
:获取当前CPU的高优先级任务链表__get_cpu_var(tasklet_hi_vec).list = NULL
:清空原链表(原子操作)local_irq_enable()
:重新启用中断- 关键:在中断保护下快速获取并清空链表,减少锁持有时间
2.3. 遍历处理任务队列
while (list) {struct tasklet_struct *t = list;list = list->next;
while (list)
:循环处理链表中的每个任务struct tasklet_struct *t = list
:获取当前任务list = list->next
:移动到下一个任务- 作用:逐个处理链表中的所有任务
2.4. 尝试锁定任务
if (tasklet_trylock(t)) {
tasklet_trylock(t)
:尝试获取任务的锁- 非阻塞操作,如果锁已被占用则立即返回失败
- 目的:防止同一任务在多个CPU上并发执行
2.5. 检查任务状态和引用计数
if (!atomic_read(&t->count)) {
atomic_read(&t->count)
:原子读取任务的引用计数!atomic_read(&t->count)
:如果引用计数为0(任务可用)- 作用:检查任务是否被禁用(count > 0 表示任务被禁用)
2.6. 状态检查和清除
if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state))BUG();
test_and_clear_bit(TASKLET_STATE_SCHED, &t->state)
:测试并清除"已调度"状态位- 如果清除失败(原本未设置),触发内核错误
BUG()
- 作用:确保任务确实处于已调度状态
2.7. 执行任务回调函数
t->func(t->data);
t->func
:任务回调函数指针t->data
:传递给回调函数的数据- 核心操作:实际执行用户注册的任务函数
2.8. 任务执行完成处理
tasklet_unlock(t);continue;}tasklet_unlock(t);}
tasklet_unlock(t)
:释放任务锁continue
:跳过后续代码,处理下一个任务- 如果引用计数不为0,也释放锁但继续后续处理
2.9. 任务重新调度
local_irq_disable();t->next = __get_cpu_var(tasklet_hi_vec).list;__get_cpu_var(tasklet_hi_vec).list = t;__raise_softirq_irqoff(HI_SOFTIRQ);local_irq_enable();}
}
重新调度流程:
local_irq_disable()
:禁用中断t->next = __get_cpu_var(tasklet_hi_vec).list
:将任务添加到链表头部__get_cpu_var(tasklet_hi_vec).list = t
:更新链表头__raise_softirq_irqoff(HI_SOFTIRQ)
:重新触发高优先级软中断local_irq_enable()
:启用中断