Linux中断延迟之tasklet

发表于:2012-3-27 09:57

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:bullbat专栏    来源:51Testing软件测试网采编

  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();
 }
}

  可以看到,tasklet其实是软中断中两项,每一项对应的不是一个软中断函数,而是一个链表上的所有函数,在对应的软中断到来时,对应链表中的所有函数都将得到执行。而对于tasklet的唤醒其实就是设置pending位掩码的相应位,使软中断到来时会执行他。

21/212>
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号