Linux中断延迟之tasklet

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

tasklet的内核实现

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

void __init softirq_init(void)   {       int cpu;          for_each_possible_cpu(cpu) {           int i;           /*对tasklet相关pcp变量的初始化*/           per_cpu(tasklet_vec, cpu).tail =               &per_cpu(tasklet_vec, cpu).head;           per_cpu(tasklet_hi_vec, cpu).tail =               &per_cpu(tasklet_hi_vec, cpu).head;           for (i = 0; i < NR_SOFTIRQS; i++)               INIT_LIST_HEAD(&per_cpu(softirq_work_list[i], cpu));       }          register_hotcpu_notifier(&remote_softirq_cpu_notifier);       /*将tasklet 执行函数加入软中断向量中,      这个执行函数会执行tasklet对应一个链表      中的所有函数*/       open_softirq(TASKLET_SOFTIRQ, tasklet_action);       open_softirq(HI_SOFTIRQ, tasklet_hi_action);   }  

open_softirq函数在前面我们已经分析过了,在这里可以看出,两类tasklet以一个软中断的方式加入软中断向量中,而这两种tasklet实际上位两个链表,就是上面的tasklet_hi_vec和tasklet_vec,我们看一个就行了,实现大同小异。

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;/*已调度的tasklet描述符的链表被清空*/       __get_cpu_var(tasklet_vec).tail = &__get_cpu_var(tasklet_vec).head;       local_irq_enable();/*打开本地中断*/          while (list) {/*对于list链表的每个tasklet描述符*/           struct tasklet_struct *t = list;              list = list->next;              if (tasklet_trylock(t)) {               /*通过查看tasklet描述符的count字段,              检查tasklet是否被禁止*/               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);           }           /*运行到这里,表示tasklet被禁止*/           local_irq_disable();           t->next = NULL;           /*重新插入到链表中,然后再次激活软中断*/           *__get_cpu_var(tasklet_vec).tail = t;           __get_cpu_var(tasklet_vec).tail = &(t->next);           /*这里的激活实际上设置位掩码pending          的对应位,使其在软中断时能够被执行*/           __raise_softirq_irqoff(TASKLET_SOFTIRQ);           local_irq_enable();       }   }  

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/22951.html