对于x86硬中断的概念,一直都落在理论的认识之上,直到这两天才(因某个问题)发现Linux的实现却并非如此,这里纠正一下(注意:Linux内核源码更新太快,一个说法的时效性太短,所以需注意我提到的香草内核版本,并且以x86-64架构为基准)。

以前的认识:Linux对硬中断(本文如无特殊说明,都是指普通意义上的可屏蔽硬件中断)的处理有优先级概念,高优先级硬中断可以打断低优先级硬中断。

重新认识:

1,对于x86硬件而言,在文档325462.pdf卷3章节6.9 PRIORITY AMONG SIMULTANEOUS EXCEPTIONS AND INTERRUPTS 提到一个表格,是指如果在同一时刻有多个异常或中断到达,那么CPU会按照一个指定的优先级顺序对它们进行响应和服务,而并不是我之前所想的判断是否可相互打断执行的高低级别。

2,对于Linux系统而言,硬中断之间并没有优先级的概念(虽然Intel CPU提供支持,请参考文档325462.pdf卷3章节10.8.3 Interrupt, Task, and Processor Priority),或者说优先级只有两个,全部关闭或全部开启,如下:

Regardless of what the hardware might support, typical UNIX-type systems only make use of two levels: the minimum (all interrupts enabled) and the maximum (all interrupts disabled).

这意味着,如果一个硬中断处理函数正在执行,只要当前是处于开启中断的情况,那么此时发生的任何另外一个中断都可以打断当前处理函数,从而出现中断嵌套的情况。

值得注意的是,Linux提供对单个中断开启/禁止的接口(以软件实现为主,比如给对应中断描述符desc的status打上IRQ_DISABLED旗标):

void disable_irq(unsigned int irq)void enable_irq(unsigned int irq)

下面来看看Linux的实际处理,其硬中断的一般处理流程(具体可见参考1、2、3以及源代码,以2.6.30.8为例):

硬件中断 -> common_interrupt -> do_IRQ -> handle_irq -> generic_handle_irq_desc -> desc->handle_irq或__do_IRQ。

其中desc->handle_irq是一个回调函数,会根据不同中断类型(I/O APIC、MSI)有不同的指向,比如:handle_fasteoi_irq()、handle_edge_irq(),这可以参考设置函数ioapic_register_intr()和setup_msi_irq()。通过/proc/interrupts可以看到各个中断的具体类型:

[root@localhost ~]# cat /proc/interruptsCPU0 CPU10: 888 0 IO-APIC-edge timer1: 96 112 IO-APIC-edge i80423: 1 0 IO-APIC-edge4: 1 0 IO-APIC-edge7: 0 0 IO-APIC-edge parport08: 1 0 IO-APIC-edge rtc09: 0 0 IO-APIC-fasteoi acpi12: 204 0 IO-APIC-edge i804214: 0 0 IO-APIC-edge ata_piix15: 460641 900 IO-APIC-edge ata_piix16: 0 0 IO-APIC-fasteoi Ensoniq AudioPCI17: 118347 0 IO-APIC-fasteoi ehci_hcd:usb1, ioc018: 70 0 IO-APIC-fasteoi uhci_hcd:usb219: 115143 0 IO-APIC-fasteoi eth024: 0 0 PCI-MSI-edge pciehp25: 0 0 PCI-MSI-edge pciehp26: 0 0 PCI-MSI-edge pciehp27: 0 0 PCI-MSI-edge pciehp28: 0 0 PCI-MSI-edge pciehp...

不管是desc->handle_irq还是__do_IRQ,它们都会调入到另外一个函数handle_IRQ_event()。重点:从CPU接收到中断信号并开始处理,到这个函数为止,都是处于中断禁止状态。为什么?很简单,因为Intel开发者手册上是这么说的,在文档325462.pdf卷3章节6.8.1 Masking Maskable Hardware Interrupts提到:

When an interrupt is handled through an interrupt gate, the IF flag is automati-cally cleared, which disables maskable hardware interrupts. (If an interrupt ishandled through a trap gate, the IF flag is not cleared.)

