Linux中断下半部tasklet机制

平台:Linux2.6.18

一,      软中断

1.1         在文件<linux/interrupt.h>中

1.1.1     当前内核用到的软中断类型

1 enum
2 {    // HI_SOFTIRQ,TASKLET_SOFTIRQ为tasklet用软中断实现时用到的两个软中断 
3     HI_SOFTIRQ=0,
4     TIMER_SOFTIRQ,
5     NET_TX_SOFTIRQ,
6     NET_RX_SOFTIRQ,
7     BLOCK_SOFTIRQ,
8     TASKLET_SOFTIRQ
9 };

1.1.2     软中断结构体softirq_action

1 struct softirq_action
2 {  //如果my_softirq指向softirq_vec数组的某项
3    //内核调用软中断处理程序action的方式:my_softirq->action(my_softirq);
4    //传递参数my_softirq对将来在结构体中加入新的域时,可以在不改动action参数形式的情
5   //况下,传递新的域
6     void    (*action)(struct softirq_action *);
7     void    *data;
8 };

1.2         在文件kernel/softirq.c中

1.2.1     32个软中断数组

static struct softirq_action softirq_vec[32] __cacheline_aligned_in_smp;

1.2.2     软中断处理程序的注册函数open_softirq

1 void open_softirq(int nr, void (*action)(struct softirq_action*), void *data)
2 {
3     softirq_vec[nr].data = data;
4     softirq_vec[nr].action = action;
5 }

1.2.3     __init softirq_init(void)源码

1 void __init softirq_init(void)
2 {
3     open_softirq(TASKLET_SOFTIRQ, tasklet_action, NULL);
4     open_softirq(HI_SOFTIRQ, tasklet_hi_action, NULL);
5 }

1.2.4     tasklet是通过软中断实现的

HI_SOFTIRQ与TASKLET_SOFTIRQ是tasklet通过软中断实现的关键,关系如图2-1所示。

图1-1 tasklet通过软中断实现的数据结构之间的联系

 

tasklet机制创建HI_SOFTIRQ或TASKLET_SOFTIRQ两种类型的软中断,然后,按照软中断的调度过程去执行对应的tasklet处理程序tasklet_hi_action或tasklet_action。

综合以上可以得出结论:tasklet是通过软中断实现的一种下半部机制。

1.2.5     执行软中断do_softirq()

在do_softirq()函数中执行的关键函数是__do_softirq(),以下分析__do_softirq()中部分重要代码。

 1 #define MAX_SOFTIRQ_RESTART 10
 2 int max_restart = MAX_SOFTIRQ_RESTART;
 3 pending = local_softirq_pending();//pending保存软中断的32位位图,类型对应位为1时等待处理
 4 restart:
 5     /* Reset the pending bitmask before enabling irqs */
 6     set_softirq_pending(0);//先将实际的软中断位图清零。问1:对于tasklet的HI_SOFTIRQ
 7   //或TASKLET_SOFTIRQ类型的软中断同时有多个的情况下,这样清零是否合理?当然
 8   //是否存在同时有多个HI_SOFTIRQ或TASKLET_SOFTIRQ类型的软中断的情况?
 9   //答1:一次do_softirq中调用tasklet_action处理程序时对tasklet_vec整个链表进行处理。
10     local_irq_enable();//后开本地中断
11     h = softirq_vec;
12     do {
13         if (pending & 1) {//类型对应位为1时满足条件,进入处理
14             h->action(h);//在1.2中解释了这种内核调度中断处理程序的方式
15             rcu_bh_qsctr_inc(cpu);
16         }
17         h++;
18         pending >>= 1;
19     } while (pending);
20     local_irq_disable();
21     pending = local_softirq_pending();//问2:HI_SOFTIRQ与TASKLET_SOFTIRQ是在什么时机触发的?
22   //一次do_softirq()无处理完HI_SOFTIRQ或TASKLET_SOFTIRQ软中断的情况是否存在?
23   //如果存在,如何处理的?
24   //答2:触发的时机,目前了解到的有:tasklet_schedule调度时,以及tasklet_action处理函数中tasklet未被处理时。
25   //问题2,根据下面对tasklet_action处理程序的分析可能确定存在。如何处理的,目前分析的一种可能 26   //的处理方式是:在tasklet_action中未被处理的tasklet放回了tasklet_vec,并且都触发了 27   //TASKLET_SOFTIRQ软中断。所以,在本次do_softirq函数的MAX_SOFTIRQ_RESTART次重复 28   //中,会被继续处理。(Am I right?2014年11月2日) 29 if (pending && --max_restart)//在处理软中断的过程中又有新的软中断挂起了,故再次调度,但 30 //不超过MAX_SOFTIRQ_RESTART次。 31 goto restart;

