发博文
正文 字体大小:

linux下半部 之 tasklet 结构分析

(2009-09-09 18:22:10)
标签:

it

分类: kernel

主要数据结构


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

 


tasklet 是在 softirq 的基础上实现的,基于HI_SOFTIRQ(软中断0) 和 TASKLET_SOFTIRQ(软中断5)。
这两个tasklet只是在优先级上有区别。
在初始化的时候,对应的HI_SOFTIRQ 和 TASKLET_SOFTIRQ 的 action分别被设置为 tasklet_hi_action() 和 tasklet_action()。


tasklet 和 高优先级tasklet 分别存放在 PER_CPU  变量 tasklet_vec 和 tasklet_hi_vec 中,类型为 struct tasklet_head.

对于每一个CPU,维护一个tasklet的链表,如下图所示:

                                                                                             
                                                                                             
                                                                                       
                                                                                             
                                                                                       
                            /---------\        /---------\                                   
                                                                           
                            CPU#0        CPU#1         ......                    
                                                                           
                            \---------/        \---------/                                   
                                                                                       
                                                                                             
                                                                                       
                                                                                             
                                                                                       
                                                                                             
                         +-----------------+-----------------+---------------                
                         tasklet_head   tasklet_head                                
     tasklet_vec[NR_CPUS]| +-------------+ | +-------------+ |   ......                      
                         | |   *list     | | |   *list     | |                               
                         | +-------------+ | +-------------+ |                               
                         +-----------------+-----------------+---------------                
                                                                                             
                                                                                       
                                                                                             
                                                                                       
                                                                                             
                         +-----------------+-----------------+---------------                
                         tasklet_head   tasklet_head                          
  tasklet_hi_vec[NR_CPUS]| +-------------+ | +-------------+ |   ......                
                         | |   *list     | | |   *list     | |                         
                         | +-------------+ | +-------------+ |                         
                         +-----------------+-----------------+---------------          
                                                                                 
                                                                                       
                                                                                 
                                                                                       
                                                                                 
                                                                                       
                                                                                       
                                                                                       
                                                                                       
                                                                                       
                                                                                       
                                                                                       
                                                                                       
                                                                                       
                                                                                       
                                                                                      
                                                                                       
                                                                                       
  /---------------------------------------------------------------------------\        
                                                                                 
   CPU#0                                                                         
                                                                            
                                                                            
                                                                            
                                                                            
    tasklet_head    /--> tasklet_struct   /--> tasklet_struct               
   +-------------+   +--------------+   +--------------+    /------\ |   
    *list     |--/     *next     |--/     *next     |--->| NULL | |   
   +-------------+      +--------------+      +--------------+    \------/ |   
                          state           state                 
                        +--------------+      +--------------+              
                          count           count                 
                        +--------------+      +--------------+              
                        (*func)()       (*func)()               
                        +--------------+      +--------------+              
                          data            data                  
                        +--------------+      +--------------+              
                                                                            
  \---------------------------------------------------------------------------/   
                                                                                  
                                                                                  
                                                                                  
  /---------------------------------------------------------------------------\   
                                                                            
   CPU#1                                                                    
                                                                            
                                                                            
                                                                            
                                                                            
    tasklet_head    /--> tasklet_struct   /--> tasklet_struct               
   +-------------+   +--------------+   +--------------+    /------\ |   
    *list     |--/     *next     |--/     *next     |--->| NULL | |   
   +-------------+      +--------------+      +--------------+    \------/ |   
                          state           state                 
                        +--------------+      +--------------+              
                          count           count                 
                        +--------------+      +--------------+              
                        (*func)()       (*func)()               
                        +--------------+      +--------------+              
                          data            data                  
                        +--------------+      +--------------+              
                                                                            
  \---------------------------------------------------------------------------/   
                                                                                  
                                                                                  
 
 

 

初始化一个tasklet通过函数 tasklet_init() ,该函数会初始化 tasklet_struct 中的各个成员:
void tasklet_init(struct tasklet_struct *t,
    void (*func)(unsigned long), unsigned long data)
{
 t->next = NULL;
 t->state = 0;
 atomic_set(&t->count, 0);
 t->func = func;
 t->data = data;
}


调度一个tasklet 通过函数 tasklet_hi_schedule() 或者 tasklet_schedule()。
他们做的事情类似,以下本文将以tasklet_schedule()为例来说明。

tasklet_schedule() 首先会判断该 tasklet 是否已经被调度过,对于同一个tasklet,在同一时刻只能被调度一次,这通过 tasklet的 state中的 TASKLET_STATE_SCHED 位来标记。
然后会将 tasklet 插入到当前CPU的tasklet_vec 的list中。
然后触发taskt的softirq

