Chinaunix首页 | 论坛 | 博客
  • 博客访问: 309452
  • 博文数量: 101
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 774
  • 用 户 组: 普通用户
  • 注册时间: 2018-10-15 14:13
个人简介

搭建一个和linux开发者知识共享和学习的平台

文章分类

全部博文(101)

文章存档

2024年(15)

2023年(24)

2022年(27)

2019年(8)

2018年(27)

分类: LINUX

2022-09-15 11:12:00

    linux内核对外部中断的处理分成两大部分HARDIRQ和SOFTIRQ,HARDIRQ在执行时处理器的中断是关闭的,耗时的工作延迟到SOFTIRQ中执行。因此内核为驱动提供了一个基于SOFTIRQ的任务延迟的实现机制tasklet。
    tasklet是内核定义的几种softirq之一,根据优先级不同,内核将tasklet分成两种,在softirq中对应TASKLET_SOFTIRQ和HI_SOFTIRQ,后者的执行优先级高于前者。

    linux系统初始化期间通过调用softirq_init为TASKLET_SOFTIRQ和HI_SOFTIRQ安装了执行函数。
void __init softirq_init(void)
{
    int cpu;

    for_each_possible_cpu(cpu)
    {
         per_cpu(tasklet_vec, cpu).tail =&per_cpu(tasklet_vec, cpu).head;
         per_cpu(tasklet_hi_vec, cpu).tail =&per_cpu(tasklet_hi_vec, cpu).head;
    }

    open_softirq(TASKLET_SOFTIRQ, tasklet_action);
    open_softirq(HI_SOFTIRQ, tasklet_hi_action);
}

void open_softirq(int nr, void (*action)(struct softirq_action *))
{
    softirq_vec[nr].action = action;
}
    在中断处理SOFTIRQ中,如果发现本地CPU的_softirq_pending上TASKLET_SOFTIRQ或者HI_SOFTIRQ位被置1,就调用tasklet_action或者tasklet_hi_action。

    驱动中为了实现基于tasklet机制的延迟操作,需要声明一个tasklet对象。可以用DECLEARE_TASKLET宏声明并初始化一个静态的tasklet对象,也可以调用tasklet_init来完成。
    声明了tasklet对象之后,驱动需要调用tasklet_schedule来向系统提交这个tasklet,实际上就是将一个tasklet对象加入到tasklet_vec管理的链表中。
void __tasklet_schedule(struct tasklet_struct *t)
{
    unsigned long flags;

    local_irq_save(flags);
    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_restore(flags);
}
通过操作tail将tasklet对象依次加入到链表中。
    如果一个tasklet被调度执行完后,其state的TASKLET_STATE_SCHED位被清0,这意味着除非被再次提交,否则下次的SOFTIRQ将不会再调度到它,这是一种one-shot特性。
    如果tasklet可以被提交,那么接下来的工作就是把它加入到当前处理器tasklet_vec管理的链表中,然后再通过raise_softirq_irqoff调用告诉SOFTIRQ当前处理器有个TASKLET_SOFTIRQ正等待处理。raise_softirq_irqoff用一个整形变量的位来表示该位上是否有待决的softirq等待处理。


阅读(844) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~