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)来处理这些负载。

for(;;)
{
if(!softirq_pending(cpu)) //假设没有软中断,则调用schedule()
schedule(); set_current_state(TASK_RUNNING); while(softirq_pending(cpu)){
do_softirq();
if(need_resched()) //如有必要又一次调度,每次迭代之后都会schedule()以便让更重要的进程得到处理机会
schedule();
} set_current_state(TASK_INTERRUPTIBLE);
}

(4)工作队列(work queue)是还有一种将工作任务推后的方式,与软中断和tasklet都不同样。工作队列把工作交给一个内核线程去运行——这个下半部总是在进程上下文中运行。最重要的,工作队列同意又一次调度甚至睡眠

所以,假设推后运行的任务须要睡眠。那么就选择工作队列;假设推后的任务不须要睡眠,那么就选择软件中断或者tasklet。假设须要使用一个能够又一次调度的实体来运行当前中断的下半部任务,就应该使用工作队列。

工作队列是唯一能在进程上下文中运行的下半部实现机制,也仅仅有它才干够睡眠(关键是看你的任务是否须要睡眠)

虽然工作队列的操作处理函数运行在进程上下文中,可是它不能訪问用户空间,由于该内核线程在用户空间没有相关的内存映射。

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

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

(5)下半部机制的选择

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

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

总结:驱动程序的编写者。须要做两个选择。首先,你是不是须要一个可调度的实体来运行须要推后完毕的工作——从根本上来说,你须要推后的工作任务有休眠的须要吗?要是有,那么工作队列就是唯一的选择。否则最好用tasklet。

其次,假设必须专注于性能的提高。那么就考虑软中断吧~

(6)使用下半部机制时。即使是在一个单处理器的系统上,避免共享数据的訪问也是至关重要的。禁止下半部的函数有local_bh_disable()和local_bh_enable(),这两个函数仅仅能禁止和激活本地处理器的软中断和tasklet。

由于工作队列是在进程上下文中运行的,不会涉及异步运行的问题。所以也就不是必需禁止它们运行。

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

request_threaded_irq(unsigned int irq, irq_handler_t handler,
irq_handler_t thread_fn,
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的类型定义例如以下:

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系统须要考虑)。

參考资料:

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. Linux内核:关于中断你需要知道的

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

  4. 深入理解Linux内核-中断和异常

    Linux内核代码查看 http://androidxref.com/ 中断:被定义位一个事件,它能改变处理器执行指令的顺序.它对应硬件(CPU.其他硬件设备)电路产生的电信号. 同步中断:指令执行时 ...

  5. 理解Linux内核之中断控制

    乍一看下边的Linux内核代码,貌似L3389有bug,于是我就绕有兴趣地阅读了一下local_irq_save/local_irq_restore的源代码. /* linux-4.14.12/mm/ ...

  6. Linux 内核PCI 中断

    对于中断, PCI 是容易处理的. 在 Linux 启动时, 计算机的固件已经分配一个唯一的中 断号给设备, 并且驱动只需要使用它. 中断号被存储于配置寄存器 60 (PCI_INTERRUPT_LI ...

  7. Linux 系统下你关注过哪些内核参数,说说你知道的?

    Tcp/ip io cpu memorynet.ipv4.tcp_syncookies = 1#启用syncookiesnet.ipv4.tcp_max_syn_backlog = 8192#SYN队 ...

  8. Linux内核实现中断和中断处理(一)

    Linux实现中断处理 内核是怎么知道应用程序要调用系统调用的呢?或者说应用程序怎么通知系统内核自己需要执行一个系统调用,这是通过软中断实现的,通过引发一个异常来促使系统切换到内核态去执行异常处理程序 ...

  9. linux内核对中断的处理方式

    中断取代了轮询的通知方式,DMA取代了轮询的读写数据方式. 分类软件指令造成的中断(又叫异常,同步中断).    svc, und, abt硬件通过中断请求信号造成的中断(异步中断).  irq,fi ...

随机推荐

  1. easyui源码翻译1.32--Messager(消息窗口)

    前言 使用$.messager.defaults重写默认值对象.下载该插件翻译源码 消息窗口提供了不同的消息框风格,包含alert(警告框), confirm(确认框), prompt(提示框), p ...

  2. Server.MapPath 的使用方法

    Server.MapPath 的使用方法 用法: 1.Server.MapPath ("/") 应用程序根目录所在的位置 如 C:\Inetpub\wwwroot\ 2.Serve ...

  3. 【HDOJ】1026 Ignatius and the Princess I

    这道题搞了很久啊.搜索非常好的一道题.昨天想了2小时,以为是深搜,但后来发现深搜怎么也没法输出正确路径.今天拿宽搜试了一下,问题就是普通的队列宽搜没法得到当前时间最小值.看了一下讨论区,发现优先级队列 ...

  4. jQuery功能一览

    // Hello world!"); }); $("#btn5").click(function(){ $("#test5").val("D ...

  5. ACM ICPC Asia Regional 2011 Kuala Lumpur C题

    看了逆波兰表达式之后,发现真是强悍的数据结构,栈的应用怎么感觉一辈子也学不完了呢 后缀表达式即逆波兰表达式,就是将所有的运算符按照一定的等级全部都安排到数字的后面去,实现正确的运算法则. OK,代码要 ...

  6. asp.net基础

    这篇主要讲述以下基础知识: Request对象 Response对象 Server对象 Cookie对象 Application对象 ViewState对象 <%%>与<%=%> ...

  7. C++类型引用浅析

    C++类型引用浅析 引言 从最早被Bjarne Stroustrup 发明,作为C语言的扩展,到广为人知C++98标准,再到最新的C++11.C++14和C++17标准,C++一直在不断地进步.演化. ...

  8. 使用ssh协议挂载远程文件目录

    安装sshfs 命令:sudo apt-get install sshfs 使用modprobe加载模块 命令:sudo modprobe fuse 设置权限 把下面的<username> ...

  9. Git 钩子

    1. 概念概述 1.1. 安装钩子 1.2. 脚本语言 1.3. 钩子的作用域 2. 本地钩子 2.1. 预提交钩子 Pre-Commit 2.2. 准备提交信息钩子 Prepare Commit M ...

  10. 【Java基础】Java IO流的总结

    Java IO流分为输入流和输出流,而输入流和输出流中又分字符流和字节流.顾名思义,输入流则是输入到程序中计算,输出流是把程序的结果输出到文件或者设备.而字符流输入输出以字符为单位,字节流则是以字节为 ...