转自:http://www.cnblogs.com/li-hao/archive/2012/01/12/2321084.html

软中断、tasklet和工作队列并不是Linux内核中一直存在的机制,而是由更早版本的内核中的“下半部”(bottom half)演变而来。下半部的机制实际上包括五种,但2.6版本的内核中,下半部和任务队列的函数都消失了,只剩下了前三者。本文重点在于介绍这三者之间的关系。(函数细节将不会在本文中出现,可以参考文献,点这里

1. 上半部和下半部的区别

上半部指的是中断处理程序,下半部则指的是一些虽然与中断有相关性但是可以延后执行的任务。举个例子:在网络传输中,网卡接收到数据包这个事件不一定需要马上被处理,适合用下半部去实现;但是用户敲击键盘这样的事件就必须马上被响应,应该用中断实现。
两者的主要区别在于:中断不能被相同类型的中断打断,而下半部依然可以被中断打断;中断对于时间非常敏感,而下半部基本上都是一些可以延迟的工作。由于二者的这种区别,所以对于一个工作是放在上半部还是放在下半部去执行,可以参考下面四条:
a)如果一个任务对时间非常敏感,将其放在中断处理程序中执行。
b)如果一个任务和硬件相关,将其放在中断处理程序中执行。
c)如果一个任务要保证不被其他中断(特别是相同的中断)打断,将其放在中断处理程序中执行。
d)其他所有任务,考虑放在下半部去执行。

2. 为什么要使用软中断?

软中断作为下半部机制的代表,是随着SMP(share memory processor)的出现应运而生的,它也是tasklet实现的基础(tasklet实际上只是在软中断的基础上添加了一定的机制)。软中断一般是“可延迟函数”的总称,有时候也包括了tasklet(请读者在遇到的时候根据上下文推断是否包含tasklet)。它的出现就是因为要满足上面所提出的上半部和下半部的区别,使得对时间不敏感的任务延后执行,而且可以在多个CPU上并行执行,使得总的系统效率可以更高。它的特性包括:
a)产生后并不是马上可以执行,必须要等待内核的调度才能执行。软中断不能被自己打断,只能被硬件中断打断(上半部)。
b)可以并发运行在多个CPU上(即使同一类型的也可以)。所以软中断必须设计为可重入的函数(允许多个CPU同时操作),因此也需要使用自旋锁来保护其数据结构。

3. 为什么要使用tasklet?(tasklet和软中断的区别)

由于软中断必须使用可重入函数,这就导致设计上的复杂度变高,作为设备驱动程序的开发者来说,增加了负担。而如果某种应用并不需要在多个CPU上并行执行,那么软中断其实是没有必要的。因此诞生了弥补以上两个要求的tasklet。它具有以下特性:
a)一种特定类型的tasklet只能运行在一个CPU上,不能并行,只能串行执行。
b)多个不同类型的tasklet可以并行在多个CPU上。
c)软中断是静态分配的,在内核编译好之后,就不能改变。但tasklet就灵活许多,可以在运行时改变(比如添加模块时)。
tasklet是在两种软中断类型的基础上实现的,但是由于其特殊的实现机制(将在4.3节详细介绍),所以具有了这样不同于软中断的特性。而由于这种特性,所以降低了设备驱动程序开发者的负担,因此如果不需要软中断的并行特性,tasklet就是最好的选择。

4. 可延迟函数(软中断及tasklet)的使用

一般而言,在可延迟函数上可以执行四种操作:初始化/激活/执行/屏蔽。屏蔽我们这里不再叙述,前三个则比较重要。下面将软中断和tasklet的三个步骤分别进行对比介绍。

4.1.初始化

初始化是指在可延迟函数准备就绪之前所做的所有工作。一般包括两个大步骤:首先是向内核声明这个可延迟函数,以备内核在需要的时候调用;然后就是调用相应的初始化函数,用函数指针等初始化相应的描述符。
如果是软中断则在内核初始化时进行,其描述符定义如下:

  struct softirq_action
          {
                   void (*action)(struct softirq_action *);
                   void*data;
          };

在\kernel\softirq.c文件中包括了32个描述符的数组static struct softirq_action softirq_vec[32];但实际上只有前6个已经被内核注册使用(包括tasklet使用的HI_SOFTIRQ/TASKLET_SOFTIRQ和网络协议栈使用的NET_TX_SOFTIRQ/NET_RX_SOFTIRQ,还有SCSI存储和系统计时器使用的两个),剩下的可以由内核开发者使用。需要使用函数:
         void open_softirq(int nr, void (*action)(struct softirq_action*), void *data)
