转自:http://blog.csdn.net/duqi_2009/article/details/38009717

1、中断处理程序与其他内核函数真正的区别在于,中断处理程序是被内核调用来相应中断的,而它们运行于中断上下文(原子上下文)中,在该上下文中执行的代码不可阻塞。中断就是由硬件打断操作系统。

2、异常与中断不同,它在产生时必须考虑与处理器时钟同步。异常被称为同步中断,例如:除0、缺页异常、陷入内核(trap)引起系统调用处理程序异常。

3、不同的设备对应的中断不同,而每个中断都通过一个唯一的数字(中断号)标识。

4、既想让中断处理程序运行得快,又想中断处理程序完成的工作量多,为了在这两个相悖的目标之间达到一种平衡,一般把中断处理分为两个部分。中断处理程序是上半部(top half):接收到一个中断,它就立刻开始执行,但只做有严格时限的工作,例如对接受的中断进行应答或者复位硬件,这些工作都是在中断被禁止的情况下完成的(上半部情况下,中断被禁止);另一部分是下半部(bottom half):能够被允许稍后完成的工作会推迟到下半部。

(1)为什么要用下半部?

中断处理程序执行的时候,当前中断号对应的中断在所有处理器上都会被屏蔽;更糟糕的是,如果处理器程序是IRQF_DISABLED类型,它执行的时候会把本地的所有中断都屏蔽。然而,缩短中断被屏蔽的时间对系统的响应能力和性能都至关重要,所以,我们应该尽力缩短中断处理程序的时间,办法就是把一些工作放到以后去做。关键是:在下半部运行的时候,允许响应所有中断

(2)划分中断上半部和下半部的借鉴原则:

  • 如果一个任务对时间非常敏感,将其放在中断处理程序中执行
  • 如果一个任务和硬件相关,将其放在中断处理程序中执行。
  • 如果一个任务要保证部被其他中断(特别是相同的中断)打断,将其放置在中断处理程序中执行。
  • 其他所有任务,考虑放置在下半部执行

5、例子,网卡驱动程序,当网卡接收到来自网路的数据包时,需要通知内核数据包到了。中断处理程序(top half)立即开始执行:通知硬件,拷贝最新的网络数据到内存,然后读取网卡更多的数据包,这些工作非常紧迫,因为网卡上接受数据包的缓存大小固定;下半部:执行处理和操作数据包的其他工作。

6、Linux提供的实现下半部的机制:(上半部的实现机制只有一种:中断处理程序)

在Linux内核2.6中,内核提供了三种不同形式的下半部实现机制:软中断、tasklet和工作队列。这三种机制从2.3开始引入。软中断用的比较少,tasklet是下半部更常用的一种形式,但是,tasklet是基于软中断实现的。

(1)如果你想加入一个新的软中断,首先应该问问自己为什么用tasklet实现不了,目前只有两个子系统(网络和SCSI)直接使用软中断。软中断只有在那些执行频率很高和连续性很高的情况下才需要使用。如果不需要扩展到多个处理器,那么就使用tasklet吧。tasklet本质上也是软中断,只不过同一个处理器程序的多个实例不能再多个处理器上同时运行。

下半部何时调用?内核在执行完中断处理器程序以后,do_softirq()函数,于是软中断开始执行中断处理程序留给它去完成的剩余任务。大部分tasklet和软中断都是在中断处理程序中被设置成待处理状态,所以最近一个中断返回的时候就是执行do_softirq()的最佳时机。

(2)tasklet_action()和tasklet_hi_action()是tasklet处理的核心。

(3)ksoftirqd辅助线程:每个处理器都有一组辅助处理软中断(和tasklet)的内核线程,当内核中出现大量软中断的时候,这些内核进程就会辅助处理它们。当一个软中断正在执行时,可能会再次触发它自己,内核目前采取的方案是:不会立即处理重新触发的软中断,在大量软中断出现的时候,内核会唤醒一组内核线程(nice值是19)来处理这些负载。

[cpp] view plaincopy print?
  1. for(;;)
  2. {
  3. if(!softirq_pending(cpu)) //如果没有软中断,则调用schedule()
  4. schedule();
  5. set_current_state(TASK_RUNNING);
  6. while(softirq_pending(cpu)){
  7. do_softirq();
  8. if(need_resched()) //如有必要重新调度,每次迭代之后都会schedule()以便让更重要的进程得到处理机会
  9. schedule();
  10. }
  11. set_current_state(TASK_INTERRUPTIBLE);
  12. }

(4)工作队列(work queue)是另一种将工作任务推后的方式,与软中断和tasklet都不相同。工作队列把工作交给一个内核线程去执行——这个下半部总是在进程上下文中执行,最重要的,工作队列允许重新调度甚至睡眠。所以,如果推后执行的任务需要睡眠,那么就选择工作队列;如果推后的任务不需要睡眠,那么就选择软件中断或者tasklet。如果需要使用一个可以重新调度的实体来执行当前中断的下半部任务,就应该使用工作队列。工作队列是唯一能在进程上下文中运行的下半部实现机制,也只有它才可以睡眠(关键是看你的任务是否需要睡眠)。尽管工作队列的操作处理函数运行在进程上下文中,但是它不能访问用户空间,因为该内核线程在用户空间没有相关的内存映射。

