tasklet存储结构及调用流程

1. 简介

tasklet是基于softirq的,它在中断上下文执行,不屏蔽中断,在其中不能执行睡眠/等待操作。

2. 存储结构

softirq在linux kernel中由一个数组存储,每一种类型的softirq对应一个action。

softirq的类型定义在include/linux/interrupt.h文件中,共有(NR_SOFTIRQS - 1)个。
softirq

3. 代码流程

3.1 open_softirq

将传入的action,赋值到softirq_vec对应类型的位置上。

3.2 raise_softirq_irqoff

在有softirq需要处理时,调用raise_softirq_irqoff函数,该函数一共做了两件事:

  1. 将传入的参数类型softirq的pending bit置1。
  2. wakeup ksoftirqd smp_hotplug_thread。

存放pending bit的变量,是一个per-cpu变量,名为irq_stat,它的定义如下:

kernel/softirq.c
#ifndef __ARCH_IRQ_STAT
irq_cpustat_t irq_stat[NR_CPUS] ____cacheline_aligned;
EXPORT_SYMBOL(irq_stat);
#endif

arch/arm64/include/asm/hardirq.h
typedef struct {
        unsigned int __softirq_pending;
        unsigned int ipi_irqs[NR_IPI];
} ____cacheline_aligned irq_cpustat_t; 

唤醒的ksoftirqd,是一个smp_hotplug_thread线程,它的定义为:

kernel/softirq.c
static struct smp_hotplug_thread softirq_threads = {
        .store                  = &ksoftirqd,
        .thread_should_run      = ksoftirqd_should_run,
        .thread_fn              = run_ksoftirqd,
        .thread_comm            = "ksoftirqd/%u",
};

其中的成员做简单介绍:

  1. store: DEFINE_PER_CPU(struct task_struct *, ksoftirqd); ----定义的per-cpu task_struct。
  2. thread_should_run: 在wakeup这个线程时,会先调用这个函数,判断是否唤醒。
  3. thread_fn: wakeup ksoftirqd后,真正运行的核心函数。
  4. thread_comm: per-cpu的ksoftirqd名称定义,例如ksoftirqd/0。

3.3 run_ksoftirqd

在执行完raise_soft_irqoff后,若当前cpu不在中断中,则会唤醒ksoftirqd线程,执行run_ksoftirqd函数,再看看一下,这个run_ksoftirqd到底做了哪些事。
函数定义如下:

kernel/softirq.c
static void run_ksoftirqd(unsigned int cpu)
{
        local_irq_disable();
        if (local_softirq_pending()) {
                /*
                 * We can safely run softirq on inline stack, as we are not deep
                 * in the task stack here.
                 */
                __do_softirq();                                                                                                                                                                            
                local_irq_enable();
                cond_resched_rcu_qs();
                return;
        }
        local_irq_enable();
}

这个函数非常简单,主要做的事情就是,关闭本地中断,调用__do_softirq函数。继续查看__do_softirq。

3.4 __do_softirq

这个函数篇幅较长,后续再完善,主要功能为:遍历所有的softirq类型,若有pending bit,则执行相应的action。

4. tasklet

1) tasklet位于softirq_vec数组中的第7个元素,为softirq_vec[6]。
2) tasklet注册action的流程为:

start_kernel
	softirq_init {
		open_softirq(TASKLET_SOFTIRQ, tasklet_action);
		open_softirq(HI_SOFTIRQ, tasklet_hi_action);
	}

3) 注册的action,分别为tasklet_action / tasklet_hi_action。

4.1 tasklet_action

先看一下代码,根据代码进行分析。

kernel/softirq.c
static void tasklet_action(struct softirq_action *a)
{
        struct tasklet_struct *list;

        local_irq_disable();
        list = __this_cpu_read(tasklet_vec.head); ------ 1)
        __this_cpu_write(tasklet_vec.head, NULL);
        __this_cpu_write(tasklet_vec.tail, this_cpu_ptr(&tasklet_vec.head));
        local_irq_enable();

        while (list) { ------ 遍历tasklet_vec上所有的node
                struct tasklet_struct *t = list;

                list = list->next;

                if (tasklet_trylock(t)) { //尝试拿锁,若拿到则处理该tasklet
                        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);
                }

				//若没拿到锁,或者其它cpu正在处理该tasklet,则将其重新放入list中,raise后继续遍历下一个
                local_irq_disable();
                t->next = NULL;
                *__this_cpu_read(tasklet_vec.tail) = t;
                __this_cpu_write(tasklet_vec.tail, &(t->next));
                __raise_softirq_irqoff(TASKLET_SOFTIRQ);
                local_irq_enable();
        }
}
  1. 读取per-cpu的变量tasklet_vec,复制给临时变量list。
  2. 遍历list中的所有元素,若某个tasklet的count为0时,则调用tasklet->func。若不为0则将其添加到tasklet_list中,并设置tasklet pending bit 为 1。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值