在内核开中中,发现一个进程屏蔽中断以后,卡死在信号量上,虽然一直卡死在信号量上,但是,一直没有触发nmi操作,这个一直让我很奇怪,今天终于搞清楚了。
首先,我们要了解一下nmi wacthdog的原理,这个网上有很多解释,这里简单说一下。内核存在一些进程,屏蔽了中断,但是由于某些原因,死锁,或者一直没有退出,这个时候,cpu就会被他一直霸占着,无法调度给其他进程使用。为了防止这种情况出现,设计出了nmi watchdog进程,他是不可屏蔽的中断,他会周期性的检测cpu是不是被某个进程一直霸占了。检测的方法也很简单,就是在规定时间内,这个cpu是否发生过中断,通过计数判断,如果没有,则说明一直被某个进程占用。这个占用时间如果超过了某个阈值,一般是5秒钟,则nmi就认为这个进程有死锁了,就要触发panic。panic会把一些堆栈信息保留,然后强制重启系统。
那么什么样子的死锁会一直霸占cpu呢?我们知道的锁,有互斥锁,信号量,自旋锁。对于互斥锁,信号量,如果一个进行没有抢到互斥锁或者信号量,则会等待,这个等待,其实就是睡眠,也就是这个进程此时会进入睡眠状态,也就是S状态,也有可能是D状态。不论是什么状态,只要不是RUNNING状态,那么他就已经让出了cpu了,所以,此时,这个进程并没有霸占cpu。所以并不会触发nmi,对于处于D状态的进程,内核有hung task进制予以应对。
而自旋锁,则不然,如果一个进程没有抢到自旋锁,他是不会睡眠的,而是会不断的循环,此时,这个进程是处于RUNNING状态的,如果此时,这个进程还屏蔽了中断,那么他也不会被调度,会一直霸占着cpu,这个时候,超过一定时限,就会触发nmi了。