同级中断可以嵌套吗_中断引发的面试教训

61ccf8dd4327fcc9ed24887198ef28e4.png
d31476ca4208054718bb739b22e8a926.png

01

中断引发的面试教训

2546769222e8755933025d7ab53aebaa.png
2d7d968509772f0f292b69806dfdc78c.png
3d08f9d72e128eef829882bd5ca23b9d.png
2d7661a6a57d17f0d593cd65c1c9388d.png
1b47a45e87bc6772c415c73f01011d66.png

02

什么是中断?

中断:(英语:Interrupt)指当出现需要时,CPU暂时停止当前程序的执行转而执行处理新情况的程序和执行过程。

即在程序运行过程中,系统出现了一个必须由CPU立即处理的情况,此时,CPU暂时中止程序的执行转而处理这个新的情况的过程就叫做中断。

中断 在嵌入式软件中几乎不能离开它,你看到的几乎所有的芯片都有中断功能,不管是裸机程序STC89C51还是嵌入式Linux系统,还是其他的RTOS系统都有中断。每个外接设备申请一个唯一的中断号,让外设发生中断时,向CPU报告自己的中断号,CPU知道是哪个设备发生中断,然后执行相对应的操作。

bdce5a5961ed7544f329a315d77190f0.png

03

为什么要用中断?

ccf53fb835b536f12e7b9f8d3b3573d7.png

04

Linux中断子系统

3dc2c1d4897db0b934bfc356bf7a792a.png

4.1、中断系统相关硬件描述

20a6453caee196fa397e6890ef274f4f.png
6782620f29f902c4f4bdfa1c014e7be1.png
cb12dae8f4ca8e9e57205dae34999164.png

4.1.1、多个Interrupt controller和多个cpu之间的拓扑结构

843048d1ce2291356f5f50fc7cd3e42f.png
  • 第一种,就是有一个Root GIC(Generic Interrupt Controller)连接多个CPU,然后second GIC 接在 Root GIC上,Sencond GIC只负责上报中断信息给Root GIC,Root GIC负责接收Second GIC中断信息然后给CPU汇报中断信息。
cbe942fe8c757f4ad0440762c6c80d30.png
  • 第二种就是Root GIC 负责给cpu0-cpu4汇报工作,Second GIC负责给cpu3-cpu7汇报工作。这样设计的弊端就是Second GIC上的中断信号不能传给Cpu0-Cpu3,这样的设计理论上不是很完美。
979c80196c68ebec0c8da980bfbf8827.png

4.1.2、Interrupt controller把中断事件送给哪个CPU?

afb786de58b991bfe250f33021dc55e5.png

在 SMP 体系结构中(cpu三大架构 numa smp mpp 之一),我们可以通过调用系统调用和一组相关的宏来设置 CPU 亲和力(CPU affinity),将一个或多个进程绑定到一个或多个处理器上运行。

中断在这方面也毫不示弱,也具有相同的特性。中断亲和力是指将一个或多个中断源绑定到特定的 CPU 上运行。中断亲和力最初由 Ingo Molnar 设计并实现。

在 /proc/irq 目录中,对于已经注册中断处理程序的硬件设备,都会在该目录下存在一个以该中断号命名的目录 IRQ# ,IRQ# 目录下有一个 smp_affinity 文件(SMP 体系结构才有该文件),它是一个 CPU 的位掩码,可以用来设置该中断的亲和力, 默认值为 0xffffffff,表明把中断发送到所有的 CPU 上去处理。如果中断控制器不支持 IRQ affinity,不能改变此默认值,同时也不能关闭所有的 CPU 位掩码,即不能设置成 0x0。

举个栗子

我们以网卡(eth1,中断号 44 )为例,在具有 8 个 CPU 的服务器上来设置网卡中断的亲和力(以下数据出自内核源码 DocumentationIRQ-affinity.txt):

[root@moon 44]# cat smp_affinityffffffff[root@moon 44]# echo 0f > smp_affinity[root@moon 44]# cat smp_affinity0000000f[root@moon 44]# ping -f hPING hell (195.4.7.3): 56 data bytes...--- hell ping statistics ---6029 packets transmitted, 6027 packets received, 0% packet lossround-trip min/avg/max = 0.1/0.1/0.4 ms[root@moon 44]# cat /proc/interrupts | grep 44: 44: 0 1785 1785 1783 1783 1 1 0 IO-APIC-level eth1[root@moon 44]# echo f0 > smp_affinity[root@moon 44]# ping -f hPING hell (195.4.7.3): 56 data bytes..--- hell ping statistics ---2779 packets transmitted, 2777 packets received, 0% packet lossround-trip min/avg/max = 0.1/0.5/585.4 ms[root@moon 44]# cat /proc/interrupts | grep 44: 44: 1068 1785 1785 1784 1784 1069 1070 1069 IO-APIC-level eth1[root@moon 44]#