当触发一个tasklet的时候,对应的softirq会被执行,即会执行 tasklet_hi_action() 或者 tasklet_action().
而这两个函数,就会遍历该CPU上的tasklet链表,依次执行各个tasklet的func函数,执行的tasklet会从链表上删除掉。
tasklet 在执行的时候, state中的 TASKLET_STATE_RUN 位会被置位,然后会清除 state 的 TASKLET_STATE_SCHED 位。
执行完毕后,state中的 TASKLET_STATE_RUN 位会被清除掉。
如果在执行前, state中的 TASKLET_STATE_RUN 位会被置位,说明当前类型的tasklet正在另一个CPU上被执行,此时需要等待其在另一个CPU上执行完。

出现这种情况的原因是:
对于一个tasklet, TASKLET_STATE_SCHED 标记该tasklet是否被调度,TASKLET_STATE_RUN 标记该 tasklet 是否正在执行。
tasklet的状态顺序如下图所示:

                                                    
                
                
                
                                                     
                                   init               
                      +---------------------------+   
                      | clear TASKLET_STATE_SCHED |   
                      | clear TASKLET_STATE_RUN    
                      +---------------------------+   
                                   ||                 
                                   ||                 
                                   ||                 
                                   ||                 
                                   ||                 
                                   ||                 
                                   \/     
                             /------------\
                               idle    |
                             \------------/
                                   ||     
                                   ||                    
                                   ||                    
                                   ||                    
                                   ||                    
                                   ||                    
                                   \/     
                                                            
                           tasklet_schedule                 
               +-----------------------------------------+                 
                                                                     
                  /------------------------------\     /--------\    
                                              | no |           
                  TASKLET_STATE_SCHED == 0 ?  |----|-->| return |    
                                                         
                  \------------------------------/     \--------/    
                                                                  
                                |yes                  |
                                                   |
                                                   |
                     +-------------------------+        
                     | set TASKLET_STATE_SCHED |        
                     +-------------------------+        
                               ||                       
               +------------------||---------------------+    
                                  ||                          
                                  ||                          
                                  ||                             
                                  ||                             
                                  \/         
                                             
                           tasklet_action    
               +-----------------------------------------+
                                                      |
                  /------------------------------\    |
                                                |
                    TASKLET_STATE_RUN == 0 ?  |<------------\
                                                      |
                  \------------------------------/          |
                                                      |
                            yes|       |no                  |
                                                      |
                                    \----------->-----------/
                                                   |
                   +--------------------------+       |
                   set TASKLET_STATE_RUN        |
                   +--------------------------+       |
                                                   |
                                                   |
                                                   |
                                                   |
                                                   |
                   +---------------------------+      |
                   | clear TASKLET_STATE_SCHED |      |
                   +---------------------------+      |
                                                   |
                                                   |
                                                   |
                                                   |
                                                   |
                   +--------------------------+       |
                    run tasklet function        |
                   +--------------------------+       |
                                                   |
                                                   |
                                                             
                                                             
                                                             
                   +--------------------------+                 
                   | clear TASKLET_STATE_RUN                 
                   +--------------------------+                 
                              ||                                
                              ||                                
               +-----------------||----------------------+
                                 ||
                                 ||
                                 ||    
                                 \/    
                             /--------\
                                   |
                             | return |
                                   |
                             \--------/             
                                                    
                                                    
                                                    
注意:图中的 return表明函数返回,此时tasklet的状态并不一定是idle的。
                                                    

在这里要注意,在tasklet_action 的时候,set TASKLET_STATE_RUN 之后 clear TASKLET_STATE_SCHED,然后才执行taskletlet。
而在此过程中,中断是开的,这个时候,tasklet的 TASKLET_STATE_SCHED 为0, 此时在另外一个CPU上,是可以schedule该tasklet的(因为 TASKLET_STATE_SCHED 为0)。
但是由于 TASKLET_STATE_RUN 在tasklet 的function执行完后才被 clear,因而,在另一个CPU上,即使 schedule 了该 tasklet,也必须等到原来的CPU上的 tasklet执行完才能 Run。

可以看出,通过 TASKLET_STATE_SCHED 和 TASKLET_STATE_RUN 这两个标记,保证了在同一时刻,一个 tasklet 只能在一个CPU上执行。

 

 

 

参考资料:

[1] Understanding linux kernel 3rd

[2] linux kernel 2.6.23.11

 

阅读 评论 收藏 转载 打印举报
已投稿到:
  • 评论加载中,请稍候...

       

    验证码: 请点击后输入验证码 收听验证码

    发评论

    以上网友发言只代表其个人观点,不代表新浪网的观点或立场。

      

    新浪BLOG意见反馈留言板 不良信息反馈 电话:4006900000 提示音后按1键(按当地市话标准计费) 欢迎批评指正

    新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 会员注册 | 产品答疑

    新浪公司 版权所有