《Linux内核设计与实现》读书笔记(四)-- 中断与中断处理

来源:互联网 发布:知乎 博客园 csdn 编辑:程序博客网 时间:2024/05/22 17:48

  中断机制:让硬件在需要的时候向内核发出信号。

1、中断

  中断使得硬件得以发出通知给处理器。硬件设备生成中断的时候并不考虑与处理器的时钟同步–换言之中断随时可以产生。因此,内核随时可能因为新来的中断而被打断。
  不同的设备对应的中断不同,每个中断都通过一个唯一的数字标志。
  这些中断值通常被称为中断请求(IRQ)线。每个IRQ线都会被关联一个数值量。

2、中断处理程序

  在响应一个特定中断的时候,内核会执行一个函数,该函数叫做中断处理程序或中断服务例程。产生中断的每个设备都有一个相应的中断处理程序。
  中断处理程序是被内核调用来响应中断的,而它们运行于我们称之为中断上下文的特殊上下文。
  中断处理程序随时可能执行,必须保证中断处理程序能够快速执行,这样才能保证尽可能快地恢复中断代码的执行。

3、上半部与下半部的对比

  又想中断处理程序运行得快,又想中断处理程序完成的工作量多,鉴于上述两个目的之间存在此消彼长的矛盾关系,我们把中断处理切为两个部分。上半部:接收到一个中断,它就立即开始执行,但只做有严格时限的工作;能够被允许稍后完成的工作会推迟到下半部去。

4、注册中断处理程序

  中断处理程序是管理硬件的驱动程序的组成部分。每一设备都有相关的驱动程序,如果设备使用中断,那么响应的驱动程序就注册一个中断处理程序。
  驱动程序可以通过request_irq()函数注册一个中断处理程序,并且激活给定的中断线,以处理中断。

/************************************************ @irq: Interrupt line to allocate @handler: Function to be called when the IRQ occurs. @flags: Interrupt type flags @devname: An ascii name for the claiming device*************************************************/int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,const char *name, void *dev)

4.1、中断处理程序标志

  上述中断注册函数第三个参数可以为0,也可能是下列一个或多个标志的位掩码。
  IRQF_DISABLED—-标志内核在处理中断处理程序程序本身期间,要禁止所有其他中断。比较少用。
  IRQF_SAMPLAE_RANDOM—-表明这个设备产生的中断对内核熵池有贡献。内核熵池负责提供从各种随机事件导出的真正的随机数。如果指定该标志,那么来自该设备的中断间隔时间就会作为墒填充到熵池。
  IRQF_TIMER—-为系统定时器的中断处理而准备。
  IRQF_SHARED—-表明可以在多个中断处理程序之间共享中断线。
  第四个参数name是与中断相关的设备的ASCII文本表示。
  第五个参数dev用于共享中断线。当一个中断处理程序需要释放时,dev将提供唯一的标志信息,以便从共享中断线的诸多中断处理程序中删除指定的那一个。
  注意:request_irq()函数可能会睡眠,因此,不能再中断上下文或其他不允许阻塞的代码中调用该函数。为什么会睡眠?proc_mkdir()–>proc_create()–>kmalloc(),kmalloc函数是可以睡眠的。

4.2 一个中断例子

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

  有一点很重要:初始化硬件和注册中断初始化程序的顺序必须正确,以防止中断处理程序再设备初始化完成之前就开始执行。

4.3、释放中断处理程序

void free_irq(unsigned int irq,void *dev);

5、编写中断处理程序

  对于中断处理程序的声明:

static irqreturn_t intr_handler(int irq, void *dev)

  irq:中断号
  dev: 与中断处理程序注册时传递给request_irq()的参数dev一致。
  中断处理程序可能返回两个特殊的值:IRQ_NONE和IRQ_HANDLED。当中断处理程序检测到一个中断,但该中断对应的设备并不是再注册处理函数期间指定的产生源时,返回IRQ_NONE;当中断处理程序被正确调用,且确实是它所对应的设备产生了中断时,返回IRQ_HANDLED。
  中断处理程序通常会标记为static,因为它从来不会被别的文件中的代码直接调用。
  Linux中的中断处理程序是无须重入的。同一个中断处理程序绝对不会被同时调用以处理嵌套的中断。

共享的中断处理程序

共享与非共享的处理程序再注册和运行方式墒比较相似,但差异主要有以下三处:

  • request_irq()的参数flasgs必须设置IRQF_SHARED标志。
  • 对于每个注册的中断处理程序来说,dev参数必须唯一。
  • 中断处理程序必须能够区分它的设备是否真的产生了中断。

  所有共享中断线的驱动程序都必须满足上述要求。

6、中断处理机制

  首先牢记一点:中断处理程序打断了其他的代码。因此所有的中断处理程序必须尽可能的迅速、简洁。尽量吧工作从中断处理程序中分离出来,放在下半部执行,因为下半部可以在更合适的时间运行。
  下图为中断从硬件到内核的路由。
这里写图片描述

7、中断控制方法

函数 说明 local_irq_disable() 禁止本地中断传递 local_irq_enable() 激活本地中断传递 local_irq_save() 保存本地中断传递的当前状态,然后禁止本地中断传递 local_irq_restore() 恢复本地中断传递到给定的状态 disable_irq() 禁止给定中断线,并确保该函数返回之前在该中断线上没有处理程序在运行 disable_irq_nosync() 禁止给定中断线 enable_irq() 激活给定中断线 irqs_disabled() 如果本地中断传递被禁止,则返回非0;否则返回0 in_interrupt() 如果在中断上下文中,则返回非0;如果在进程上下文中,则返回0 in_irq() 如果当前正在执行中断处理程序,则返回非0;否则返回0
阅读全文
0 0