[linux内核]中断下半部分——tasklet

1,Tasklet的概念

tasklet是利用软中断实现的一种下半部机制,tasklet由两类软中断的代表,HI_SOFTIRQ和TASKLET_SOFTIRQ,这两个的区别是HI_SOFTIRQ类型的软中断先于TASKLET_SOFTIRQ类型的软中断先执行。

tasklet由tasklet_struct结构表示,每个结构单独代表一个tasklet,在interrupt.h中定义。

 

[cpp] view plaincopy技术分享技术分享
 
  1. 420 struct tasklet_struct  
  2. 421 {  
  3. 422         struct tasklet_struct *next;  
  4. 423         unsigned long state;  //state成员的值在0,TASKLET_STATE_SCHED和TASKLET_STATE_RUN之间取值,TASKLET_STATE_SCHED表明该tasklet已经被调度正准备投入运行。  
  5. 424         atomic_t count;  //tasklet的引用计数,如果它不为0则tasklet被禁止,  
  6. 425         void (*func)(unsigned long);  
  7. 426         unsigned long data;  
  8. 427 };  


tasklet由tasklet_schedule()函数进行调度,

 

 

[cpp] view plaincopy技术分享技术分享
 
  1. <span style="font-weight: bold; font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">2,Tasklet机制</span>  

 

1)声明自己的Tasklet

静态创建:

既可以使用<linux/interrupt.h>中定义的两个宏中的一个DECLARE_TASKLET或DECLARE_TASKLET_DISABLED来静态创建tasklet,前者把创建的tasklet的引用计数器设置为0,该tasklet处于激活状态。另一个把引入计数器设为1,所以该tasklet处于禁止状态。还可以使用tasklet_init()动态创建一个tasklet。

 

[cpp] view plaincopy技术分享技术分享
 
  1. 429 #define DECLARE_TASKLET(name, func, data) \  
  2. 430 struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(0), func, data }  

 

动态创建:

 

[cpp] view plaincopy技术分享技术分享
 
  1. struct msdc_host{  
  2.     struct tasklet_struct card_tasklet;  
  3. };  
  4. struct msdc_host *host;  
  5. tasklet_init(&host->card_tasklet,msdc_tasklet_card,unsigned long arg);//msdc_tasklet_card是tasklet处理函数  
  6. tasklet_hi_schedule(&host->card_tasklet);  
  7.   
  8. 470 void tasklet_init(struct tasklet_struct *t,  
  9. 471                   void (*func)(unsigned long), unsigned long data)  
  10. 472 {  
  11. 473         t->next = NULL;  
  12. 474         t->state = 0;  
  13. 475         atomic_set(&t->count, 0);  
  14. 476         t->func = func;  
  15. 477         t->data = data;  
  16. 478 }  

 

 

2)编写自己的tasklet处理程序

tasklet处理程序必须符合规定的函数类型:void tasklet_handler(unsigned long data)。因为是靠软中断实现,所以tasklet不能睡眠。这意味着你不能在tasklet中使用信号量或其他什么阻塞式函数。如果你的tasklet和其他的tasklet或软中断共享了数据,你必须进行适当的锁保护。

3)调度自己的tasklet

通过调用tasklet_schedule()函数来调度。在tasklet被调度以后在其还没有得到运行机会之前,如果一个相同的tasklet又被调度了,那么它仍只会运行一次。而如果这时它已经开始运行了,那么这个新的tasklet会被重新调度并再次运行。作为一种优化措施,一个tasklet总在调度它的处理器上执行-这是希望更好地利用处理器的高速缓存。可以调用tasklet_disable()函数来禁止某个指定的tasklet,也可以调用tasklet_enable()函数激活一个tasklet。还可以调用tasklet_kill()函数从挂起的队列中去掉一个tasklet。

 

3,ksoftirqd

每个处理器都有一个这样的线程,所有的线程名字都叫ksoftirqd/n,n对应于处理器的编号,这些线程是在最低的优先级上运行(nice值是19),这样好处是它们和其它重要的认为抢夺资源,在空闲的系统上,这个方案也表现良好。

 

4,工作队列和tasklet的区别~

工作队列运行在进程上下文中,可以中断,如果你的中断下半部分需要睡眠,那么应该使用工作队列的机制。

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。