Linux内核学习7:中断与中断处理(1)

为什么要引入中断这个概念?

任何操作系统内核的核心任务,都包含有对连接到计算机上的硬件设备进行有效的管理,如硬盘、蓝光碟机、键盘等。要想管理这些设备,首先要能和它们进行通信。

但是处理器的速度与外围硬件设备的速度不在一个数量级上,因此,如果内核采取让处理器向硬件发送一个请求,然后专门等待回应的办法,就显得效率非常低。

处理方法:让内核在硬件处理请求的期间处理其他事务,等到硬件真正完成了请求操作以后,再回头来对它进行处理。

中断机制:让硬件在需要的时候再向内核发出信号(此处的区别就是由内核主动请求变成硬件主要请求)。

轮询(polling):轮询其实也是处理上述效率低的一种方法,就是让内核定期对设备的状态进行查询,然后做出相应的处理。这也是一种内核主动的方式,但是这种方法的效率也很低,是因为不管硬件设备是正在忙碌着完成任务还是已经大功告成,轮询的周期总是在重复执行。

1 中断的基本概念:关于中断有几个基本的概念需要了解:

1)关于中断发生时刻

硬件设备生成中断的时候并不考虑处理器的时钟同步,即中断随时都可以产生。内核随时可能因为新来的中断而被打断。

2)何为中断

举个简单的例子:当我们敲击键盘的时候,键盘控制器(控制键盘的硬件设备)会发出一个中断,通知操作系统有键按下。

中断的本质就是一个电信号,由硬件设备发向处理器。处理器接到中断后,马上会向操作系统反映此信号的由来,然后就由操作系统负责处理这些新来的数据。

物理学角度分析:

3)如何区分中断类型

不同的设备对应的中断不同,而每个中断都通过一个唯一的数字标志。因此,来自键盘的中断就有别于来自硬盘的中断。从而使得操作系统能够对中断进行区分。

这些中断经常被称作为中断请求(IRQ)线。每IRQ线都会被关联到一个数值

关于IRQ线:

在经典的PC机上,IRQ0是时钟中断,IRQ1是键盘中断。

但是并不是所有的中断号都是这样的,比如说在PCI总线上的设备而言,中断是动态分配的。

4)异常与中断的区别

异常:也叫做同步中断,它在产生时必须与处理器时钟同步。

异常产生的原因大致是由于处理器执行到编程失误而导致的错误指令(如被0除)的时候,或者在执行期间出现特殊情况(如缺页),必须靠内核处理的时候,处理器就会产生一个异常。

2 中断处理程序

1)什么是中断处理程序

在响应一个中断的时候,内核会执行一个函数,该函数叫做中断处理程序或中断服务例程(ISR)。产生每一个中断的每一个设备都有一个相应的中断处理程序。

一个设备的中断处理程序是它设备驱动程序的一部分——设备驱动程序就是用于对设备进行管理的内核代码。

2)中断上下文

为什么要引入中断上下文?

我们还是来图解:

简单的来说:中断随时都可能发生,因此中断处理程序也是随时可能执行。所以必须保证中断处理程序的快速执行,这样才能保证尽可能快的恢复中断代码的执行。

因此就会遇到这样一个问题,对硬件而言,操作系统迅速对其中断进行服务非常重要;但是对于系统其他部分而言,让中断处理程序尽可能早的完成也非常重要。

因此呢就有了上下文的区分,对中断程序上半部分而言,其快速的反应,如上图所示,快速的对硬件反应。但是中断程序需要处理的其他大量工作并不是很紧急。就留在下半部分去处理。

3)注册中断处理程序

中断处理程序是管理硬件的驱动程序的组成部分。每一个设备都有相关的驱动程序,如果设备使用中断(大部分都使用),那么就相应的驱动程序注册一个中断处理程序。

驱动程序(如果编写驱动程序,在接下来的章节会体现)通过request_irq()函数注册一个中断处理程序(它被声明在文件<linux/interrupt.h>中),并激活给定的中断线:

函数原型:

/*request_irq:分配一条给定的中断线*/int request_irq(unsigned int irq;irq_handler_t handler;unsigned long flags;const char *name;void *dev;}

参数说明:

irq:表示要分配的中断号

handler:是一个指针,指向处理这个中断的实际中断处理程序

flags:可以是0,也可以是如下的一个或多个位掩码。其定义在<linux/interrupt.h>里面

有:

IRQF_DISABLED:表示内核在处理中断处理程序本身期间,要禁止所有的其他中断。若不设置,中断处理程序可以与除本身外的其他任何中断同时运行

IRQF_SAMPLE_RANDOM:表明这个设备产生的中断对内核熵池有贡献。内核熵池:负责提供从各种随机事件导出的真正随机数。

IRQF_TIMER:特别的为系统定时器的中断处理准备的。

IRQF_SHARED:表明可以在多个中断处理程序之间共享中断线。

name:与中断相关设备的ASCII文本表示

dev:用于共享中断线。当一个中断处理程序需要释放时,dev将提供唯一的标志信息,以便从共享中断线的诸多中断处理程序中删除指定的一个。如果无需共享中断线,那么此值就为NULL。

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

实例分析:

要求:在一个驱动程序中请求一个中断线,并通过request_irq()安装中断处理:

request_irq():if(request_irq(irqn,my_interrupt,IRQF_SHARED,"my_device",my_dev)){printk(KERN_ERR "my_device:cannot register IRQ%d\n",irqn);return -EIO;

分析:irqn是请求的中断线;my_interrupt是中断处理程序;设置成可共享中断线;设备命名为"my_device";最后传递my_dev变量给dev形参。

4)卸载中断处理程序

卸载驱动程序时,需要注销相应的中断处理程序,并释放中断线。此时需要调用

void free_irq(unsigned int irq,void *dev)

说明:如果中断线不是共享的,那么,该函数删除处理程序的同时将禁用这条中断线。如果中断线是共享的,则仅仅删除dev所对应的处理程序,而这条中断线本身只有在删除了最后一个处理程序时才会禁用

三亚呀——赴一个蓝天碧海。只是微笑地固执自己的坚持,

Linux内核学习7:中断与中断处理(1)

相关文章:

你感兴趣的文章:

标签云: