Linux的suspend机制的设计原理(续)--cpu的热插拔

来源:互联网 发布:剑桥英语在用系列知乎 编辑:程序博客网 时间:2024/04/30 01:27

前面简单谈了一下linux的suspend机制的实现,其主要思想就是,启动cpu外的别的cpu都不关闭,而是进入idle然后进入play_dead中执行halt,我们知道halt只有中断可以唤醒,可是醒了以后发现该cpu为dead状态,那么仍然进入halt,如果将设备也停了,那么该cpu就一直halt了,直到我们按下电源,这个就是硬件范畴了,启动cpu则不是进入halt,而是执行一些列操作将快照映像写入磁盘,最后调用power_down关闭电源,这个操作是由pm_ops->enter(PM_SUSPEND_DISK)完成的,这就提供了一个灵活的回调函数机制,将操作策略和执行机制分离,我们可以实现acpi的pm_ops,还可以实现apm的pm_ops,但是不管采用哪一种电源管理,上面说的执行机制是不会变的。在resume的时候,大体策略就是将磁盘的快照映像恢复到内存,然后开启所有的cpu开始工作,由于电源管理的规范,只有一个cpu可以用来唤醒机器,那么这样的话前面的halt调别的cpu也是正当的,当需要唤醒机器的时候,因为suspend到磁盘的时候,启动cpu已经做好了随时被唤醒的准备,所以它当然要担负起唤醒的重任,唤醒函数其实就是software_resume,注意这个函数的定义是late_initcall,这个定义是__define_initcall("7",fn),意思就是在所有设备都启动后再最后调用,因此可以断定,唤醒的时候还是要执行一遍设备初始化的,当所有的设备都初始化完毕以后再调用这个函数,这个函数的主要任务就是将存入磁盘的快照映像恢复入内存,也就是从power_down下面开始而不是继续执行software_resume,这个可以类比一下进程都是从schedule中被切换出去,然后在schedule中被切换回来,实际上如果到了software_resume的末尾就说明恢复磁盘快照映像时出了错误,按照道理是不该执行到software_resume的最后的。

前面讨论的基础是什么?其实就是cpu的热插拔机制,也就是cpu的hotplug机制,所谓热插拔就是可以在系统运行的时候动态的增加或者去除cpu,天啊,cpu都可以热插拔了吗?是的,可以,但是并不像usb那样可以直接针对硬件热插拔,而是在拔下cpu之前必须先通知系统该cpu要被拔下,然后系统确认正常后才可以拔下该cpu,也就是说cpu的热插拔是针对软件的热插拔,其实这很好理解,usb设备仅仅是一个设备,一个硬件插进去会有信息通知cpu,而cpu进而执行软件来初始化该设备,但是cpu拔下来怎么办呢?通知谁呢?难道处理器间中断吗?这样其实也不行,想想看usb也不是可以随意拔掉的,在windows系统上你一般都是点击移除usb设备得到系统确认可以安全移除后才会拔下usb设备的,当然如果你非要强行拔下,损失一般并不大,顶多就是一些数据损失,一般内核在读写外设发现外设不存在或者出错时都会有相应的处理机制,但是cpu就不一样了,在拔下之前,它上面可能运行着一些重要的进程,可能是一些很重要的服务进程,如果它正在该cpu上运行时你把cpu拔了,那么该进程就可能遭受永远的破坏,也很容易造成整个系统死锁,比如拔下的cpu上有一个进程正在内核空间占有一把锁,那么当cpu被拔掉后,这把锁将永远不会释放,其它争夺这把锁的进程就有可能死在那里,而且还会造成连锁反映。于是在cpu被拔掉前,务必要先通过软件down掉该cpu,也就是上面的suspend机制中对待启动cpu之外别的cpu的做法,等待其执行halt后再拔掉,这样就不会有任何损失了。想拔下一个cpu的话可以通过sysfs操作,然后系统会调用cpu_down函数,其实这个函数就是迫使这个cpu切换到执行idle,然后halt,就是靠设置idle的优先级为最高来实现的,这样的话,所有在这个cpu上排队的进程就得不到机会执行进而在这个cpu死了以后被迁移到别的cpu上,那个在这个cpu上的当前进程也会因为优先级低而为idle让出cpu。除了上面要做的之外,还要通知到该被通知的实体,也就是对cpu的热插拔感兴趣的实体,这个是靠linux内核的通知链机制执行的,事实上,对热插拔cpu的支持主要就是就是注册一条通知链:

int register_cpu_notifier(struct notifier_block *nb)

{

return blocking_notifier_chain_register(&cpu_chain, nb);

}

设计cpu热插拔机制的时候,主要几个要点,最重要的就是不能影响在热插拔cpu上执行的进程,也就是cpu的热插拔对进程应该是透明的,linux的这个实现想想看十分合理,它本质就是利用idle进程的无用性来完成不对别的进程影响的,而且将cpu状态设置为dead状态可以避免在load_balance新的进程重新调度到这个cpu上,cpu的dead状态有cpu_online_map来体现。

有网友说linux在suspend的时候重启别的cpu而不恢复别的cpu原因有两点:1.suspend的时候不要太注重效率;2.停掉别的cpu会更有效率。仅供参考,其实不用按cpu保存状态而是按照进程保存状态,体现了cpu只是一个服务者的思想,只要能保存进程状态就可以了,cpu对用户是透明的,用户关注他们运行了什么进程可是不会管用几个cpu来运行。