在設備驅動的中斷處理中經常會用到tasklet,在前面稍微看了下linux的軟中斷後,tasklet就很容易理解了。Tasklet也要用到軟中斷,而tasklet的用法和定時器的用法很相似。
同樣的在main.c中,
start_kernel-->softirq_init
先給出tasklet的結構體定義:
- struct tasklet_struct
- {
- struct tasklet_struct *next;
- unsigned long state;
- atomic_t count;
- void (*func)(unsigned long);
- unsigned long data;
- };
-
- struct tasklet_head
- {
- struct tasklet_struct *head;
- struct tasklet_struct **tail;
- };
-
- static DEFINE_PER_CPU(struct tasklet_head, tasklet_vec);
- static DEFINE_PER_CPU(struct tasklet_head, tasklet_hi_vec);
-
- void __init softirq_init(void)
- {
- int cpu;
-
- for_each_possible_cpu(cpu) {
- int i;
-
- per_cpu(tasklet_vec, cpu).tail =
- &per_cpu(tasklet_vec, cpu).head;
- per_cpu(tasklet_hi_vec, cpu).tail =
- &per_cpu(tasklet_hi_vec, cpu).head;
- for (i = 0; i < NR_SOFTIRQS; i++)
- INIT_LIST_HEAD(&per_cpu(softirq_work_list[i], cpu));
- }
-
- register_hotcpu_notifier(&remote_softirq_cpu_notifier);
-
- open_softirq(TASKLET_SOFTIRQ, tasklet_action);
- open_softirq(HI_SOFTIRQ, tasklet_hi_action);
- }
這樣在softirq_init函數中,首先初始化tasklet_vec
然後注冊tasklet軟中斷,www.linuxidc.com 中斷服務程序是tasklet_action
軟中斷的執行還是由ksoftirqd內核線程來處理。
下面看下tasklet的初始化:
- 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的調度:
- 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_struct加入這個tasklet_vec向量表中
這裡調用raise_softirq_irqoff(TASKLET_SOFTIRQ);
來觸發軟中斷。
那麼,前面的中斷服務程序是tasklet_action就開始執行了:
- static void tasklet_action(struct softirq_action *a)
- {
- struct tasklet_struct *list;
-
- local_irq_disable();
- list = __get_cpu_var(tasklet_vec).head;
- __get_cpu_var(tasklet_vec).head = NULL;
- __get_cpu_var(tasklet_vec).tail = &__get_cpu_var(tasklet_vec).head;
- local_irq_enable();
-
- while (list) {
- struct tasklet_struct *t = list;
-
- list = list->next;
-
- if (tasklet_trylock(t)) {
- if (!atomic_read(&t->count)) {
- if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state))
- BUG();
- t->func(t->data);
- tasklet_unlock(t);
- continue;
- }
- tasklet_unlock(t);
- }
-
- local_irq_disable();
- t->next = NULL;
- *__get_cpu_var(tasklet_vec).tail = t;
- __get_cpu_var(tasklet_vec).tail = &(t->next);
- __raise_softirq_irqoff(TASKLET_SOFTIRQ);
- local_irq_enable();
- }
- }
遍歷tasklet_vec向量表,調用每個tasklet中在注冊時的t->func(t->data);函數。
這樣,tasklet就可以用於中斷的頂半部和底半部。
在中斷處理的頂半部,調用tasklet_schedule函數
Tasklet關聯的tasklet處理函數就是中斷的底半部處理。