20135327郭皓--读书笔记四

第七章 中断和中断处理

7.1 中断

  • 中断使得硬件得以发出通知给处理器。
  • 不同的设备对应的中断不同,而每个中断都通过一个唯一的数字标志。
  • 这些中断值通常被称为中断请求(IRQ)线.每个 IRQ线都会被关联二个数值量一一例如, 在经典的 PC 机上, IRQ0是时钟中断,而 IRQ1是键盘中断。但并非所有的中断号都是这样严格定义的。

异常

  • 在操作系统中,讨论中断就不能不提及异常。异常与中断不同,它在产生时必须考虑与 处理器时钟同步。实际上,异常也常常称为同步中断。

7.2 中断处理程序

  • 在响应一个特定中断的时候,内核会执行一个函数,该函数叫做中断处理程序(interrupt handler)或中断服务例程(interrupt service routine, ISR)。产生中断的每个设备都有一个。相应的中断处理程序。
  • 在 Linux 中,中断处理程序就是普普通通的C 函数.只不过这些函数必须按照特定的类型 声明,以便内核能够以标准的方式传递处理程序的信息,在其他方面,它们与一般的函数别无二致。
  • 中断处理程序与其他内核函数的真正区别在于,中断处理程序是被内核调用来响应中断的, 而它们运行于我们称之为中断上下文的特殊上下文中。
  • 中断上下文偶尔也称作原子上下文,因为正如我们看到的,该上下文中的执行代码不可阻塞。
  • 中断可能随时发生,因此中断处理程序也就随时可能执行。所以必须保证中断处理程序能够 快速执行,这样才能保证尽可能快地恢复中断代码的执行。

7.3 上半部与下半部的对比

  

我们一般把中断处理切为两个部分或两半。中断处理程序是上半部(top half) 一一接收到一个中断,它就立即开始执行,但只做有严格时限的工作,例如对接收的中断进行应答或复位硬件,这些工作都是在所有中断被禁止的情况下完成的。能够被允许稍后完成的工作会推迟到下半部(bottom half)去。此后,在合适的时机,下半部会被开中断执行。 

 

7.4 注册中断处理程序

  • 中断处理程序是管理硬件的驱动程序的组成部分。
  • 驱动程序可以通过 request_irq()函数注册-个中断处理程序(它被声明在文件<linux/interrupt.h> 中〉, 并且激活给定的中断线,以处理中断
1 /* request_irq:分配一条给定的中断线 */
2  int request_irq(unsigned int irq,
3      irq_handler_t handler,
4      unsigned long flags, 
5      const char *name, 
6     void *dev) 

第一个参数irq表示要分配的中断号.

第二个参数handler是一个指针,指向处理这个中断的实际中断处理程序。

7.4.1 中断处理程序标志 

第三个参数flags可以为0,也可能是下列一个或多个标志的位掩码。其定义在文件<linux/ interrupt.h>。在这些标志中最重要的是:

    •  IRQF _DISABLED-一该标志被设置后,意味着内核在处理中断处理程序本身期间,要禁止所有的其他中断。
    •  IRQF_SAMPLE_RANOOM一--此标志表明这个设备产生的中断对内核熵池(entropy pool) 有贡献。内核熵池负责提供从各种随机事件导出的真正的随机数。
    •  IRQF _TIMER -一该标志是特别为系统定时器的中断处理而准备的。 
    •  IRQF _SHARED-一此标志表明可以在多个中断处理程序之间共享中断线。

第四个参数 name 是与中断相关的设备的 ASCII 文本表示。

第五个参数 dev 用于共享中断线。

request_ irq()成功执行会返回 0。 如果返回非0值,就表示有错误发生,在这种情况下,指定的中断处理程序不会被注册。

注意, request_irq()函数可能会睡眠,因此,不能在中断上下文或其他不允许阻塞的代码中调用该函数

7.4.3 释放中断处理程序

  • 卸载驱动程序时,需要注销相应的中断处理程序,并释放中断线。
  • 如果指定的中断线不是共享的,那么,该函数删除处理程序的同时将禁用这条中断线.如果中断线是共享的,则仅删除dev所对应的处理程序,而这条中断线本身只有在删除了最后一个处理程序时才会被禁用。

7.5 编写中断处理程序

重入和中断处理程序 
        Linux 中的中断处理程序是无须重入的。当一个给定的中断处理程序正在执行时,相应的中断线在所有处理器上都会被屏蔽掉,以防止在同一中断线上接收另一个新的中断。通常情况下,所有其他的中断都是打开的,所以这些不同中断线上的其他中断都能被处理,但当前中断线总是被禁止的。 由此可以看出,同一个中断处理程序绝对不会被同时调用以处理嵌套的中断。这极大地简化了中断处理程序的编写。
    

 

7.5.1 共事的中断处理程序

  • 共享的处理程序与非共享的处理程序在注册和运行方式上比较相似,但差异主要有以下三处:
    • request_irq()的参数 flags 必须设置 IRQF_SHARED 标志。 
    • 对于每个注册的中断处理程序来说,dev参数必须唯一。 
    • 中断处理程序必须能够区分它的设备是否真的产生了中断。

 

7.6 中断上下文

  • 当执行一个中断处理程序时,内核处于中断上下文( interrput context)中。
  • 进程上下文可以睡眠,也可以调用调度程序。
  • 中断上下文和进程并没有什么瓜葛。与 current 宏也是不相干的
  • 中断上下文具有较为严格的时间限制,因为它打断了其他代码。

 

7.7 中断处理机制的实现

在内核中,中断的旅程开始于预定义入口点,这类似于系统调用通过预定义的异常句柄进入内核。

ret_from_intr()例程类似于初始入口代码

 

7 .8 /proc/interrupts 

procfs是一个虚拟文件系统,它只存在于内核内存,一般安装于/proc目录。在procfs中读写文件都要调用内核函数,这些函数模拟从真实文件中读或写。与此相关的例子是/proc/interrupts文件,该文件存放的是系统中与中断相关的统计信息

 

  

第1列是中断线。 在这个系统中,现有的中断号为0 ~ 2、 4、 5、 12 及 15。这里没有显示没有安装处理程序的中断线。

第2列是一个接收中断数目的计数器。

第3列是处理这个中断的中断控制器。 

7.9 中断控制

    Linux 内核提供了一组接口用于操作机器上的中断状态。这些接口为我们提供了能够禁止当 前处理器的中断系统,或屏蔽掉整个机器的一条中断线的能力,这些例程都是与体系结构相关 的,可以在 <asm/system.h> 和 <asm/irq.h>中找到。 

 

  一般来说, 控制中断系统的原因归根结底是需要提供同步。

7.9.1 禁止和激活中断

 

 

7.9.2 禁止指定中断线

在某些情况下,只禁止整个系统中一条特定的中断钱就够了。 这就是所谓的屏蔽掉(masking out)一条中断线。作为例子,你可能想在对中断的状态操作之前禁止设备中断的传递。为此,Linux 提供了四个接口:

1 void disable_irq(unsigned int irql;
2 void disable_irq_nosync(unsigned int irq) ;
3 void enable_irq(unsigned int irq) ; 
4 void synchronize_irq(unsigned int irq); 

前两个函数禁止中断控制器上指定的中断线,即禁止给定中断向系统中所有处理器的传递。 

所有这三个函数可以从中断或进程上下文中调用,而且不会睡眠。 

禁止多个中断处理程序共享的中断线是不合适的。

7.9.3 中断系统的状态

 

7.10 小结

本章介绍了中断,它是一种由设备使用的硬件资源异步向处理器发信号。实际上,中断就是由硬件来打断操作系统。

大多数现代硬件都通过中断与操作系统通信。

内核提供的接口包括注册和注销中断处理程序、禁止中断、屏蔽中断线以及检查中断系统的状态。

 

posted @ 2016-04-07 14:19  20135327郭皓  阅读(204)  评论(0编辑  收藏  举报