Chinaunix首页 | 论坛 | 博客
  • 博客访问: 545149
  • 博文数量: 183
  • 博客积分: 2650
  • 博客等级: 少校
  • 技术积分: 1427
  • 用 户 组: 普通用户
  • 注册时间: 2008-11-22 17:02
文章分类
文章存档

2017年(1)

2015年(46)

2014年(4)

2013年(8)

2012年(2)

2011年(27)

2010年(35)

2009年(60)

分类: LINUX

2013-08-04 21:17:22

原文地址:小任务(tasklet) 作者:leonwang202

一、简介
tasklet是一种“延迟操作”机制,是通过《软中断》来是实现的。
tasklet最大的特点是小任务不会同时执行,这样就不用显式地加锁,把同步的负担由驱动转移到了内核

单CPU情况:
特点1schedule – schedule – run – schedule – run
特点2、同一CPU上,同一tasklet只有一个实例运行

SMP情况:
特点3在CPU_01上schedule过tasklet,必然会在CPU_01上执行tasklet,这个靠《CPU私有变量》实现的  
特点4软中断在SMP下可能会同时运行,同一个tasklet保证在SMP下不会同时运行

每一个tasklet都有如下数据结构
  1. truct tasklet_struct{
  2.     struct tasklet_struct *next;
  3.     unsigned long state;     //可选状态:TASKLET_STATE_SCHED 和 TASKLET_STATE_RUN
  4.     atomic_t count;          //count值为0时,该task才使能,即允许执行
  5.     void (*func)(unsigned long); //钩子函数
  6.     unsigned long data;          //钩子函数的形参
  7. };

以下是两个tasklet_struct的CPU私有变量全局链表 (文件/kernel/softirq.c)
内核的所有tasklet_struct都由这两个链表串起来
  1. static DEFINE_PER_CPU(struct tasklet_head, tasklet_vec) = { NULL };
  2. static DEFINE_PER_CPU(struct tasklet_head, tasklet_hi_vec) = { NULL };

二、相关API

void tasklet_init(struct tasklet_struct *t,void (*func)(unsigned long), unsigned long data);
//初始化count(为0),func,data 这三个成员

void tasklet_schedule(struct tasklet_struct *t)
//检查tasklet状态,如果TASKLET_STATE_SCHED,就啥都不做返回(特点1明白了吧)
//否则,就设置状态为TASKLET_STATE_SCHED,并把tasklet_struct放到当前调度的CPU的全局链表中去

void tasklet_enable(struct tasklet_struct *t); //使tasklet_struct.count减1
void tasklet_disable(struct tasklet_struct *t);//使tasklet_struct.count加1
void tasklet_kill(struct tasklet_struct *t);    //将tasklet移除队列


三、tasklet的实现

tasklet的软中断的注册
  1. start_kernel()
  2.     -->softirq_init()
  3.         -->open_softirq(TASKLET_SOFTIRQ, tasklet_action,NULL)
  4.         -->open_softirq(HI_SOFTIRQ,tasklet_hi_action,NULL)

tasklet的软中断的处理
  1. void __do_softirq(void)
  2. {
  3.  //....省略
  4.   do {
  5.      if (pending & 1) {
  6.         h->action(h); //关键的一句,tasklet、内核timer、网络中断都是在这里搞的
  7.         rcu_bh_qsctr_inc(cpu);
  8.      }
  9.      h++;
  10.      pending >>= 1;
  11.   }while (pending);
  12.   //....省略
  13. }

上面的h->action 就是先前注册的软中断处理例程 tasklet_action

  1. static void tasklet_action(struct softirq_action *a){
  2.     struct tasklet_struct *list;
  3.     local_irq_disable();
  4.     list = __get_cpu_var(tasklet_vec).list;
  5.     __get_cpu_var(tasklet_vec).list = NULL;
  6.     local_irq_enable();
  7.    
  8.     while (list) {
  9.         struct tasklet_struct *t = list;
  10.         list = list->next;
  11.         if (tasklet_trylock(t)) { //这句保证在一个CPU上,同一个tasklet只有一个实例运行(特点2明白了吧)
  12.             if (!atomic_read(&t->count)) { //count值为0,tasklet才能执行
  13.                 if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state))
  14.                     BUG();
  15.                 t->func(t->data); //这句执行tasklet上挂的钩子函数
  16.                 tasklet_unlock(t);
  17.                 continue;
  18.             }
  19.             tasklet_unlock(t);
  20.         }
  21.         local_irq_disable();
  22.        
  23.         //此tasklet已在别的CPU上运行了,在此CPU上也要运行,再把tasklet加到队列中
  24.         t->next = __get_cpu_var(tasklet_vec).list;
  25.         __get_cpu_var(tasklet_vec).list = t;
  26.         __raise_softirq_irqoff(TASKLET_SOFTIRQ);
  27.         local_irq_enable();
  28.     }
  29. }



阅读(940) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~