设为首页 收藏本站
查看: 322|回复: 0

[经验分享] linux 内核tasklet详解

[复制链接]
累计签到:77 天
连续签到:1 天
发表于 2014-5-27 10:14:07 | 显示全部楼层 |阅读模式
本文内核版本为2.6.32

软中断被执行的优先级要高于内核线程。硬中断是可以抢占内核线程的,硬中断退出时会立即执行软中断。这时软中断执行程序是运行在中断上下文的。如果软中断执行程序在指定时间内没处理完,就会挂起来等下次下次被执行。下次被执行可以是另一个硬中断退出时在中断上下文中执行,也可以是在特殊的内核线程ksoftirq被调度到来执行,这时是运行在线程上下文的。

总体来说,软中断执行程序被执行的机会会比普通线程要多。所以一些要优先并需要及时处理的工作可以交给软中断来处理。但linux 实现了软中断,但对内核模块开发的人员来说,内核并没有直接提供使用软中断的API。内核提供了tasklet 来给内核模块开发人员来用。

tasklet是在软中断HI_SOFTIRQ和TASKLET_SOFTIRQ基础上实现的。

初始化:
在start_kernel()里调用softirq_init()初始化这两个软中断。


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

数据结构:

每个tasklet 由数据结构tasklet_struct 代表。

struct tasklet_struct
{
    struct tasklet_struct *next;
    unsigned long state;     //tasklet状态。
    atomic_t count;         //锁计数器
    void (*func)(unsigned long);  //tasklet处理函数。
    unsigned long data;      //处理函数需要的参数。
};

全局数组tasklet_vec[NR_CPU] 和 tasklet_hi_vec[NR_CPU] 。数组元素是一个tasklet_head元素,是tasklet_struct 链表头。数组下标对应每个cpu ID.即数组保存了每个cpu上的tasklet_struct 链表。

tasklet 的state状态字段有如下状态:
TASKLET_STATE_SCHED     表示tasklet已经插入到tasklet_vec 或 tasklet_hi_vec数组中的一个链表上了。
TASKLET_STATE_RUN     表示tasklet正在被执行。

static inline int tasklet_trylock(struct tasklet_struct *t)
{
    return !test_and_set_bit(TASKLET_STATE_RUN, &(t)->state);
}

static inline void tasklet_unlock(struct tasklet_struct *t)
{
    smp_mb__before_clear_bit();
    clear_bit(TASKLET_STATE_RUN, &(t)->state);
}

调用tasklet_init()来定义一个tasklet.

void tasklet_init(struct tasklet_struct *t,void (*func)(unsigned long), unsigned long data)
{
    t->next = NULL;
    t->state = 0;
    atomic_set(&t->count, 0);
    t->func = func;
    t->data = data;
}


禁止tasklet:
static inline void tasklet_disable_nosync(struct tasklet_struct *t)
{
    /*禁止tasklet后立即返回*/
    atomic_inc(&t->count);   //增加tasklet的锁计数器。
    smp_mb__after_atomic_inc();
}


static inline void tasklet_unlock_wait(struct tasklet_struct *t)
{
    /*直到等到tasklet执行完毕返回*/
    while (test_bit(TASKLET_STATE_RUN, &(t)->state)) { barrier(); }
}

static inline void tasklet_disable(struct tasklet_struct *t)
{
    /*禁止tasklet并且直到tasklet执行完毕后返回*/
    tasklet_disable_nosync(t);
    tasklet_unlock_wait(t);
    smp_mb();
}


激活tasklet:
static inline void tasklet_enable(struct tasklet_struct *t)
{
    smp_mb__before_atomic_dec();
    /*递减tasklet的锁计数器*/
    atomic_dec(&t->count);
}


调度tasklet
根据tasklet的优先级调用tasklet_schedule() 或tasklet_hi_schedule().

static inline voidtasklet_schedule(struct tasklet_struct *t)
{
    /*如果tasklet没被调度过,即没被插入tasklet_vec相应的链表 ,调度*/
    if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state))
    {
        __tasklet_schedule(t);
    }
}


void fastcall__tasklet_schedule(struct tasklet_struct *t)
{
    unsigned long flags;
    /*保存中断状态寄存器并关闭本地CPU的中断*/
    local_irq_save(flags);

    /*把tasklet插入本地CPU的tasklet_vec中对应的链表里*/
    t->next = __get_cpu_var(tasklet_vec).list;
    __get_cpu_var(tasklet_vec).list = t;
   
   /*把本地CPU的软中断TASKLET_SOFTIRQ位标记为挂起*/
    raise_softirq_irqoff(TASKLET_SOFTIRQ);

    /*恢复中断状态寄存器并开本地CPU中断*/

    local_irq_restore(flags);
}


软中断TASKLET_SOFTIRQ的处理函数如下:

    static void tasklet_action(struct softirq_action *a)
    {
        struct tasklet_struct *list;
        /*保存中断状态寄存器并关闭本地CPU的中断*/

        local_irq_disable();

        /*取得tasklet_vec数组中本地CPU的tasklet链表,并存入临时变量中*/
        list = __get_cpu_var(tasklet_vec).list;

        /*清空tasklet_vec数组中本地CPU的tasklet链表*/
        __get_cpu_var(tasklet_vec).list = NULL;

        /*恢复中断状态寄存器并开本地CPU中断*/
        local_irq_enable();

        /*循环执行tasklet链表上每个tasklet的处理函数*/
        while (list)
        {
            /*从链表上摘下一个tasklet*/
            struct tasklet_struct *t = list;
            list = list->next;
        
           /*如果tasklet没在被执行,执行,设置tasklet 的state字段为RUNNING状态*/
            if (tasklet_trylock(t))
            {
                /*如果tasklet的锁计数器为0,执行*/
                if (!atomic_read(&t->count))
                {
                    /*清除tasklet的SCHED状态*/
                    if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state))
                        BUG();
                    /*执行tasklet的处理函数*/
                    t->func(t->data);
                    /*清除tasklet 的state字段的RUNNING状态,继续处理链表上的下一个tasklet*/
                    tasklet_unlock(t);
                    continue;
                }

                /*如果tasklet 的锁计数器不为0,表示tasklet被禁用,清除state字段的RUNNING状态*/
                tasklet_unlock(t);
            }

            /*关闭本地CPU中断,并把以上没被处理的tasklet重新挂到tasklet_vec数组中对应本地CPU上的链表上*/
            local_irq_disable();
            t->next = __get_cpu_var(tasklet_vec).list;
            __get_cpu_var(tasklet_vec).list = t;
           /*把本地CPU上的TASKLET_SOFTIRQ标记为挂起,并使能中断*/
           __raise_softirq_irqoff(TASKLET_SOFTIRQ);
           local_irq_enable();
        }
    }



运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.iyunv.com/thread-19741-1-1.html 上篇帖子: linux 内核软中断详解 下篇帖子: cloudstack4云平台centos6.4安装配置教程
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表