初始化数组中索引为nr的那个元素。需要的参数当然就是action函数指针以及data。例如网络子系统就通过以下两个函数初始化软中断(net_tx_action/net_rx_action是两个函数):

    open_softirq(NET_TX_SOFTIRQ,net_tx_action);
     open_softirq(NET_RX_SOFTIRQ,net_rx_action);

这样初始化完成后实际上就完成了一个一一对应的关系:当内核中产生到NET_TX_SOFTIRQ软中断之后,就会调用net_tx_action这个函数。
tasklet则可以在运行时定义,例如加载模块时。定义方式有两种:
静态声明

DECLARE_TASKET(name, func, data)
DECLARE_TASKLET_DISABLED(name, func, data)

动态声明

void tasklet_init(struct tasklet_struct *t, void (*func)(unsigned long), unsigned long data)

其参数分别为描述符,需要调用的函数和此函数的参数—必须是unsigned long类型。也需要用户自己写一个类似net_tx_action的函数指针func。初始化最终生成的结果就是一个实际的描述符,假设为my_tasklet(将在下面用到)。

(4.2)激活

激活标记一个可延迟函数为挂起(pending)状态,表示内核可以调用这个可延迟函数(即使在中断过程中也可以激活可延迟函数,只不过函数不会被马上执行);这种情况可以类比处于TASK_RUNNING状态的进程,处在这个状态的进程只是准备好了被CPU调度,但并不一定马上就会被调度。
软中断使用raise_softirq()函数激活,接收的参数就是上面初始化时用到的数组索引nr。
tasklet使用tasklet_schedule()激活,该函数接受tasklet的描述符作为参数,例如上面生成的my_tasklet:

tasklet_schedule(& my_tasklet)

4.3.执行

执行就是内核运行可延迟函数的过程,但是执行只发生在某些特定的时刻(叫做检查点,具体有哪些检查点?详见《深入》p.177)。
每个CPU上都有一个32位的掩码__softirq_pending,表明此CPU上有哪些挂起(已被激活)的软中断。此掩码可以用local_softirq_pending()宏获得。所有的挂起的软中断需要用do_softirq()函数的一个循环来处理。
而对于tasklet,由于软中断初始化时,就已经通过下面的语句初始化了当遇到TASKLET_SOFTIRQ/HI_SOFTIRQ这两个软中断所需要执行的函数:

    open_softirq(TASKLET_SOFTIRQ, tasklet_action, NULL);
     open_softirq(HI_SOFTIRQ, tasklet_hi_action, NULL);

因此,这两个软中断是要被区别对待的。tasklet_action和tasklet_hi_action内部实现就是为什么软中断和tasklet有不同的特性的原因(当然也因为二者的描述符不同,tasklet的描述符要比软中断的复杂,也就是说内核设计者自己多做了一部分限制的工作而减少了驱动程序开发者的工作)。

5.为什么要使用工作队列work queue?(work queue和软中断的区别)

上面我们介绍的可延迟函数运行在中断上下文中(软中断的一个检查点就是do_IRQ退出的时候),于是导致了一些问题:软中断不能睡眠、不能阻塞。由于中断上下文出于内核态,没有进程切换,所以如果软中断一旦睡眠或者阻塞,将无法退出这种状态,导致内核会整个僵死。但可阻塞函数不能用在中断上下文中实现,必须要运行在进程上下文中,例如访问磁盘数据块的函数。因此,可阻塞函数不能用软中断来实现。但是它们往往又具有可延迟的特性。
因此在2.6版的内核中出现了在内核态运行的工作队列(替代了2.4内核中的任务队列)。它也具有一些可延迟函数的特点(需要被激活和延后执行),但是能够能够在不同的进程间切换,以完成不同的工作。

[Linux内核]软中断、tasklet、工作队列的更多相关文章

  1. Linux内核学习之工作队列

    Author       : Toney Email         : vip_13031075266@163.com Date          : 2020.12.02 Copyright : ...

  2. 《深入理解Linux内核》软中断/tasklet/工作队列

    软中断.tasklet和工作队列并不是Linux内核中一直存在的机制,而是由更早版本的内核中的“下半部”(bottom half)演变而来.下半部的机制实际上包括五种,但2.6版本的内核中,下半部和任 ...

  3. linux内核--软中断与tasklet

    硬件中断通常都需要在最短的时间内执行完毕,如果将所有硬件中断相关的处理都放在硬件中断处理程序中,那么就达不到这个目的. 通过linux提供的软中断和tasklet,可以将硬件中断处理程序中可以延迟处理 ...

  4. Linux内核实现透视---工作队列

    作为Linux中断低半部的另一种实现机制的基础,工作队列的出现更多的是为了解决软中断和Tasklet对于用户进程的时间片的不良影响问题的.工作队列本身是可以使用内核线程来替代的,但是使用线程来实现复杂 ...

  5. [Linux内核]软中断与硬中断

    转自:http://blog.csdn.net/zhangskd/article/details/21992933 本文主要内容:硬中断 / 软中断的原理和实现 内核版本:2.6.37 Author: ...

  6. Linux内核实践之工作队列【转】

    转自:http://blog.csdn.net/bullbat/article/details/7410563 版权声明:本文为博主原创文章,未经博主允许不得转载. 工作队列(work queue)是 ...

  7. Linux内核实践之工作队列

    工作队列(work queue)是另外一种将工作推后执行的形式,它和tasklet有所不同.工作队列可以把工作推后,交由一个内核线程去执行,也就是说,这个下半部分可以在进程上下文中执行.这样,通过工作 ...

  8. Linux内核软中断

    1 软中断概述 软中断是实现中断下半部的一种手段,与2.5以前版本的下半段机制不同.软中断可以同时运行在不同的CPU上. 1.1 软中断的表示 内核中用结构体softirq_action表示一个软中断 ...

  9. 2017-2018-1 20179209《Linux内核原理与分析》第五周作业

    一.实验:使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用 环境说明 实验环境为 Ubuntu16.10 和 实验楼环境. 选择39号系统调用实验.39号系统调用为mkdir系统调用. ...

随机推荐

  1. java学习笔记7--抽象类与抽象方法

    接着前面的学习: java学习笔记6--类的继承.Object类 java学习笔记5--类的方法 java学习笔记4--类与对象的基本概念(2) java学习笔记3--类与对象的基本概念(1) jav ...

  2. Linux磁盘扩容

    Linux磁盘扩容 fdisk -l # 查看硬盘信息 lvextend -L +1G /dev/mapper/vg00-lvroot 或者 lvextend -l +%FREE /dev/mappe ...

  3. 将应用发布到WasLiberty的两种方法

    1.直接将War放到defaultserver(或其它自定义server)的dropin目录. 一放进去,war中的app就会随着server启动起来,这个war是会被解压的,用find / -nam ...

  4. C#基础视频教程7.2 如何编写简单游戏

    前面一小节我们实现了简单的碰撞检测,但是实际上游戏的对象并不是一个标准的矩形(小鸟是一个不规则的物体,其实碰撞的管道也是不规则物体),所以如果真的要做的比较完美,我们自己要写一个方法,能够导入一个图像 ...

  5. UISlider 设置增量

    UISlider 设置增量 UISlider *slier = [[UISlider alloc]initWithFrame:CGRectMake(wu500.right, , , )]; slier ...

  6. QtGui.QLineEdit

    A QtGui.QLineEdit is a widget that allows to enter and edit a single line of plain text. There are u ...

  7. [Swift A] - A Swift Tour

    首先说下自己对Swift语言的一点点看法,对于一个写过javascript和常年写java代码的人来说,学习Swift是一件很简单的事情.就像某某人说过,每个人都有弱点和优点,我到目前为止,只是初步的 ...

  8. win10 家庭中文版打开本地组策略编辑器

      win10 家庭中文版打开本地组策略编辑器 CreateTime--2018年5月14日09:01:25 Author:Marydon 1.问题描述 2.问题解析 win10家庭版没有访问本地组策 ...

  9. ubuntu——主题更新,Ubuntu-tweak安装

    1.首先打开终端 2.在终端中输入sudo apt-add-repository ppa:tualatrix/ppa 回车后输入密码等一会,导入密钥 3.再输入sudo apt-get update ...

  10. SQL 横转竖 、竖专横 (转载) 使用Dapper.Contrib 开发.net core程序,兼容多种数据库 C# 读取PDF多级书签 Json.net日期格式化设置 ASPNET 下载共享文件 ASPNET 文件批量下载 递归,循环,尾递归 利用IDisposable接口构建包含非托管资源对象 《.NET 进阶指南》读书笔记2------定义不可改变类型

    SQL 横转竖 .竖专横 (转载)   普通行列转换 问题:假设有张学生成绩表(tb)如下: 姓名 课程 分数 张三 语文 74 张三 数学 83 张三 物理 93 李四 语文 74 李四 数学 84 ...