免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1473 | 回复: 1
打印 上一主题 下一主题

linux中断延迟之tasklet [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2011-12-27 22:19 |只看该作者 |倒序浏览

linux中断延迟之tasklet








tasklet是I/O驱动程序中实现可延迟函数的首选方法。从下面的内核代码的分析中我们会看到,tasklet建立在两个叫做HI_SOFTIRQ和TASKLET_SOFTIRQ的软中断之上。几个tasklet可以与同一个软中断相关联,每个tasklet执行自己的函数。tasklet和高优先级的tasklet分别存放在tasklet_vec和tasklet_hi_vec数组中。下面我们结合具体的代码来了解他的实现和运用。

tasklet的内核实现

在start_kernel函数做内核初始化工作的时候会调用函数softirq_init




view plaincopy to clipboard
  1. 01.void __init softirq_init(void)  
  2. 02.{  
  3. 03.    int cpu;  
  4. 04.  
  5. 05.    for_each_possible_cpu(cpu) {  
  6. 06.        int i;  
  7. 07.        /*对tasklet相关pcp变量的初始化*/  
  8. 08.        per_cpu(tasklet_vec, cpu).tail =  
  9. 09.            &per_cpu(tasklet_vec, cpu).head;  
  10. 10.        per_cpu(tasklet_hi_vec, cpu).tail =  
  11. 11.            &per_cpu(tasklet_hi_vec, cpu).head;  
  12. 12.        for (i = 0; i < NR_SOFTIRQS; i++)  
  13. 13.            INIT_LIST_HEAD(&per_cpu(softirq_work_list[i], cpu));  
  14. 14.    }  
  15. 15.  
  16. 16.    register_hotcpu_notifier(&remote_softirq_cpu_notifier);  
  17. 17.    /*将tasklet 执行函数加入软中断向量中,
  18. 18.    这个执行函数会执行tasklet对应一个链表
  19. 19.    中的所有函数*/  
  20. 20.    open_softirq(TASKLET_SOFTIRQ, tasklet_action);  
  21. 21.    open_softirq(HI_SOFTIRQ, tasklet_hi_action);  
  22. 22.}
复制代码
open_softirq函数在前面我们已经分析过了,在这里可以看出,两类tasklet以一个软中断的方式加入软中断向量中,而这两种tasklet实际上位两个链表,就是上面的tasklet_hi_vec和tasklet_vec,我们看一个就行了,实现大同小异。




view plaincopy to clipboard
  1. 01.static void tasklet_action(struct softirq_action *a)  
  2. 02.{  
  3. 03.    struct tasklet_struct *list;  
  4. 04.  
  5. 05.    local_irq_disable();/*禁用本地中断*/  
  6. 06.    list = __get_cpu_var(tasklet_vec).head;/*将链表的地址保存*/  
  7. 07.    __get_cpu_var(tasklet_vec).head = NULL;/*已调度的tasklet描述符的链表被清空*/  
  8. 08.    __get_cpu_var(tasklet_vec).tail = &__get_cpu_var(tasklet_vec).head;  
  9. 09.    local_irq_enable();/*打开本地中断*/  
  10. 10.  
  11. 11.    while (list) {/*对于list链表的每个tasklet描述符*/  
  12. 12.        struct tasklet_struct *t = list;  
  13. 13.  
  14. 14.        list = list->next;  
  15. 15.  
  16. 16.        if (tasklet_trylock(t)) {  
  17. 17.            /*通过查看tasklet描述符的count字段,
  18. 18.            检查tasklet是否被禁止*/  
  19. 19.            if (!atomic_read(&t->count)) {/*如果没有禁止*/  
  20. 20.                /*清楚调度标志*/  
  21. 21.                if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state))  
  22. 22.                    BUG();  
  23. 23.                t->func(t->data);/*执行对应函数*/  
  24. 24.                tasklet_unlock(t);  
  25. 25.                continue;/*继续下一个*/  
  26. 26.            }  
  27. 27.            tasklet_unlock(t);  
  28. 28.        }  
  29. 29.        /*运行到这里,表示tasklet被禁止*/  
  30. 30.        local_irq_disable();  
  31. 31.        t->next = NULL;  
  32. 32.        /*重新插入到链表中,然后再次激活软中断*/  
  33. 33.        *__get_cpu_var(tasklet_vec).tail = t;  
  34. 34.        __get_cpu_var(tasklet_vec).tail = &(t->next);  
  35. 35.        /*这里的激活实际上设置位掩码pending
  36. 36.        的对应位,使其在软中断时能够被执行*/  
  37. 37.        __raise_softirq_irqoff(TASKLET_SOFTIRQ);  
  38. 38.        local_irq_enable();  
  39. 39.    }  
  40. 40.}  
复制代码
可以看到,tasklet其实是软中断中两项,每一项对应的不是一个软中断函数,而是一个链表上的所有函数,在对应的软中断到来时,对应链表中的所有函数都将得到执行。而对于tasklet的唤醒其实就是设置pending位掩码的相应位,使软中断到来时会执行他。
tasklet的内核编程与应用
了解了tasklet的内核实现,对于他的应用就很简单了,首先,你应该分配一个新的tasklet_struct数据结构,并调用tasklet_init函数初始化它。




view plaincopy to clipboard
  1. 01.void tasklet_init(struct tasklet_struct *t,  
  2. 02.          void (*func)(unsigned long), unsigned long data)  
  3. 03.{  
  4. 04.    t->next = NULL;  
  5. 05.    t->state = 0;  
  6. 06.    atomic_set(&t->count, 0);  
  7. 07.    t->func = func;  
  8. 08.    t->data = data;  
  9. 09.}
复制代码
为了重新激活你的tasklet,调用tasklet_enable函数;

为了激活tasklet,根据自己tasklet需要的优先级,调用tasklet_schedule函数或tasklet_hi_schedule函数。我们也只看一个




view plaincopy to clipboard
  1. 01.static inline void tasklet_hi_schedule(struct tasklet_struct *t)  
  2. 02.{  
  3. 03.    /*标志位的检查*/  
  4. 04.    if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state))  
  5. 05.        __tasklet_hi_schedule(t);  
  6. 06.}  
复制代码
view plaincopy to clipboard
  1. 01.void __tasklet_hi_schedule(struct tasklet_struct *t)  
  2. 02.{  
  3. 03.    unsigned long flags;  
  4. 04.  
  5. 05.    local_irq_save(flags);  
  6. 06.    t->next = NULL;  
  7. 07.    *__get_cpu_var(tasklet_hi_vec).tail = t;  
  8. 08.    __get_cpu_var(tasklet_hi_vec).tail = &(t->next);  
  9. 09.    /*激活对应softirq_vec[]数组中HI_SOFTIRQ下标
  10. 10.    的软中断,就是tasklet_hi_vec链表*/  
  11. 11.    raise_softirq_irqoff(HI_SOFTIRQ);  
  12. 12.    local_irq_restore(flags);  
  13. 13.}  
复制代码
实现了上面的几个操作流程,当软中断函数一旦被唤醒就由do_softirq函数来执行。


论坛徽章:
0
2 [报告]
发表于 2011-12-27 22:19 |只看该作者
谢谢分享
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP