您的位置首页>企业动态>

深入浅出分析Linux设备驱动程序中断

导读大家好,我是极客范的本期栏目编辑小友,现在为大家讲解深入浅出分析Linux设备驱动程序中断问题。一、前言Linux中断宏观上分为两种:软中断

大家好,我是极客范的本期栏目编辑小友,现在为大家讲解深入浅出分析Linux设备驱动程序中断问题。

一、前言

Linux中断宏观上分为两种:软中断和硬中断。这里“软”和“硬”的意思是指软件相关和硬件相关,而不是软件实现的中断或硬件实现的中断。

软中断是“信号机制”。软不是软件中断。Linux使用信号对进程产生各种中断操作。我们现在知道有31个信号,这里省略其细节。感兴趣的读者可以参考相关参考文献[1]。一般来说,软中断是由内核机制的触发事件(如进程运行超时)引起的,但不可忽视的是,大量的软中断也是由硬件相关的中断引起的。比如打印机端口产生硬件中断时,会通知硬件相关的硬中断,硬中断会产生软中断并发送给操作系统内核,让内核根据这个软中断唤醒休眠在打印机任务队列中的处理进程。

硬中断是一般意义上的“中断处理程序”,直接处理硬件发送的中断信号。当硬中断收到它应该处理的中断信号时,它回到自驱动设备,查看设备的状态寄存器,找出发生了什么,并采取相应的行动。我们不会讨论软中断,这是进程调度中需要考虑的问题。因为我们讨论的是设备驱动的中断,所以重点放在硬中断上。我们说的是硬中断,也就是硬件相关的中断。

第二,中断生成

需要中断是因为外设需要通知操作系统她出事了,但中断的功能只是一个设备报警灯。灯亮时,中断处理程序只知道发生了一些事情,但有必要去设备看看发生了什么。也就是说,当中断处理程序得知设备有中断时,它不知道设备发生了什么。只有当它访问设备上的一些状态寄存器时,它才能知道发生了什么以及如何处理它。

设备通过中断线路向中断控制器发送高电平,告知操作系统已经产生中断,操作系统将从中断控制器的状态位知道是哪条中断线路产生了中断。PC机使用的中断控制器是8259,每个8259可以管理8条中断线路,当两个8259级联时,可以控制15条中断线路。这里的中断线路是实电路,通过硬件接口连接到CPU外部的设备控制器。

Iii .伊拉克

不是每个设备都能向中断线路发送中断信号。只有当它控制了某条中断线路时,它才能向这条中断线路发送信号。随着计算机外部设备越来越多,15条中断线路是不够的,中断线路是非常宝贵的资源。要使用中断线路,必须申请中断线路,即IRQ(中断要求)。我们经常把申请中断线路称为申请IRQ或中断号。

IRQ非常有价值,所以我们建议只在设备需要中断的时候申请IRQ,或者在申请IRQ的时候共享中断,让更多的设备可以使用中断。

无论IRQ的使用是独占还是共享,申请IRQ的流程都是一样的,分为三个步骤:

1.检测所有中断线路,查看哪些中断没有被占用。选择这些未使用的中断之一作为设备的IRQ。

2.通过中断应用功能申请选中的IRQ,即指定应用方式是独占还是共享。

3.根据中断应用函数的返回值决定做什么:如果成功,一切都会好的;如果失败,重新应用或放弃应用程序并返回错误。

申请IRQ的过程在参考书的源代码中有详细描述。通过仔细阅读源代码中的一个简短示例,读者可以对中断号的应用有一个深刻的理解。

四.中断处理程序

Linux中的中断处理程序非常有特色。它的一个中断处理程序分为两部分:tophalf和下半部分。之所以有上半部分和下半部分,完全是因为中断处理的效率。

上半部分的功能是‘注册中断’。当中断发生时,他将设备驱动程序中中断例程的下半部分挂在设备执行队列的下半部分,然后什么也不发生——等待新中断的到来。这样,前半部分的执行会非常快,他可以接受更多她负责的设备造成的中断。上半部分之所以快,是因为它完全屏蔽了中断。如果她没有完成执行,其他中断就无法及时处理,只能等到中断处理程序完成。因此,为了尽可能地服务和处理设备产生的中断,中断处理程序必须快速。

然而,一些中断事件的处理是复杂的,所以中断处理程序必须花更多的时间来完成事情。如何解决短时间内完成复杂加工的矛盾?这时,Linux引入了后半部分的概念。下半部分和上半部分最大的区别是下半部分是可中断的,而上半部分是不可中断的。

下半部分几乎完成了中断处理程序的所有工作,因为上半部分只是将下半部分放入他们负责的设备的中断处理程序队列中,然后就不管它了。一般来说,下部负责检查设备,获取导致中断的事件信息,并根据该信息进行处理(通常通过读取设备上的寄存器获得)。如果他在后半段不知道怎么做,就用著名的鸵鸟算法来解决问题——说白了就是忽略了这个事件。

因为下部是可中断的,如果其他设备在其运行过程中中断,下部可以暂时中断,然后该设备的上部可以稍后运行。然而,重要的是要注意,如果设备中断处理程序正在运行,无论它是运行前半部分还是后半部分,只要中断处理程序没有被处理,

