我认为微内核相对于单内核上没有明显的技术优势,微内核一般都宣称有如下的技术优势:
1. 各服务可以动态加载插入,使内核很小,减少内存。
2. 系统非常灵活。当运行一个应用程序时,只需把选定的系统服务加载到系统中即可。而修改了服务以后可以通过联机进行测试;并不需要重新构建或者启动一个新的内核,他们并不影响系统的运行。
3. 各服务地址空间独立,不影响其它模块(如文件系统服务调用内存管理服务的功能)。一个服务组件的失效并不会导致整个系统的崩溃,内核需要做的,仅仅是重新启动这个组件,而不必影响其它的部分。
4. 可移植性强,各用户台服务与硬件无关。
1. 第一点,目前的Linux来说也有内核模块机制解决。当然还有不少功能是直接链接,没有实现为内核模块形式,但是这是目前实现问题,今后如果必要都是可以实现的(比如VFS组件也可以搞一个ko出来加载进去)。对于这点,微内核并无明显优势了。
2. 第二点同上。
3. 第三点,有两层含义。
3.1 第一层是本服务实效的问题,这一点。我想Linux也是可以做到的,比如一个"功能",如VFS,如果其内部全局变量数据混乱了以后,有可能就会访问非法地址,现在一般做法是BUG, OOPS或panic。这其实也是可以修改为不进行oops,panic的,而是把资源清理回收一下,把所有的数据重新初始化一下。这个与是否是内核模块无关,目前的内核也可以做。大概你会说,这样其它的内核部分就会暂时不能使用这个服务了。但是微内核重启这个组件时,也一样不能使用该组件。因此微内核并无优势。
3.2 第二层含义是影响其它部分,其它部分有三种可能。
a) 可能是调用本功能的用户态线程,目前如果发生oops,该线程会被kill,其实也可以修改为不kill,而是取消它的资源。比如如果VFS功能实效,我就强制关闭所有文件句柄,释放资源如锁等等。
b) 二是影响其它的组件,一个比较常见的问题就是VFS如果发生代码错误有了野指针,修改了网络组件的全局变量,因为内核的地址空间是所有代码共享的。这个问题,也不是没有办法解决。目前粗略想到的一个办法是取消所有进程的内核地址空间共享模式。每个进程有独立的内核地址空间,在这个空间内,每个内核组件就像一个用户态进程的一个动态库,你用的时候进行动态映射。比如你调用VFS的系统调用时,系统会帮你自动映射VFS代码段和数据段到你的内核空间;如果VFS访问了内存管理的API,在调用这个组件间API的接口时,进行内存组件的映射,同时把VFS解除映射。当内存管理分配完内存时,再进行VFS映射,内存解除映射动作。这样内核态运行时,在某一时刻只有一个组件存在地址映射,因此它要想非法访问其它组件的地址必然会引起page fault。至于中断,也是一样,在某一时刻必然只会映射一段代码。当从中断返回内核态时,只要恢复被打断时刻的映射状态即可。其实映射早就映射好了的,只不过是修改页目录项中"存在"的1位标志而已,性能并不会受到多大的影响。当然这个映射和解除映射的动作,如果现在要全部加在内核中工作量是巨大的。但是如果有必要,我想是可以通过编译时的插桩技巧来实现的。
c) 三是内核,就是目前Linux比较严重的问题,一般都是oops,panic重启。这点我前面说了,这个也只是实现的问题,只要3.1, 以及3.2.a), 3.2.b) 三点做好了,可以不用强制重启内核。
4. 第四点比较牵强,所谓移植,无非就是对一些硬件驱动的修改,CPU体系结构部分的处理等。不管你的服务包括驱动运行在用户态还是内核态,该修改的还是要修改。与宏内核,微内核的设计没有关系。
综述,第1,2,3个问题其实都是目前"实现"上的问题,只是因为目前Linux的可靠性,灵活性问题还没有到非那样做不可的地步,而并非Linux从设计上就不能那么实现,因此并不是单内核还是微内核"设计"上的问题。微内核上宣称的所谓的技术优势,Linux上也一样是可以实现的。没有必要非要通过另外设计一套基于IPC的内核组件服务模型,把问题隐藏。
阅读(3159) | 评论(1) | 转发(0) |