在上例中,我们首先只允许在 CPU0-3 上处理网卡中断,接着运行 ping 程序,不难发现在 CPU4-7 上并没有对网卡中断进行处理。然后只在 CPU4-7 上对网卡中断进行处理, CPU0-3 不对网卡中断进行任何处理,运行 ping 程序之后,再次查看 /proc/interrupts 文件时,不难发现 CPU4~7 上的中断次数明显增加,而 CPU0~3 上的中断次数没有太大的变化。

44dd9c46ecf8f2af5c25f4c4bf34d917.png

4.2、中断子系统相关的软件框架

c2a6d7b8226899c250b6b4efb5f1b200.png

4.2.1、中断上半部分和下半部分

中断处理程序的这两个目标相互冲突:

  • 快点执行
  • 执行大量工作

由于这些竞争目标,中断的处理分为两部分或一半:

  • 上半部分。中断处理程序是上半部分。上半部分在收到中断后立即运行,仅执行对时间要求严格的工作,例如确认收到中断或重置硬件。
  • 下半部分。可以在以后执行的工作推迟到下半部分。下半部分将在更方便的时间运行,并启用所有中断。

4.2.2、中断分类

中断如果分为两大类,那就是同步中断和异步中断,如果根据中断原因来分,可以分为四种。具体如下图:

38c5542ff9fb1a56cee198527b5ca363.png
7fb314dbe65d3264528109083b92d209.png

4.2.3、中断上下文

执行中断处理程序时,内核处于中断上下文中。

与进程上下文的区别:

  • 进程上下文是内核在代表进程执行时所处的操作模式,例如执行系统调用或运行内核线程。
  • 在进程上下文中,current宏(在内核中,可以通过current宏来获得当前执行进程的task_struct指针)指向关联的任务。
  • 由于进程在进程上下文中耦合到内核,因此进程上下文可以休眠或以其他方式调用调度程序。

current宏在发生中断的时候,它指向中断的进程。

没有后备进程,中断上下文无法休眠,无法重新安排。因此,您无法从中断上下文中调用某些函数。如果函数休眠,则不能从中断处理程序中使用它:这限制了可以从中断处理程序调用的函数。中断上下文是时间关键的,因为中断处理程序会中断其他代码。

应该记住,中断处理程序已经中断了其他代码(可能甚至是另一行上的另一个中断处理程序)。由于异步性质,所有中断处理程序必须尽可能快速和简单。应尽可能地将工作从中断处理程序中推出,并在下半部分执行,后者在更方便的时间运行。

4.2.4、linux kernel的中断子系统

架构图如下所示:

b27827e8475e4ff1ee84bdd06bc146d1.png

由上面的block图,我们可知linux kernel的中断子系统分成4个部分:

  • 硬件无关的代码,我们称之Linux kernel通用中断处理模块。无论是哪种CPU,哪种controller,其中断处理的过程都有一些相同的内容,这些相同的内容被抽象出来,和HW无关。此外,各个外设的驱动代码中,也希望能用一个统一的接口实现irq相关的管理(不和具体的中断硬件系统以及CPU体系结构相关)这些“通用”的代码组成了linux kernel interrupt subsystem的核心部分。
  • CPU architecture相关的中断处理。 和系统使用的具体的CPU architecture相关。
  • Interrupt controller驱动代码 。和系统使用的Interrupt controller相关。
  • 普通外设的驱动。这些驱动将使用Linux kernel通用中断处理模块的API来实现自己的驱动逻辑。

4.2.5、中断调试

  • 用示波器查看硬件是否真实产生了中断;
  • cat /proc/interrupts 里面列举了系统申请的所有中断,查看自己注册的中断是否在里面;
  • cat cat /proc/irq/[num]/ 里面很多可以查看和调试的参数。

4.2.6、Linux中断是否可以嵌套吗?

564057478eeff1d3ca879d7660715dc9.png
ed1ecce55155e1e75d211c86f943e30a.png

它的commit log清晰地解释中断嵌套可能引入的一些risk,比如stack溢出等。也就是说,从这个commit开始,实际Linux已经不再支持中断的嵌套, 也没有快慢中断的概念了,IRQF_DISABLED标记也作废了。在IRQ HANDLER里面,无论一个中断设置还是不设置IRQF_DISABLED, 内核都不会开启CPU对中断的响应。

具体查看链接:

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=e58aa3d2d0cc

bf234bcf55348138a8bcfd40abe3598a.png
40b14a5c418e06368983eb7ca0e85ee0.png
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值