注意:mmc驱动中用到了工作队列~

Notice:通常在发生系统调用时,内核会代表用户空间的进程运行,此时它才能访问用户空间,也只有在此时它才会映射用户空间的内存。

(5)下半部机制的选择

对下半部机制的比较
下半部 上下文 顺序执行保障
软中断 中断 没有
tasklet 中断 同类型不能同时执行
工作队列 进程 没有(和进程上下文一样被调度)

从易用性角度来看:工作队列 > tasklet > 软中断

总结:驱动程序的编写者,需要做两个选择。首先,你是不是需要一个可调度的实体来执行需要推后完成的工作——从根本上来说,你需要推后的工作任务有休眠的需要吗?要是有,那么工作队列就是唯一的选择;否则最好用tasklet。其次,如果必须专注于性能的提高,那么就考虑软中断吧~

(6)使用下半部机制时,即使是在一个单处理器的系统上,避免共享数据的访问也是至关重要的。禁止下半部的函数有local_bh_disable()和local_bh_enable(),这两个函数只能禁止和激活本地处理器的软中断和tasklet。因为工作队列是在进程上下文中运行的,不会涉及异步执行的问题,所以也就没必要禁止它们执行。

7、在驱动程序中,要申请中断(注册中断处理程序)

[cpp] view plaincopy print?
  1. request_threaded_irq(unsigned int irq, irq_handler_t handler,
  2. irq_handler_t thread_fn,
  3. unsigned long flags, const char *name, void *dev);

irq  需要申请的irq编号,对于ARM体系,irq编号通常在平台级的代码中事先定义好,有时候也可以动态申请。

handler  中断服务回调函数,该回调运行在中断上下文中,并且cpu的本地中断处于关闭状态,所以该回调函数应该只是执行需要快速响应的操作,执行时间应该尽可能短小,耗时的工作最好留给下面的thread_fn回调处理。

thread_fn  如果该参数不为NULL,内核会为该irq创建一个内核线程,当中断发生时,如果handler回调返回值是IRQ_WAKE_THREAD,内核将会激活中断线程,在中断线程中,该回调函数将被调用,所以,该回调函数运行在进程上下文中,允许进行阻塞操作

flags  控制中断行为的位标志,IRQF_XXXX,例如:IRQF_TRIGGER_RISING,IRQF_TRIGGER_LOW,IRQF_SHARED等,在include/linux/interrupt.h中定义。

name  申请本中断服务的设备名称,同时也作为中断线程的名称,该名称可以在/proc/interrupts文件中显示。

dev  当多个设备的中断线共享同一个irq时,它会作为handler的参数,用于区分不同的设备。free_irq()函数调用的时候,dev的作用就体现出来了。

8、irq_handler_t的类型定义如下:

[cpp] view plaincopy print?
  1. typedef irqreturn_t  (*irq_handler_t)(int,void*);

用typedef 定义了一个函数指针类型irq_handler_t,指向的函数原型返回类型为 irqreturn_t  ;它接收的参数类型就是int 和void* 两个参数

9、request_threaded_irq()函数是可以睡眠的,因为request_threaded_irq()-->proc_mkdir()-->proc_create()-->kmalloc(),而kmalloc()是可以睡眠的。所以,不能在中断上下文中调用该函数。

10、先初始化硬件,然后再注册中断处理程序,以防止中断处理程序在设备初始化完成之前就开始执行。

11、free_irq():如果在给定的中断线上没有中断处理程序,则注销响应的处理程序,并禁用其中断线。

12、中断处理程序即使什么工作也不做,至少需要知道产生中断的设备,告诉它已经收到中断了;对于复杂的设备,可能还需要在中断处理器程序中发送和接收数据,以及执行一些扩充的工作。这些扩充的工作尽可能被推迟到下半部(bottom half)去完成。

13、中断线和中断号是两个相同的概念,irq

14、Linux中的中断处理程序是无需重入的,当一个给定的中断处理程序正在执行时,相应的中断号在所有处理器上都是被屏蔽掉;所以,同一个中断处理程序绝对不会被同时调用以处理嵌套中断。

15、进程上下文:一种内核所处的操作模式,此时内核代表进程执行——例如,执行系统调用或者运行内核线程。在进程上下文中,可以通过current宏关联当前进程。又因为进程是以进程上下文的形式连接到内核的,因此,进程上下文可以睡眠,也可以调用调度程序

16、中断上下文:与进程没什么关系,与current宏也没有关系,所以中断上下文不可以睡眠,在中断上下文中不可以调用任何可能睡眠的函数。

17、中断处理程序打断了其他的代码的执行,所以中断上下文中的代码应该简洁、迅速,尽可能把工作从中断处理程序中分离出来,放在下半部执行。

18、中断处理程序栈的设置是一个内核配置项,如果有的话,是1页大小,即4KB

