歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Linux設備驅動下的tasklet

在設備驅動的中斷處理中經常會用到tasklet,在前面稍微看了下linux的軟中斷後,tasklet就很容易理解了。Tasklet也要用到軟中斷,而tasklet的用法和定時器的用法很相似。

同樣的在main.c中,

start_kernel-->softirq_init

先給出tasklet的結構體定義:

  1. struct tasklet_struct  
  2. {  
  3.     struct tasklet_struct *next;  
  4.     unsigned long state;  
  5.     atomic_t count;  
  6.     void (*func)(unsigned long);  
  7.     unsigned long data;  
  8. };  
  9.   
  10. struct tasklet_head  
  11. {  
  12.     struct tasklet_struct *head;  
  13.     struct tasklet_struct **tail;  
  14. };  
  15.   
  16. static DEFINE_PER_CPU(struct tasklet_head, tasklet_vec);  
  17. static DEFINE_PER_CPU(struct tasklet_head, tasklet_hi_vec);  
  18.   
  19. void __init softirq_init(void)  
  20. {  
  21.     int cpu;  
  22.   
  23.     for_each_possible_cpu(cpu) {  
  24.         int i;  
  25.   
  26.         per_cpu(tasklet_vec, cpu).tail =  
  27.             &per_cpu(tasklet_vec, cpu).head;  
  28.         per_cpu(tasklet_hi_vec, cpu).tail =  
  29.             &per_cpu(tasklet_hi_vec, cpu).head;  
  30.         for (i = 0; i < NR_SOFTIRQS; i++)  
  31.             INIT_LIST_HEAD(&per_cpu(softirq_work_list[i], cpu));  
  32.     }  
  33.   
  34.     register_hotcpu_notifier(&remote_softirq_cpu_notifier);  
  35.   
  36.     open_softirq(TASKLET_SOFTIRQ, tasklet_action);  
  37.     open_softirq(HI_SOFTIRQ, tasklet_hi_action);  
  38. }  

這樣在softirq_init函數中,首先初始化tasklet_vec

然後注冊tasklet軟中斷,www.linuxidc.com 中斷服務程序是tasklet_action

軟中斷的執行還是由ksoftirqd內核線程來處理。

下面看下tasklet的初始化:

  1. void tasklet_init(struct tasklet_struct *t,  
  2.           void (*func)(unsigned long), unsigned long data)  
  3. {  
  4.     t->next = NULL;  
  5.     t->state = 0;  
  6.     atomic_set(&t->count, 0);  
  7.     t->func = func;  
  8.     t->data = data;  
  9. }  

Tasklet的調度:

  1. void tasklet_init(struct tasklet_struct *t,  
  2.           void (*func)(unsigned long), unsigned long data)  
  3. {  
  4.     t->next = NULL;  
  5.     t->state = 0;  
  6.     atomic_set(&t->count, 0);  
  7.     t->func = func;  
  8.     t->data = data;  
  9. }  

這裡先將剛才初始化的tasklet_struct加入這個tasklet_vec向量表中

這裡調用raise_softirq_irqoff(TASKLET_SOFTIRQ);

來觸發軟中斷。

那麼,前面的中斷服務程序是tasklet_action就開始執行了:

  1. static void tasklet_action(struct softirq_action *a)  
  2. {  
  3.     struct tasklet_struct *list;  
  4.   
  5.     local_irq_disable();  
  6.     list = __get_cpu_var(tasklet_vec).head;  
  7.     __get_cpu_var(tasklet_vec).head = NULL;  
  8.     __get_cpu_var(tasklet_vec).tail = &__get_cpu_var(tasklet_vec).head;  
  9.     local_irq_enable();  
  10.   
  11.     while (list) {  
  12.         struct tasklet_struct *t = list;  
  13.   
  14.         list = list->next;  
  15.   
  16.         if (tasklet_trylock(t)) {  
  17.             if (!atomic_read(&t->count)) {  
  18.                 if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state))  
  19.                     BUG();  
  20.                 t->func(t->data);  
  21.                 tasklet_unlock(t);  
  22.                 continue;  
  23.             }  
  24.             tasklet_unlock(t);  
  25.         }  
  26.   
  27.         local_irq_disable();  
  28.         t->next = NULL;  
  29.         *__get_cpu_var(tasklet_vec).tail = t;  
  30.         __get_cpu_var(tasklet_vec).tail = &(t->next);  
  31.         __raise_softirq_irqoff(TASKLET_SOFTIRQ);  
  32.         local_irq_enable();  
  33.     }  
  34. }  

遍歷tasklet_vec向量表,調用每個tasklet中在注冊時的t->func(t->data);函數。

這樣,tasklet就可以用於中斷的頂半部和底半部。

在中斷處理的頂半部,調用tasklet_schedule函數

Tasklet關聯的tasklet處理函數就是中斷的底半部處理。

Copyright © Linux教程網 All Rights Reserved