简介

关键词 ISR,轮询,可屏蔽,不可屏蔽。

中断和异常

中断和异常一般来说都会同时讨论,不过异常和中断稍有不同。中断一般是由硬件产生的中断,是异步的,而异常则是由处理器生成,属于同步的。
常用的中断,定时器中断,外部中断,DAC中断等。
常有的异常,缺页异常,除0错误,段错误等。

Top halves and Bottom halves

Top half

中断处理程序是上半部分。上半部分将在收到中断后立即运行,并且仅执行时间关键的工作,例如确认收到中断或重置硬件。

Bottom half

下半部分用于处理数据,让上半部分处理新的传入中断。下半程运行时启用中断。如有必要,可以禁用中断,但通常应避免这样做,因为这与在监听新中断时处理数据的基本目的相悖。后半部分运行在更方便的时间,并启用所有中断。
例如,使用网卡时:

  1. 当网卡从网络接收数据包时,网卡会立即发出中断。这将优化网络吞吐量和延迟,并避免超时。

内核通过执行网卡的注册中断进行响应。

  1. 中断运行、确认硬件、将新的网络数据包复制到主内存中,并读取网卡以了解更多数据包。这些作业非常重要、时间关键且特定于硬件的工作。
  2. 内核通常需要快速将网络数据包复制到主内存中,因为网卡上的网络数据缓冲区是固定的,且大小很小,尤其是与主内存相比。复制数据包的延迟可能导致缓冲区溢出,传入数据包将覆盖网卡的缓冲区,从而丢弃数据包。
  3. 在主内存中安全地存储网络数据后,将完成中断的作业,并且可以将系统控制返回到生成中断时中断的任何代码。
  4. 数据包的其他处理和处理稍后发生在下半部分。

中断处理的下半部分有四种。

  1. Workqueue
  2. Threaded IRQs
  3. Softirq
  4. Tasklets

关于 bottom-half合集可以查看 bottom-half网页。

ISR中断编程

编写中断程序以前,有以下几点需要注意。

  1. 中断处理程序无法进入睡眠状态,因此避免调用具有的某些函数sleep
  2. 当中断处理程序的一部分代码进入关键部分时,请使用自旋锁而不是互斥锁。因为如果不能使用互斥锁,它将进入睡眠状态,直到需要使用沉默(mute)为止。
  3. 中断处理程序无法与用户空间交换数据。
  4. 中断处理程序必须尽快执行。为了确保这一点,最好将实现分为上半部分和下半部分两部分。处理程序的上半部分将尽快完成工作,然后在下半部分进行较晚的工作,这可以通过softirq或tasklet或工作队列来完成。
  5. 中断处理程序不能重复调用。当处理程序已经在执行时,必须禁用其相应的IRQ,直到处理程序完成为止。
  6. 较高权限的处理程序可以中断中断处理程序。如果要避免被高品质的处理程序打扰,可以将中断处理程序标记为快速处理程序。但是,如果将太多标记为快速处理程序,则系统性能会下降,因为中断等待时间会更长。

    内核中与中断相关的参数

    与中断有关的函数

    1. request_irq(unsigned int irq,irq_handler_t handler,unsigned long flags,const char *name,void *dev_id)
    2. free_irq(unsigned int irq,void *dev_id)
    3. enable_irq(unsigned int irq)
    4. disable_irq(unsigned int irq)
    5. disable_irq_nosync(unsigned int irq)
    6. in_irq()
    7. in_interrupt()

    与中断有关的标志

  • IRQF_DISABLED.
  • IRQF_SAMPLE_RANDOM
  • IRQF_TIMER
  • IRQF_SHARED

    Registering an Interrupt Handler

    ```c

    define IRQ_NO 11

if (request_irq(IRQ_NO, irq_handler, IRQF_SHARED, “etx_device”, (void *)(irq_handler))) { printk(KERN_INFO “my_device: cannot register IRQ “); goto irq; }

  1. <a name="cvpqp"></a>
  2. ### Freeing an Interrupt Handler
  3. ```c
  4. free_irq(IRQ_NO,(void *)(irq_handler));

Interrupt Handler

  1. static irqreturn_t irq_handler(int irq,void *dev_id) {
  2. printk(KERN_INFO "Shared IRQ: Interrupt Occurred");
  3. return IRQ_HANDLED;
  4. }

程序设计

这一个demo一直没有实验成功,等以后深入理解arm 中断再来做这个实验。

参考资料