栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

tasklet存储结构及调用流程

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

tasklet存储结构及调用流程

目录
  • 1. 简介
  • 2. 存储结构
  • 3. 代码流程
    • 3.1 open_softirq
    • 3.2 raise_softirq_irqoff
    • 3.3 run_ksoftirqd
    • 3.4 __do_softirq
  • 4. tasklet
    • 4.1 tasklet_action

1. 简介

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

2. 存储结构

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

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

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()) {
                
                __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的流程为:

softirq_init
	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);
        __this_cpu_write(tasklet_vec.head, NULL);
        __this_cpu_write(tasklet_vec.tail, this_cpu_ptr(&tasklet_vec.head));
        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 = 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。
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/311059.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号