19、控制中断系统的原因归根结底是需要提供同步。禁止中断提供保护机制,防止来自其他中断程序的并发访问,也能够禁止内核抢占;提供保护机制,防止来自其他处理器的并发访问(SMP系统需要考虑)

转载于:https://www.cnblogs.com/sky-heaven/p/5531416.html

Linux内核:关于中断你需要知道的【转】相关推荐

  1. Linux内核实现中断和中断处理(二)

    第一部分移步传送门召唤!!:http://www.cnblogs.com/lenomirei/p/5562086.html 上回说了Linux内核实现中断会把中断分为两部分进行处理,上回讲了上部分,这 ...

  2. 再思linux内核在中断路径内不能睡眠/调度的原因(2010)【转】

    转自:http://blog.csdn.net/maray/article/details/5770889 Linux内核中断路径中不能睡眠,为什么? 这里就行了很深入的讨论,值得一看:http:// ...

  3. 第三十四期-ARM Linux内核的中断(4)

    作者:罗宇哲,中国科学院软件研究所智能软件研究中心 上一期中我们介绍了ARM Linux内核中外设中断处理的部分流程,这一期我们将继续介绍ARM Linux内核的外设中断处理流程中与中断描述符相关的部 ...

  4. linux内核的中断上下文,Linux操作系统中中断上下文中的互斥

    UP(单CPU系统)上的中断处理 互斥 如果一个中断处理程序的代码访问或者更新了由非中断的代码(通常称为基准代码)使用的同一数据结构,那么就会出现竞争条件. 幸运的是,得到允许的以内核态执行的进程会临 ...

  5. linux内核 sin头文件,Linux内核中中断request_irq详解--中断共享问题解决

    .函数原型如下: 2.4 内核 int request_irq (unsignedintirq,void (*handler)(int,void*,structpt_regs*),unsignedlo ...

  6. linux内核nmi中断,LINUX AM335X NMI中断使用方法

    首先高清楚你要用什么中断,如果是用普通的GPIO去申请中断,那在网上百度就可以了,这里主要讲一下如何使用NMI中断(不可屏蔽中断),自己在这里走了很多弯路,希望可以帮助大家理解,有其他看法的大家在这里 ...

  7. 中断描述符表IDT以及Linux内核IDT表的初始化的基本情况

    IDT,Interrupt Descriptor Table,中断描述符表是CPU用来处理中断和程序异常的. 一 中断和IDT表概要 中断可以由硬件产生(称为外部中断),也可以由软件产生(称为内部中断 ...

  8. Linux 内核中断内幕【转】

    转自:http://www.ibm.com/developerworks/cn/linux/l-cn-linuxkernelint/ 本文对中断系统进行了全面的分析与探讨,主要包括中断控制器.中断分类 ...

  9. Linux内核深入理解中断和异常(1)

    Linux内核深入理解中断和异常(1) rtoax 2021年3月 1. 中断介绍 内核中第一个子系统是中断(interrupts). 1.1. 什么是中断? 我们已经在这本书的很多地方听到过 中断( ...

  10. Linux内核中断和异常分析(上)

    中断,通常被定义为一个事件.打个比方,你烧热水,水沸腾了,这时候你要去关掉烧热水的电磁炉,然后再去办之前手中停不下来的事情.那么热水沸腾就是打断你正常工作的一个信号机制.当然,还有其它的情况,我们以后 ...

最新文章

  1. python indexerror_python – “IndexError:位置索引器超出范围”,当它们明显没有时
  2. ACL,NAACL,EMNLP,IJCNLP以及ACL、EMNLP2021论文模板
  3. 【C++】引用与变量
  4. react native windows 搭建(完整版)
  5. c++内存管理优化之ptmalloc,tcmalloc,jemalloc使用实例
  6. 《系统集成项目管理工程师》必背100个知识点-21监控项目工作ITTO
  7. pat 乙级 1010 一元多项式求导(C++)
  8. 怎样判断一个网站是不是前后端分离的?
  9. 知方可补不足~UPDLOCK更新锁的使用
  10. 深入了解人工智能机器人的应用领域有哪些?
  11. 数据集Pascal VOC2012
  12. 项目开发日报表(第一天)
  13. 信号完整性基础01:从频域出发理解信号(1)-时域和频域
  14. 爬取 bilibili 弹幕数据
  15. 小说阅读翻页分页实现思路
  16. 关于java中method.invoked 传入类型不一样的问题
  17. LINKERD 2.11 中文实战手册
  18. NLP入门开源实践总结
  19. vue-router 采坑记录
  20. QQ空间迁移_【SRX550_HA_以及端口绑定高可靠性尝试】

热门文章

  1. SPSS 26安装教程
  2. python b64encode_Python base64模块详解 | 学步园
  3. python 流式编程_python 使用yield进行数据的流式处理
  4. VHDL读写txt文件
  5. 机器人学习--University of Alberta自主机器人导航课
  6. 回调函数案列(C高级)
  7. MFC的SendMessage函数详解
  8. 如何欺骗服务器时间_域名劫持会怎样?如何解决域名劫持
  9. TensorFlow随笔-多分类单层神经网络softmax
  10. 一文串起从NLP到CV 预训练技术和范式演进