没有完美的代码

没有完美的人,更没有完美的代码。虽然教科书上说deadlock(死锁)多么不好不好,但是在现实生活中,很难把它完全消灭。假设不小心内核出现了deadlock,可能你得干瞪眼。CPU就在那里空等着,空转着,叫天天不应,叫地地不灵。等到海枯石烂,CPU生锈的那一天,它还会那么痴痴地等着那个霸占了锁的家伙会良心发现,解下这个锁。

也许你会说,哎呀,这么麻烦干嘛?RESET一下,不就一了百了吗?但是如果是一台肩负重担的Server(服务器),在夜深人静你正呼呼大睡的时候发生了deadlock呢?如果deadlock的原因没有查到,三天五天就会发生一次,光这样被动的重启也不是办法……

不用说让人心惊胆颤的deadlock,很多时候,一段小小的循环,就会把你彻底雷到。我们总认为循环是可以结束的,但是别要忘记,事物都是辩证的,有的时候,碰巧发生了某些预料之外的条件,让这个循环成了彻彻底底的死循环。

恰巧此时,CPU的中断如果已经被禁掉,那神仙也救不了你。“我佛慈悲,能不能把循环给我停掉?”“阿弥陀佛,神仙也得遵守潜规则,你让我给你停掉循环,好歹也要给我一个中断,让我能够施法吧?”

……不能怪父母,更不能怪政府,如果你正好在电脑旁边,可以RESET;如果你不在旁边,就等着老板的电话吧。“小福啊,今天又超过100位客户打电话投诉我们的交友网站不能访问了,你赶紧打的到公司,看看是怎么回事。

赶紧啊!有个客户说,如果今晚12点之前不能登录网站,取得要约会的5位MM的详细资料,他就会携带人体炸弹到办公楼来砸场子……“

保留现场,强行重启

言归正传。如果应用程序进入死循环,我们可以把它KILL掉。如果内核因为意料之外的原因,导致系统进入无法自拔的死循环,最好的办法就是让系统给强行重启。

当然,这种重启最好是自动的,不需要人干预的,且最好能够打印出导致重启的原因,便于开发者调试错误。在Linux内核中,用NMI看门狗(NMI Watchdog Timer)的方式来实现该机制。

在系统的正常运行过程当中,每秒都有非常多的中断产生。即便它啥都不做,啥外部中断都不接收,每秒至少有数以百计的用来给线程调度的时钟中断。(如果调度时间片为10ms,则有100个时钟中断。)假设如果内核发现5秒钟之内,没有产生一个中断,那将会是怎么一回事呢?

这个时候,CPU会辩解道:“我兢兢业业地执行每一条指令,有没有中断不干我的事,叫我干啥就干啥,我是真正的劳动模范,不要怀疑我会捣鬼。

中断既来之,我就安之。不来之,则说明中断已经被禁掉了。肯定是有个幕后黑手已经调用CLI之类的指令关闭了全局的外部中断,然后偷偷摸摸干自己相干的事情,不被其他人给打断。人都有自己的隐私嘛,代码也不例外。

屏蔽中断,执行不被打断的代码,人之常情。但是用得不恰当,如同毒品一样,就会出现大问题。少量鸦片,可以当作药品;携带超过5克海洛因,就得上刑场。

禁掉中断占用一点点CPU时间,可以让程序很容易地绕开race condition(竞争条件);但是如果中断被禁掉的时间长达5秒钟,那就违反常理了。5秒钟之内系统不会有其他响应,其影响之深远,罪行之恶劣,不用满清十大酷刑简直不足以平息民愤……”

“该杀!该杀!”这个时候,内存,芯片组,硬盘……所有硬件都附和。看来CPU还是一直是IT届的老大。不怪我们不客气了,赶紧打印出现场(CPU出现LOCKUP时的相关上下文,包括寄存器值,函数调用栈等),且记入LOG,作为判案的证据,同时有警示后人只用。接着,就对施以极刑,给内核来一个oops,彻底终止它的执行,让它重新启动。

少林扫地僧——NMI

不对,不对!也许你有这样的感觉,既然5秒之内没有一个中断,基本肯定中断是已经被禁掉了,那CPU就被迫只会一直执行那段有问题的代码,根本没有机会来执行所谓的“保留现场,强行重启”的代码。

这些代码放在内核的另外一个地方,要调用它,必须由中断出发。可是,可是中断不是已经被禁了吗?借尸还魂?恐怖,恐怖……

“再厉害的黑社会,也斗不过我们人民警察!”这个时候,CPU又冷笑了,“虽然中断被禁掉了,但是,我还拥有秘密武器。那就是Non-maskable interrupt,不可屏蔽中断,简称NMI。你要禁,只能禁掉一般的可屏蔽中断。NMI,我压根就让你摸不着,碰不着!”

原来,内核中隐藏着一个神秘的高手,那就是NMI。我们调用spin_lock_irq,虽然能够禁掉本地的中断,但是NMI却不行。

内核中设置了一个watchdog timer,它的中断类型就被置为NMI,每过一定的时间,这个timer就执行一次,用来悄悄监视系统的运行。

如果系统正常,它啥事都不做,仅仅是更改一些时间计数;如果系统不正常(默认5秒没有任何普通外部中断),那它就闲不住了,会立马跳出来,且中止之前程序的运行。该出手时就出手!

我想到了在血腥的武林当中,有无数的高手。刚开始的时候,似乎人人都是高手;但后来,昔日的高手看起来都是菜鸟,强中更有强中手。再后来,更高的高手出来了,开始这里论剑那里比武,争霸天下了。

最后来,天下也许是第一第二的高手开始决战……似乎故事就这个时候结束了,但是让人大跌眼镜的是,一个小小的少林扫地僧,却能轻易地两位顶尖高手制服。

NMI就是这样的角色,平时从不站在前台,也很少为人所知。除了用NMI watchdog timer监测系统是否锁住之外,一些特殊的严重的硬件错误,比如内存奇偶校验错等,也会触发NMI的发生。不过这些错误,估计很多人从来不会碰到过。

More

如果出现死循环的地方没有把中断禁掉,那是不是不会触发NMI watchdog timer了呢?

理论上是的。至少Linux2.6的抢占内核应该不会触发。但是,由于系统还是有机会调度到其他线程,所以整个系统可能响应很慢,但不至于给死掉。我们可以通过top命令查看进程状况等手段来进行分析。

不是所有的Linux内核都支持NMI watchdog timer的。必须在内核中添加APIC的支持。(现在的内核和硬件一般都是没有问题的)如果是x86-64的硬件体系结构,APIC是被默认支持的。

在很多发行版本当中,需要在启动的时候添加内核启动参数nmi_watchdog=N来启动NMI watchdog timer。N代表了该timer的source,如果为1,表示利用IO APIC的始终源;如果为2,表示利用LOCAL APIC的performance counter。

具体哪个好用,可以分别测试一下,一般来说,比较新的CPU(一般都是双核了)选择2的话,系统负担更小一点。想要更多的了解NMI watchdog timer,请看如下的kernel文档

http://www.kernel.org/doc/Documentation/nmi_watchdog.txt

想要知道啥时APIC(注意不是ACPI),啥是IO APIC,啥是LOCAL APIC,那就请google一下吧。

原文链接:https://blog.csdn.net/freemancqcsdn/article/details/4499100 版权归原作者所有,如有侵权,请联系作者删除

【内核】深入分析内核panic(二)--内核中的少林扫地僧-NMI Watchdog Timer的更多相关文章

  1. 【内核】linux2.6版本内核编译配置选项(二)

    目录 Linux2.6版本内核编译配置选项(一):http://infohacker.blog.51cto.com/6751239/1203633 Linux2.6版本内核编译配置选项(二):http ...

  2. linux内核--内存管理(二)

    一.进程与内存     所有进程(执行的程序)都必须占用一定数量的内存,它或是用来存放从磁盘载入的程序代码,或是存放取自用户输入的数据等等.不过进程对这些内存的管理方式因内存用途不一而不尽相同,有些内 ...

  3. Linux内核启动代码分析二之开发板相关驱动程序加载分析

    Linux内核启动代码分析二之开发板相关驱动程序加载分析 1 从linux开始启动的函数start_kernel开始分析,该函数位于linux-2.6.22/init/main.c  start_ke ...

  4. 小说接入UC浏览器内核技术对话(二)

    质辛@灿岩 质辛跟我们说一下那个删除文件的逻辑吧质辛@灿岩  应该不是删除cache下所有文件吧?质辛质辛@智鹰  提供一下我们的临时文件完整路径给 灿岩吧质辛@智鹰  是负责我们ucsdk的 技术对 ...

  5. kernel:NMI watchdog: BUG: soft lockup - CPU#6 stuck for 28s! CentOS7linux中内核被锁死

    环境说明:虚拟机 CentOS7中解压一个8G的包时,内核报错 Message from syslogd@cosmo-01 at Apr 25 11:05:59 ... kernel:NMI watc ...

  6. Netlink 内核实现分析(二):通信

    在前一篇博文<Netlink 内核实现分析(一):创建>中已经较为具体的分析了Linux内核netlink子系统的初始化流程.内核netlink套接字的创建.应用层netlink套接字的创 ...

  7. ARM-Linux内核移植之(二)——Linux2.6.22内核移植

    平台:mini2440  交叉工具链:arm-linux-gcc-4.3.2 一.内核移植基本知识 移植内核也叫构建BSP(boardsupprot packet).BSP的作用有两个:一是为内核运行 ...

  8. 抢占式内核与非抢占式内核中的自旋锁(spinlock)的差别

    一.概括 (1)自旋锁适用于SMP系统,UP系统用spinlock是作死. (2)保护模式下禁止内核抢占的方法:1.运行终端服务例程时2.运行软中断和tasklet时3.设置本地CPU计数器preem ...

  9. 用户空间和内核空间通讯之【Netlink 中】

    原文地址:用户空间和内核空间通讯之[Netlink 中] 作者:wjlkoorey258 今天我们来动手演练一下Netlink的用法,看看它到底是如何实现用户-内核空间的数据通信的.我们依旧是在2.6 ...

  10. Linux内核驱动学习(二)添加自定义菜单到内核源码menuconfig

    文章目录 目标 drivers/Kconfig demo下的Kconfig 和 Makefile Kconfig Makefile demo_gpio.c 目标 Kernel:Linux 4.4 我编 ...

随机推荐

  1. AgileConfig 1.8.0 已适配 .NET8

    Hello 大家好.本月圈子里最大的事莫过于 .NET8 正式 release.群友们都在适配 .NET8.抽个周末我也把 AgileConfig 升级到了 .NET8.下面把升级的过程简单记录一下, ...

  2. 2023年的PHP项目部署笔记。什么?还有人用PHP?

    前言 这是我第一次用 PHP 的包管理工具 composer 一开始用 docker 进行部署,但一直出问题,最后还是选择直接在服务器上安装 php-fpm 搭配 nginx 的方案了. PS:doc ...

  3. 关于C#接口的用法详细解答,附上案例说明!

    接口 C#中的接口是一种定义了一组方法.属性和事件的类型.它只包含成员的声明,而不包含任何实现.接口可以被类通过实现的方式使用,从而使类能够具有接口定义的行为. 接口在C#中被定义为使用interfa ...

  4. 解决k8s删除pod后又重新创建了新的pod

    1.问题现象 2.原因 在Kubernetes中,当你删除一个Pod时,如果该Pod是由Deployment.ReplicaSet或PodController创建的,那么这个Pod会被标记为" ...

  5. Java反序列化漏洞-URLDNS链分析

    目录 一.前置知识 反射 二.分析 1. URL 2. HashMap 3. 解决一些问题 反射修改字段值 三.POC 四.利用链 一.前置知识 菜鸟教程 Java 序列化 Java安全-反射 URL ...

  6. 关于helloworld

    我们的helloworld是从一个源程序开始的,该源程序由程序员通过编译器创建并保存的文件,文件名就是hello.c.这个hello.c的源程序,实际上是有0和1组成的序列.每一个0和1都成为一位,这 ...

  7. Java 集合(一)List

    在 Java 中,主要存在以下三种类型的集合:Set.List 和 Map,按照更加粗略的划分,可以分为:Collection 和 Map,这些类型的继承关系如下图所示: Collection 是集合 ...

  8. JavaImprove--Lesson06--正则表达式

    一.正则表达式的入门 正则表达式是一些特定支付组成的,代表一个规则,简化代码,以字符的形式体现规则 正则表达式,又称规则表达式,(Regular Expression,在代码中常简写为regex.re ...

  9. Java 设置Excel页面背景

    本文介绍通过Java 程序在Excel表格中设置页面背景的方法,可设置颜色背景(即指定单一颜色作为背景色).图片背景(即加载图片设置成页面背景).程序中需要使用免费版Excel类库工具 Free Sp ...

  10. 当创建statefulset资源后,k8s组件如何协作

    本文分享自华为云社区<当创建StatefulSet后,k8s会发生什么?>,作者:可以交个朋友 . 一.StatefulSet介绍 StatefulSet 是用来管理有状态应用的工作负载对 ...