歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Linux設備驅動下的tasklet

Linux設備驅動下的tasklet

日期:2017/3/1 10:20:18   编辑:Linux編程

在設備驅動的中斷處理中經常會用到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. struct tasklet_head
  10. {
  11. struct tasklet_struct *head;
  12. struct tasklet_struct **tail;
  13. };
  14. static DEFINE_PER_CPU(struct tasklet_head, tasklet_vec);
  15. static DEFINE_PER_CPU(struct tasklet_head, tasklet_hi_vec);
  16. void __init softirq_init(void)
  17. {
  18. int cpu;
  19. for_each_possible_cpu(cpu) {
  20. int i;
  21. per_cpu(tasklet_vec, cpu).tail =
  22. &per_cpu(tasklet_vec, cpu).head;
  23. per_cpu(tasklet_hi_vec, cpu).tail =
  24. &per_cpu(tasklet_hi_vec, cpu).head;
  25. for (i = 0; i < NR_SOFTIRQS; i++)
  26. INIT_LIST_HEAD(&per_cpu(softirq_work_list[i], cpu));
  27. }
  28. register_hotcpu_notifier(&remote_softirq_cpu_notifier);
  29. open_softirq(TASKLET_SOFTIRQ, tasklet_action);
  30. open_softirq(HI_SOFTIRQ, tasklet_hi_action);
  31. }

這樣在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. local_irq_disable();
  5. list = __get_cpu_var(tasklet_vec).head;
  6. __get_cpu_var(tasklet_vec).head = NULL;
  7. __get_cpu_var(tasklet_vec).tail = &__get_cpu_var(tasklet_vec).head;
  8. local_irq_enable();
  9. while (list) {
  10. struct tasklet_struct *t = list;
  11. list = list->next;
  12. if (tasklet_trylock(t)) {
  13. if (!atomic_read(&t->count)) {
  14. if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state))
  15. BUG();
  16. t->func(t->data);
  17. tasklet_unlock(t);
  18. continue;
  19. }
  20. tasklet_unlock(t);
  21. }
  22. local_irq_disable();
  23. t->next = NULL;
  24. *__get_cpu_var(tasklet_vec).tail = t;
  25. __get_cpu_var(tasklet_vec).tail = &(t->next);
  26. __raise_softirq_irqoff(TASKLET_SOFTIRQ);
  27. local_irq_enable();
  28. }
  29. }

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

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

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

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

Copyright © Linux教程網 All Rights Reserved