在这期间设 备产生的新的中断都将被忽略掉。因为中断处理程序是不可重入的,同一个中断处理程序是不能并行的。

  在Linux Kernel 2.0以前,中断分为快中断和慢中断(伪中断我们这里不谈),其中快中断的下半部也是不可中断的,这样可以保证它执行的快一点。但是由于现在硬件水平不断 上升,快中断和慢中断的运行速度已经没有什么差别了,所以为了提高中断例程事务处理的效率,从Linux kernel 2.0以后,中断处理程序全部都是慢中断的形式了--他们的下半部是可以被中断的。

  但是,在下半部中,你也可以进行中断屏蔽--如果某一段代码不能被中断的话。你可以使用cTI、sTI或者是save_flag、restore_flag来实现你的想法。至于他们的用法和区别,请参看本文指定参考书中断处理部分。

  进一步的细节请读者参看本文指定参考书,这里就不再所说了,详细介绍细节不是我的目的,我的目的是整理概念。

  五、置中断标志位

  在处理中断的时候,中断控制器会屏蔽掉原先发送中断的那个设备,直到她发送的上一个中断被处理完了为止。因此如果发送中断的那个设备载中断处理期间又发送了一个中断,那么这个中断就被永远的丢失了。

  之所以发生这种事情,是因为中断控制器并不能缓冲中断信息,所以当前一个中断没有处理完以前又有新的中断到达,他肯定会丢掉新的中断的。但是这 种缺陷可以通过设置主处理器(CPU)上的"置中断标志位"(sTI)来解决,因为主处理器具有缓冲中断的功能。如果使用了"置中断标志位",那么在处理 完中断以后使用sTI函数就可以使先前被屏蔽的中断得到服务。

 六、中断处理程序的不可重入性

  上一节中我们提到有时候需要屏蔽中断,可是为什么要将这个中断屏蔽掉呢?这并不是因为技术上实现不了同一中断例程的并行,而是出于管理上的考 虑。之所以在中断处理的过程中要屏蔽同一IRQ来的新中断,是因为中断处理程序是不可重入的,所以不能并行执行同一个中断处理程序。在这里我们举一个例 子,从这里子例中可以看出如果一个中断处理程序是可以并行的话,那么很有可能会发生驱动程序锁死的情况。当驱动程序锁死的时候,你的操作系统并不一定会崩 溃,但是锁死的驱动程序所支持的那个设备是不能再使用了--设备驱动程序死了,设备也就死了。

  其中激发PS1的事件会使A1产生一个中断,然后B1去读R1中已有的数据,然后代码C1向R2中写数据。而激发PS2的事件会使A2产生一个中断,然后B2删除R1中的数据,然后C2读去R2中的数据。

  如果PS1先产生,且当他执行到A1和B1之间的时候,如果PS2产生了,这是A2会产生一个中断,将PS2中断掉(挂到任务队列的尾部),然 后删除了R1的内容。当PS2运行到C2时,由于C1还没有向R2中写数据,所以C2将会在这里被挂起,PS2就睡眠在代码C2上,直到有数据可读的时候 被信号唤醒。这是由于PS1中的B2原先要读的R1中的数据被PS2中的B2删除了,所以PS1页会睡眠在B1上,直到有数据可读的时候被信号唤醒。这样 一来,唤醒PS1和PS2的事件就永远不会发生了,因此PS1和PS2之间就锁死了。

  由于设备驱动程序要和设备的寄存器打交道,所以很难写出可以重入的代码来,因为设备寄存器就是全局变量。因此,最简洁的办法就是禁止同一设备的中断处理程序并行,即设备的中断处理程序是不可重入的。

  有一点一定要清楚:在2.0版本以后的Linux kernel中,所有的上半部都是不可中断的(上半部的操作是原子性的);不同设备的下半部可以互相中断,但一个特定的下半部不能被它自己所中断(即同一个下半部不能并行)。

  由于中断处理程序要求不可重入,所以程序员也不必为编写可重入的代码而头痛了。以我的经验,编写可重入的设备驱动程序是可以的,编写可重入的中断处理程序是非常难得,几乎不可能。

  七、避免竞争条件的出现

  我们都知道,一旦竞争条件出现了,就有可能会发生死锁的情况,严重时可能会将整个系统锁死。所以一定要避免竞争条件的出现。这里我不多说,大家 只要注意一点:绝大多数由于中断产生的竞争条件,都是在带有中断的内核进程被睡眠造成的。所以在实现中断的时候,一定要相信谨慎的让进程睡眠,必要的时候 可以使用cli、sti或者save_flag、restore_flag。具体细节请参看本文指定参考书。

  八、实现

  如何实现驱动程序的中断例程,是各位读者的事情了。只要你们仔细的阅读short例程的源代码,搞清楚编写驱动程序中断例程的规则,就可以编写 自己的中断例程了。只要概念正确,在正确的规则下编写你的代码,那就是符合道理的东西。我始终强调,概念是第一位的,能编多少代码是很其次的,我们一定要 概念正确,才能进行正确的思考。

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。