性能文章>如果让你来设计中断机制>

如果让你来设计中断机制原创

170313

哈喽,我是子牙,一个很卷的硬核男人

从这篇文章开始,准备系统性给大家讲讲中断这个玩意。对于中断,很多小伙伴为什么学不明白呢?因为中断很底层,底层到CPU层面,有些中断更是由CPU+操作系统配合实现的。

作为一个写过操作系统的男人,我就以我独特的手法带大家玩转中断

本系列文章预计分四篇:

  1. 深刻理解中断

  2. 模拟操作系统手写实现中断机制

  3. 由内到外深挖除零异常底层实现

  4. 由内到外深挖Linux信号底层实现

有理论,有实战,并结合现实:Linux底层实现,让大家全方位玩转中断,从此不再谈中断就色变

今天是中断机制系列文章第一篇,将从这几个角度进行分享:

  1. 细说硬中断与软中断

  2. 细说可屏蔽中断与不可屏蔽中断

  3. 细说影响中断的状态寄存器eflags

  4. 细说中断嵌套与linux解决方案

聊聊中断

计算机的世界,可以理解成虚拟世界,亦或是抽象世界。不管是虚拟的,还是抽象的,一定也是源于现实世界。看似一句废话,实则蕴含学好计算机的一种思维:抽象还原于现实。你走得越高,接触的东西就越抽象,如果没有这种思维,很多东西你完全没概念。

看很多鸡汤文说人与人的差别源于认知。我越来越觉得,认知只是基础能力,基于认知完成抽象及将抽象还原成现实的能力,才是差别所在。认知是学,抽象与反抽象是用。学,很多人能做到,学以致用,能做到的人少很多。

计算机的世界是由大师们将现实世界进行了抽象,我们在学习理解它的时候,就要把它具象还原成现实,才能深刻理解它。中断就是这样的存在。

讲中断不得不提到CPU。从结构上讲,CPU由两大部分组成:运算器、控制器。中断就是由CPU的中断控制器触发的。什么是中断,通俗理解,就是打断的意思。

早期的CPU,中断控制器是在CPU内部的。不知从什么时候开始,中断控制器从CPU中抽离,由独立的芯片进行处理,与CPU通过引脚相连,由中断控制芯片触发中断,告知CPU,CPU进行处理。这个细节第二篇文章带你手写实现。

CPU是抽象的产物,中断也是。我们将其还原成现实,CPU就像是我们的大脑,中断就像是神经系统。接下来通过举例子来让大家深刻理解。

顺便说下,操作系统中的中断是广义上的中断,包含硬中断与软中断。

由硬件触发的中断通常称为硬中断,硬中断通常都是可屏蔽的,通过配置中断控制芯片即可实现。比如时钟中断、硬盘中断、键盘中断,都可以屏蔽。也有不可屏蔽的硬中断,比如长按电源键关机。如果你长按电源键关不了机,那是不是挺离谱的!

软中断是CPU设计的时候内置的,通常是不可屏蔽的。比如我们调试能够下段点,对应的就是3号软中断,如果你看过汇编代码:int 3。比如我们的系统调用,通常操作系统都是用80号软中断。比如我们写程序遇到除零异常,对应的处理程序就是0号软中断…

关于可屏蔽中断与不可屏蔽中断,如果你有疑惑,接着往后看。其实从字面意思也能看出来,可屏蔽中断就是把中断屏蔽掉,让CPU不去处理。不可屏蔽中断就是屏蔽不了,或者说你就算屏蔽了,CPU依然会去处理。

2、一个例子

我们什么都不想的时候,其实就类似于CPU的空转,对应的汇编指令就是HLT。但是就算我们什么都不想,看到一个苹果掉落,我们的神经系统会不自觉的去思考,于是有了万有引力定律。

对于苹果掉落,其实我们也可以控制自己的大脑不去思考。很显然,在看到苹果掉落与大脑思考这中间的间隙,我们可以控制是否去思考。在计算机的世界,这个活谁来干?当然是CPU!但是CPU是怎么知道的,一方面是由中断控制芯片告知,另一方面是CPU检查状态寄存器eflags中断位

关于状态寄存器eflags,你可以理解成就是一张表,CPU在处理中断之前会去查一下,如果IF位为0,表示CPU不去处理中断,如果为1表示要处理。这个位只影响可屏蔽中断

这个位不影响不可屏蔽中断。言外之意就是如果发生了除零异常,就算IF位为0,CPU依然要去处理除零产生的异常。如图,我没开中断,代码触发了除零异常,CPU响应了

3、中断嵌套

不管是计算机世界,还是现实世界,情况不可能如前面说的那么简单

比如你在工作,你的同事A告诉你要做某件事,你的同事B告诉你要做某件事…你打算把自己的工作做完再做。你的工作做完了,可能只记得同事A告诉你的事情,后面的忘光了。也有可能是你在做A告诉你的事情,A又不停的告诉你要做这个要做那个…借用斗地主的一句话:给你压死!

这就要说到中断的嵌套。中断控制芯片或者CPU,是不支持中断嵌套的。言外之意就是CPU正在处理一个中断,这时候来一个中断,CPU会直接响应,不会出现排队的现象。

但是现实中,是需要支持中断嵌套的。在Linux系统中,如果出现中断嵌套,解决方案有两种:一、对于可屏蔽中断,处理的时候把中断屏蔽掉;二、对于不可屏蔽中断,只能在操作系统层面支持中断嵌套。

对于方案一,比如读硬盘,就是先关闭中断,给硬盘发读盘请求,发完以后,开中断。很多硬件操作都需要这样干,比如向屏幕输出内容

对于方案二,linux系统中,在进程结构体task_struct中有两个属性,分别表示:信号屏蔽字、信号未决字。言外之意就是linux在处理不可屏蔽中断的时候,只能记录一次中断嵌套。后面来的中断怎么办?丢掉。Linux可不可以搞一个队列支持无限嵌套呢?肯定是可以的!可能是觉得没必要吧!

讲到这里,你现在是否有一种:切,中断也就这么回事,这种感觉呢?当然,肯定有小伙伴看完后有一堆问题,可以留言告知我

题外话

你好,我是子牙。十余年技术生涯,一路披荆斩棘从小白到技术总监到大厂中间件到创业。技术栈如汇编、C语言、C++、Windows内核、Linux内核及特别喜欢研究虚拟机底层实现,对JVM有深入研究。分享的文章偏硬核,很硬的那种。不考虑交个朋友吗?关注硬核子牙:

点赞收藏
子牙_公号硬核子牙

对编程语言的设计与实现有浓厚兴趣。聚焦Hotspot源码、Linux内核研究,硬核干货分享

请先登录,查看1条精彩评论吧
快去登录吧,你将获得
  • 浏览更多精彩评论
  • 和开发者讨论交流,共同进步

为你推荐

从 Linux 内核角度探秘 JDK MappedByteBuffer

从 Linux 内核角度探秘 JDK MappedByteBuffer

日常Bug排查-连接突然全部关闭

日常Bug排查-连接突然全部关闭

3
1