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机制数据结构间的关联

时间: 2024-10-11 16:11:42

Linux中断下半部tasklet机制的相关文章

linux 中断底半部机制对比(任务队列,工作队列,软中断)--由linux RS485引出的血案【转】

转自:http://blog.chinaunix.net/uid-20768928-id-5077401.html 在LINUX RS485的使用过程中,由于各种原因,最后不得不使用中断底半部机制的方法来进行实现此功能.先讲两个小故事来描述一下,遇到的问题.也是因为自己对底半部机制理解得不透彻.这些故事的前提都是在串口中断中,一定条件后去完成某件事情,但时间上不能超过5ms. 故事一,最开始想到的是用workqueue.印象中workqueue 就是用来做这种事的,并且还记得可以延时一段时间再来

linux中断底半部机制

中断处理程序 ----中断处理程序ISR是在中断发生时被调用时用来处理中断的函数,在中断运行期间,不能 ----执行有可能引起睡眠测操作,不能同用户空间交换数据,不能调用schedule函数,实现 ----中断处理有一个原则,就是尽可能快处理并返回地,但是多数中断产生时要进行大量的 ----耗时处理,为了使中断处理尽可能短并完成后续大量工作,linux引入了一种底半部机制, ----分为顶半部(top half)和底半部(buttomhalf). 底半部机制 ----Tasklet ----工作

《Linux内核设计与实现》读书笔记(八)- 中断下半部的处理

在前一章也提到过,之所以中断会分成上下两部分,是由于中断对时限的要求非常高,需要尽快的响应硬件. 主要内容: 中断下半部处理 实现中断下半部的机制 总结中断下半部的实现 中断实现示例 1. 中断下半部处理 那么对于一个中断,如何划分上下两部分呢?哪些处理放在上半部,哪些处理放在下半部? 这里有一些经验可供借鉴: 如果一个任务对时间十分敏感,将其放在上半部 如果一个任务和硬件有关,将其放在上半部 如果一个任务要保证不被其他中断打断,将其放在上半部 其他所有任务,考虑放在下半部 2. 实现中断下半部

Linux中断完全分析

学习本文可以对linux中断有全面而深刻的认识.本文对Linux中断所涉及的需求.管理机制.中断实现.中断接口(上半部和下半部).驱动使用进行完全分析. 一.中断需求 软件是需求驱动的,软件的出现是为了解决需求和问题的.先知道需求,那理解代码就是为了验证已知的问题:不知道需求,那理解代码就是揣摩设计者的目的.两者相比,前者自然效率跟高. 中断是为了解决异步的需求.紧急的事情或者更高优先级的事情需要先做,就代表异步.例如,手机需要时刻优先响应用户按键或者触摸这个事件,否则用户体验就变差.信号是软件

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

1,Tasklet的概念 tasklet是利用软中断实现的一种下半部机制,tasklet由两类软中断的代表,HI_SOFTIRQ和TASKLET_SOFTIRQ,这两个的区别是HI_SOFTIRQ类型的软中断先于TASKLET_SOFTIRQ类型的软中断先执行. tasklet由tasklet_struct结构表示,每个结构单独代表一个tasklet,在interrupt.h中定义. [cpp] view plaincopy 420 struct tasklet_struct 421 { 422

linux中断的上半部和下半部 【转】

转自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=24690947&id=3491821 一.什么是下半部 中断是一个很霸道的东西,处理器一旦接收到中断,就会打断正在执行的代码,调用中断处理函数.如果在中断处理函数中没有禁止中断,该中断处理函数执行过程中仍有可能被其他中断打断.出于这样的原因,大家都希望中断处理函数执行得越快越好. 另外,中断上下文中不能阻塞,这也限制了中断上下文中能干的事. 基于上面的原因,内核将整个的中

Linux内核源代码情景分析-中断下半部(软中断)

Tasklet机制是一种较为特殊的软中断.Tasklet一词的原意是"小片任务"的意思,这里是指一小段可执行的代码,且通常以函数的形式出现.软中断向量HI_SOFTIRQ和TASKLET_SOFTIRQ均是用tasklet机制来实现的.      从某种程度上讲,tasklet机制是Linux内核对BH机制的一种扩展.在2.4内核引入了softirq机制后,原有的BH机制正是通过tasklet机制这个桥梁来纳入softirq机制的整体框架中的.正是由于这种历史的延伸关系,使得taskl

Linux中断 - tasklet

一.前言 对于中断处理而言,linux将其分成了两个部分,一个叫做中断handler(top half),属于不那么紧急需要处理的事情被推迟执行,我们称之deferable task,或者叫做bottom half,.具体如何推迟执行分成下面几种情况: 1.推迟到top half执行完毕 2.推迟到某个指定的时间片(例如40ms)之后执行 3.推迟到某个内核线程被调度的时候执行 对于第一种情况,内核中的机制包括softirq机制和tasklet机制.第二种情况是属于softirq机制的一种应用场

嵌入式Linux内核tasklet机制(附实测代码)

Linux 中断编程分为中断顶半部,中断底半部 中断顶半部: 做紧急,耗时短的事情,同时还启动中断底半部.中断底半部: 做耗时的事件,这个事件在执行过程可以被中断.中断底半部实现方法: tasklet,工作队列,软中断等机制实现.实际上是把耗时事件推后执行,不在中断程序执行. 什么是tasklet? Tasklet 一词的原意是"小片任务"的意思,这里是指一小段可执行的代码,且通常以函数的形式出现.这个 tasklet 绑定的函数在一个时刻只能在一个 CPU 上运行 ,tasklet(