zoukankan      html  css  js  c++  java
  • Linux 内核 tasklet 机制和工作队列zz

    http://blog.jobbole.com/107110/

    1. Tasklet机制分析

    上面我们介绍了软中断机制,linux内核为什么还要引入tasklet机制呢?主要原因是软中断的pending标志位也就32位,一般情况是不随意增加软中断处理的。而且内核也没有提供通用的增加软中断的接口。其次内,软中断处理函数要求可重入,需要考虑到竞争条件比较多,要求比较高的编程技巧。所以内核提供了tasklet这样的一种通用的机制。

    其实每次写总结的文章,总是想把细节的东西说明白,所以越写越多。这样做的好处是能真正理解其中的机制。但是,内容太多的一个坏处就是难道记忆,所以,在讲清楚讲详细的同时,我还要把精髓总结出来。Tasklet的特点,也是tasklet的精髓就是:tasklet不能休眠,同一个tasklet不能在两个CPU上同时运行,但是不同tasklet可能在不同CPU上同时运行,则需要注意共享数据的保护。

    主要的数据结构

    static DEFINE_PER_CPU(struct tasklet_head, tasklet_vec);

    static DEFINE_PER_CPU(struct tasklet_head, tasklet_hi_vec);

    如何使用tasklet

    使用tasklet比较简单,只需要初始化一个tasklet_struct结构体,然后调用tasklet_schedule,就能利用tasklet机制执行初始化的func函数。

    static inline void tasklet_schedule(struct tasklet_struct *t)
    {
        if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state))
            __tasklet_schedule(t);
    }
    

      tasklet_schedule处理过程也比较简单,就是把tasklet_struct结构体挂到tasklet_vec链表或者挂接到tasklet_hi_vec链表上,并调度软中断TASKLET_SOFTIRQ或者HI_SOFTIRQ

    void __tasklet_schedule(struct tasklet_struct *t)
    {
        unsigned long flags;
    local_irq_save(flags); t->next = NULL; *__get_cpu_var(tasklet_vec).tail = t; __get_cpu_var(tasklet_vec).tail = &(t->next); raise_softirq_irqoff(TASKLET_SOFTIRQ); local_irq_restore(flags); } EXPORT_SYMBOL(__tasklet_schedule); void __tasklet_hi_schedule(struct tasklet_struct *t) { unsigned long flags; local_irq_save(flags); t->next = NULL; *__get_cpu_var(tasklet_hi_vec).tail = t; __get_cpu_var(tasklet_hi_vec).tail = &(t->next); raise_softirq_irqoff(HI_SOFTIRQ); local_irq_restore(flags); } EXPORT_SYMBOL(__tasklet_hi_schedule);

      

    Tasklet执行过程

    Tasklet_action在软中断TASKLET_SOFTIRQ被调度到后会被执行,它从tasklet_vec链表中把tasklet_struct结构体都取下来,然后逐个执行。如果t->count的值等于0,说明这个tasklet在调度之后,被disable掉了,所以会将tasklet结构体重新放回到tasklet_vec链表,并重新调度TASKLET_SOFTIRQ软中断,在之后enable这个tasklet之后重新再执行它。

    static void tasklet_action(struct softirq_action *a)
    {
        struct tasklet_struct *list;
    local_irq_disable(); list = __get_cpu_var(tasklet_vec).head; __get_cpu_var(tasklet_vec).head = NULL; __get_cpu_var(tasklet_vec).tail = &__get_cpu_var(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; *__get_cpu_var(tasklet_vec).tail = t; __get_cpu_var(tasklet_vec).tail = &(t->next); __raise_softirq_irqoff(TASKLET_SOFTIRQ); local_irq_enable(); } }

      

    2. Linux工作队列

    前面已经介绍了tasklet机制,有了tasklet机制为什么还要增加工作队列机制呢?我的理解是由于tasklet机制的限制,变形tasklet中的回调函数有很多的限制,比如不能有休眠的操作等等。而是用工作队列机制,需要处理的函数在进程上下文中调用,休眠操作都是允许的。但是工作队列的实时性不如tasklet,采用工作队列的例程可能不能在短时间内被调用执行。

    数据结构说明

    首先需要说明的是workqueue_struct和cpu_workqueue_struct这两个数据结构,创建一个工作队列首先需要创建workqueue_struct,然后可以在每个CPU上创建一个cpu_workqueue_struct管理结构体。

  • 相关阅读:
    【计算机世界】467- XOR — 神奇的按位运算符
    记 · 复习知识 · 偶遇好玩的知识点
    【CSS】466- 一行 CSS 代码搞定响应式布局
    【Web技术】465- 关于前端埋点统计方案思考
    【CSS】464- 5种 CSS 浮动和清除浮动的方法
    简单易懂的 React useState() Hook 指南(长文建议收藏)
    java中的四类八种
    线程
    异常
    Aspx Ajax 调用 C#函数处理数据
  • 原文地址:https://www.cnblogs.com/soul-stone/p/8151713.html
Copyright © 2011-2022 走看看