1.1.1     触发软中断raise_softirq(),raise_softirq_irqoff()

在2.5提到软中断的32位位图,如果第n位被设置为1,那么第n位对应类型的软中断等待处理。而将对应位置1 的处理,正是触发软中断。分析函数raise_softirq(),raise_softirq_irqoff()可知,两个函数执行的核心操作是__raise_softirq_irqoff(nr);然后,分析可知,其完成的功能就是将nr对应的软中断位图置1。

1 #define __raise_softirq_irqoff(nr) do { or_softirq_pending(1UL << (nr)); } while (0)
2 #define or_softirq_pending(x)  (local_softirq_pending() |= (x))

二,      tasklet机制

2.1  在文件<linux/interrupt.h>中

2.1.1    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 enum
10 {
11     TASKLET_STATE_SCHED,    /* Tasklet is scheduled for execution */
12     TASKLET_STATE_RUN    /* Tasklet is running (SMP only) */
13 };

2.2 在文件kernel/softirq.c中

2.2.1    两个单处理器数据结构tasklet_vec和tasklet_hi_vec

1 /* Tasklets */
2 struct tasklet_head
3 {
4     struct tasklet_struct *list;
5 };
6 //由tasklet_struct结构体构成的链表
7 static DEFINE_PER_CPU(struct tasklet_head, tasklet_vec) = { NULL };
8 static DEFINE_PER_CPU(struct tasklet_head, tasklet_hi_vec) = { NULL };

2.2.2    调度tasklet

调度函数tasklet_schedule和tasklet_hi_schedule仅有的区别在于分别使用TASKLET_SOFTIRQ和HI_SOFTIRQ,定义在文件<linux/interrupt.h>中,首先检查tasklet的状态是否为TASKLET_STATE_SCHED,如果是已被调度,返回;否则,将TASKLET_STATE_SCHED位置1,然后进入__tasklet_schedule和__tasklet_hi_schedule中,分析__tasklet_schedule如下。

 1 void fastcall __tasklet_schedule(struct tasklet_struct *t)
 2 {
 3     unsigned long flags;
 4 
 5     local_irq_save(flags);
 6     t->next = __get_cpu_var(tasklet_vec).list;//将参数t指向的tasklet插入tasklet_vec链表表头
 7     __get_cpu_var(tasklet_vec).list = t;
 8     raise_softirq_irqoff(TASKLET_SOFTIRQ);//触发TASKLET_SOFTIRQ软中断,对应1.2.5节的问2
 9     local_irq_restore(flags);
10 }

2.2.3    tasklet处理程序

处理程序tasklet_action和tasklet_hi_action功能相似,tasklet_action函数的流程如图2-1所示。

图2-1 tasklet_action流程图

三,      tasklet通过软中断实现的一些理解

以下以TASKLET_SOFTIRQ类型具体分析。

1)在软中断中定义了TASKLET_SOFTIRQ软中断,在do_softirq函数时调用tasklet_action处理函数,进入tasklet处理程序。

2)在tasklet_action处理函数中,根据图2-1 tasklet_action流程图可知,对tasklet_vec链表中符合如下三个条件的tasklet下半部进行了处理。

三个条件是:⑴TASKLET_STATE_RUN位为0;⑵count=0;⑶TASKLET_STATE_SCHED位为1。含义是调度了的tasklet如何没有在其他处理器上运行且没有被禁止,则进行处理。tasklet_hi_action(tasklet_action)处理程序操作tasklet_hi_vec(tasklet_vec)链表。相关数据结构关系如图3-1所示。

图3-1 软中断与tasklet机制数据结构间的关联

 

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