在CPU开始处理一个硬中断到进入函数handle_IRQ_event()为止的这段时间里,因为处于中断禁止状态,所以不会出现被其它中断打断的情况。但是,在进入到函数handle_IRQ_event()后,立马有了这么两句:

irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action){irqreturn_t ret, retval = IRQ_NONE;unsigned int status = 0;if (!(action->flags & IRQF_DISABLED))local_irq_enable_in_hardirq();...

函数local_irq_enable_in_hardirq()的定义如下:

#ifdef CONFIG_LOCKDEP# define local_irq_enable_in_hardirq() do { } while (0)#else# define local_irq_enable_in_hardirq() local_irq_enable()#endif

宏CONFIG_LOCKDEP用于表示当前是否开启内核Lockdep功能,这是一个调试功能,用于检测潜在的死锁类风险,如果开启,那么函数local_irq_enable_in_hardirq()为空,即继续保持中断禁止状态,为什么Lockdep功能需要保持中断禁止待后文再述,这里考虑一般情况,即不开启Lockdep功能,那么执行函数local_irq_enable_in_hardirq()就会开启中断。

看函数handle_IRQ_event()里的代码,如果没有带上IRQF_DISABLED旗标,那么就会执行函数local_irq_enable_in_hardirq(),从而启用中断。旗标IRQF_DISABLED可在利用函数request_irq()注册中断处理回调时设置,比如:

if (request_irq(uart->port.irq, bfin_serial_rx_int, IRQF_DISABLED,"BFIN_UART_RX", uart)) {

如果没有设置,那么到函数handle_IRQ_event()这里的代码后,因为中断已经开启,当前中断的后续处理就可能被其它中断打断,从而出现中断嵌套的情况。

3,如果新来的中断类型与当前正在执行的中断类型相同,那么会暂时挂起。主要实现代码在函数__do_IRQ()(handle_fasteoi_irq()、handle_edge_irq()类似)内:

/** If the IRQ is disabled for whatever reason, we cannot* use the action we have.*/action = NULL;if (likely(!(status & (IRQ_DISABLED | IRQ_INPROGRESS)))) {action = desc->action;status &= ~IRQ_PENDING; /* we commit to handling */status |= IRQ_INPROGRESS; /* we are handling it */}desc->status = status;/** If there is no IRQ handler or it was disabled, exit early.* Since we set PENDING, if another processor is handling* a different instance of this same irq, the other processor* will take care of it.*/if (unlikely(!action))goto out;

逻辑很简单,如果当前中断被禁止(IRQ_DISABLED)或正在执行(IRQ_INPROGRESS),那么goto cot,所以同种类型中断不会相互嵌套。

4,从这个补丁开始,Linux内核已经全面禁止硬中断嵌套了,即从2.6.35开始,默认就是:

run the irq handlers with interrupts disabled.

因为这个补丁,所以旗标IRQF_DISABLED没用了,mainline内核在逐步删除它。

我仔细检查了一下,对于2.6.34以及以前的内核,如果要合入这个补丁,那么有略微影响的主要是两个慢速驱动,分别为rtc-twl4030和twl4030-usb,需要按照类似开启Lockdep功能一样:

#ifdef CONFIG_LOCKDEP/* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which* we don't want and can't tolerate. Although it might be* friendlier not to borrow this thread context...*/local_irq_enable();#endif

进行主动启用中断。还有另个一个慢速驱动IDE,其驱动中调用的是函数local_irq_enable_in_hardirq(),即它在开启Lockdep功能的情况下并没有明确要求启用中断,所以它应该不受补丁合入影响。嘛,我只是理论分析研究一下,仅供参考,如有风险,请实际操作者自行承担,:)。其它请看参考4,5,6。

参考:

linux高优先级打断低优先级,对Linux x86-64架构上硬中断的重新认识相关推荐

  1. linux的x64与x86_在Linux x86 64机器上链接

    linux的x64与x86 Linking is the process of combining various pieces of code and files in order to const ...

  2. linux内存free低cache高,Linux之free命令buff/cache过高

    在Linux系统中,我们经常用free命令来查看系统内存的使用状态.在一个RHEL6的系统上,free命令的显示内容大概是这样一个状态: free-g 其实:buffers/cache占用的较多,说明 ...

  3. linux 线程优先级的高低和执行顺序的关系,混乱的Linux内核实时线程优先级

    原标题:混乱的Linux内核实时线程优先级 背景 Linux会把进程分为普通进程和实时进程,普通进程采用CFS之类调度算法,而实时进程则是采用SCHED_FIFO或SCHED_RR. 无论优先级高低, ...

  4. 英特尔+性能+linux,Linux 4.20内核在英特尔处理器上性能比Linux 4.19低,附原因解释...

    在最新的Linux 4.20内核(Linux Kernel 4.20)上测试英特尔处理器性能,结果显示,在大多数低中高端英特尔处理器上Linux 4.20内核性能都比Linux 4.19内核的低,比如 ...

  5. linux 进程组id 错乱,【Linux】终端,进程组,作业,会话及作业控制

    终端 概念 在UNIX系统中,用用户通过终端登录系统后得到一一个Shell进程,这个终端成为Shell进程的控制终端 (Controlling Terminal),控制终端是保存在PCB中的信息,而我 ...

  6. linux查看通信延迟,低优先级进程延迟实时进程中的串行通信(Linux)

    我有一个实时的过程,偶尔通过RS232发送到高速摄像机.我还有其他几个实时进程占用大量CPU时间,使用CUDA在几块GPU板上进行图像处理.通常,串行通信速度非常快,每次消息和响应大约需要50 ms. ...

  7. Linux线程属性及优先级设置

    Linux线程属性及优先级设置 [原文引自]http://hikesoso2010.spaces.eepw.com.cn/articles/article/item/86413# 线程的属性由pthr ...

  8. 第41部分-Linux x86 64位汇编MMX使用

    第41部分-Linux x86 64位汇编MMX使用 使用MMX架构需要一下步骤 从整数值创建打包整数值 把打包整数值加载到MMX寄存器中 对打包整数值执行MMX数学操作. 从MMX寄存器获得结果放到 ...

  9. Linux学习总结02——内存管理——Linux在X86上的虚拟内存管理

    Linux内存管理之二:Linux在X86上的虚拟内存管理 本文档来自网络,并稍有改动. 前言 Linux支持很多硬件运行平台,常用的有:Intel X86,Alpha,Sparc等.对于不能够通用的 ...

最新文章

  1. 考考基础部分,谈谈Java集合中HashSet的原理及常用方法
  2. linux shell which 和 whereis 区别
  3. Ubuntu连接WiFi
  4. shiro-权限概述
  5. javafx2_JavaFX 2 GameTutorial第1部分
  6. ZooKeeper Internals -- ZooKeeper内部工作方式
  7. Golang Web入门(4):如何设计API
  8. linux系统结构简概
  9. Python使用matplotlib可视化环形图
  10. 数据库如何避免读取脏数据?
  11. ArcGIS笔记1_如何为shapefile要素定义坐标系
  12. Ae导出 计算机内存,ae导出视频太大怎么办-缩小Ae导出视频大小的方法 - 河东软件园...
  13. 英语语法笔记Day7——并列主从句
  14. 超多惊喜!苹果 iPhone8 最新渲染图曝光
  15. 网络互连有何实际意义?进行网络互连时,有哪些共同的问题需要解决?
  16. mysql 初始化数据库报错
  17. Android引用ttf图标字体库
  18. 打工人抛弃办公室,微软丢掉「Office」
  19. 实现智能化工厂,从导入APS系统开始
  20. 论人工智能创造物的专利权归属

热门文章

  1. 基于skyline的城市三维建模研究
  2. 香侬科技独家对话Facebook人工智能研究院首席科学家Devi Parikh
  3. Struts中ActionForm的生命周期
  4. 基于iOS/Mac平台实现H.265硬编解码
  5. Access to XMLHttpRequest at ‘http://xx‘ from origin ‘http://xx‘ has been blocked by CORS policy:
  6. 等差素数列--蓝桥杯
  7. 视频人脸检测 opencv简单应用
  8. python-pygame与pymunk-台球游戏
  9. Java期末复习题目合集
  10. java三星题之_Java三星题之剪刀石头布(三局两胜)