公开学习文档

公开学习文档


tasklet

<h2>定义</h2> <pre><code class="language-c">// file: linux-2.6.11\kernel\softirq.c /* Some compilers disobey section attribute on statics when not initialized -- RR */ static DEFINE_PER_CPU(struct tasklet_head, tasklet_vec) = { NULL }; static DEFINE_PER_CPU(struct tasklet_head, tasklet_hi_vec) = { NULL }; /* Tasklets */ struct tasklet_head { struct tasklet_struct *list; }; struct tasklet_struct { struct tasklet_struct *next; unsigned long state; atomic_t count; // 锁计数器 void (*func)(unsigned long); unsigned long data; };</code></pre> <p>tasklet 是基于 <code>HI_SOFTIRQ</code> 和 <code>TASKLET_SOFTIRQ</code> 这 2 个类型的软中断基础之上。tasklet_vec (注意是每 CPU 变量)的元素是 <code>tasklet_head</code>,它指向一个 <code>tasklet</code> 链表,里面存放各种任务。</p> <h2>tasklet 流程</h2> <pre><code class="language-c">// file: kernel/softirq.c void __init softirq_init(void) { open_softirq(TASKLET_SOFTIRQ, tasklet_action, NULL); open_softirq(HI_SOFTIRQ, tasklet_hi_action, NULL); }</code></pre> <p>系统初始化的时候,设置 2 个软中断</p> <pre><code class="language-c">// file: E:\ProgramWork\linux\linux-2.6.11\kernel\softirq.c void tasklet_init(struct tasklet_struct *t, void (*func)(unsigned long), unsigned long data) { t-&gt;next = NULL; t-&gt;state = 0; atomic_set(&amp;t-&gt;count, 0); t-&gt;func = func; t-&gt;data = data; }</code></pre> <p>初始化函数很简单。</p> <pre><code class="language-c">// file: E:\ProgramWork\linux\linux-2.6.11\include\linux\interrupt.h static inline void tasklet_disable_nosync(struct tasklet_struct *t) { atomic_inc(&amp;t-&gt;count); smp_mb__after_atomic_inc(); } static inline void tasklet_disable(struct tasklet_struct *t) { tasklet_disable_nosync(t); tasklet_unlock_wait(t); smp_mb(); } static inline void tasklet_enable(struct tasklet_struct *t) { smp_mb__before_atomic_dec(); atomic_dec(&amp;t-&gt;count); }</code></pre> <p>对 tasklet 禁用和启用。本质上是通过设备其 count 字段来实现。</p> <pre><code class="language-c">// file: include/linux/interrupt.h static inline void tasklet_schedule(struct tasklet_struct *t) { if (!test_and_set_bit(TASKLET_STATE_SCHED, &amp;t-&gt;state)) __tasklet_schedule(t); } // file: kernel/softirq.c void fastcall __tasklet_schedule(struct tasklet_struct *t) { unsigned long flags; local_irq_save(flags); // 保存 IF 标记,并禁用中断 t-&gt;next = __get_cpu_var(tasklet_vec).list; __get_cpu_var(tasklet_vec).list = t; raise_softirq_irqoff(TASKLET_SOFTIRQ); local_irq_restore(flags); // 恢复 }</code></pre> <p>激活 tasklet,将其加入 list 队头。</p> <pre><code class="language-c">// file: E:\ProgramWork\linux\linux-2.6.11\kernel\softirq.c 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-&gt;next; if (tasklet_trylock(t)) { // 检查 state 是否有 STATE_RUN 标记。表示在另一个 CPU 上运行? if (!atomic_read(&amp;t-&gt;count)) { // count 表示 tasklet 是否被 disable if (!test_and_clear_bit(TASKLET_STATE_SCHED, &amp;t-&gt;state)) BUG(); t-&gt;func(t-&gt;data); tasklet_unlock(t); continue; } tasklet_unlock(t); // 这里会清 STATE_RUN 标记 } local_irq_disable(); t-&gt;next = __get_cpu_var(tasklet_vec).list; __get_cpu_var(tasklet_vec).list = t; __raise_softirq_irqoff(TASKLET_SOFTIRQ); // 仅仅设置 pending 位图 local_irq_enable(); } } static inline int tasklet_trylock(struct tasklet_struct *t) { return !test_and_set_bit(TASKLET_STATE_RUN, &amp;(t)-&gt;state); } </code></pre> <p>软中断响应函数,就是按照 list 依次执行任务。先将全局 listA 保存到局部 listB,然后清空 listA 以便继续接受新的 task 加入。然后遍历 listB,如果已经有 STATE_RUN 状态,说明有其它人 (谁?) 在执行,则本次忽略本次执行,将 task 加入到 listA 中,也就是下次会执行的全局 list ;另外,如果 task 被 disable,也会忽略本次执行,加入到 listB 中。</p>

页面列表

ITEM_HTML