Chinaunix

标题: 对tasklet的疑问 [打印本页]

作者: rwen2012    时间: 2008-06-12 10:06
标题: 对tasklet的疑问
代码如下, 疑问一:tasklet_schedule判断该tasklet是否已经被SCHE,如果没有则执行 __tasklet_schedule(),并且只加入当前的CPU队列,而不是每个CPU队列,
  所以说每个tasklet只是被schedule一次?但ULK3上说可能是多次。

疑问二:tasklet_action()中,
       if (tasklet_trylock(t)) 首先判断是否已经在其他CPU上执行,如果只被在当前CPU上schedule一次,这个似乎没有必要?

疑问三: tasklet如果被schedule多次,怎么保证它只被执行一次,而不是在各个CPU上各执行一次?

以上假设在SMP环境下。高手请指点。HELP!


void fastcall __tasklet_schedule(struct tasklet_struct *t)
{
    unsigned long flags;

    local_irq_save(flags);
    t->next = __get_cpu_var(tasklet_vec).list;
    __get_cpu_var(tasklet_vec).list= t;  /* 只是当前CPU ? */
    raise_softirq_irqoff(TASKLET_SOFTIRQ);
    local_irq_restore(flags);
}

static inline void tasklet_schedule(struct tasklet_struct *t)
{
    if(!test_and_set_bit(TASKLET_STATE_SCHED,&t->state))
/*判断是否被SCHED,如果是,则什么也不做,这不是只调度一次吗? */


        __tasklet_schedule(t);
}



static void tasklet_action(struct softirq_action *a)
{
    struct tasklet_struct *list;

    local_irq_disable();
    list = __get_cpu_var(tasklet_vec).list;
    __get_cpu_var(tasklet_vec).list = NULL;
    local_irq_enable();

    while (list) {
        struct tasklet_struct *t = list;

        list = list->next;

      
       if (tasklet_trylock(t)) {
             /*判断是否在其他CPU上执行 */
            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上执行了,为什么还要再次加入当前的CPU队列? */
        local_irq_disable();
        t->next = __get_cpu_var(tasklet_vec).list;
        __get_cpu_var(tasklet_vec).list = t;
        __raise_softirq_irqoff(TASKLET_SOFTIRQ);
        local_irq_enable();
    }
}



[ 本帖最后由 rwen2012 于 2008-6-12 10:10 编辑 ]
作者: rwen2012    时间: 2008-06-12 10:10
为2.6.23, 较早的版本也差不多
作者: rwen2012    时间: 2008-06-12 10:27
标题: 回复 #2 rwen2012 的帖子
if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state))

SCHED被清除了, 中断上半部使该tasklet可以再一次被调用,但是不能不同时执行。

算是看明白了。


tasklet的特性也再次,可以多次被调用,但是不能同时被执行,这样使用时不用显式加锁,较softirq更方便

[ 本帖最后由 rwen2012 于 2008-6-12 10:32 编辑 ]
作者: flw2    时间: 2008-06-12 10:33
根源在于你对tasklet的理解有问题,tasklet不保证函数只运行一次,而是不同时运行,不像别的softirq,它可能同时在多CPU运行,tasklet不会,这把这种同步的负担由驱动程序作者移动到内核,就像中断处理机制一样
作者: rwen2012    时间: 2008-06-12 10:38
标题: 回复 #4 flw2 的帖子
谢谢,是理解有问题,

但它能保证“每次调度只运行一次“,是吗?谢谢
作者: flw2    时间: 2008-06-12 10:43
标题: 回复 #5 rwen2012 的帖子
“每次调度只运行一次“ 怎么理解?
作者: rwen2012    时间: 2008-06-12 10:50
标题: 回复 #6 flw2 的帖子
每次tasklet_schedule(tasklet)只会使tasklet->func()运行一次
作者: flw2    时间: 2008-06-12 10:59
如果真的调度了,就运行一次了,就像中断一样,来了10次可能也被看成是一次,但是它一次会处理完该处理的事情,原则是保证不会丢失通知

if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state))
                    BUG();
                t->func(t->data);
所以上面这段代码的顺序不能换,否则可能丢失了,在回来就是BUG了
作者: rwen2012    时间: 2008-06-12 11:17
好, 还是你理解得透彻, 谢谢指点




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2