摘要
对于好多计算机从业者来着,提及内核,大家都是一头雾水,感觉涉及到内核的东西就很神秘,本博文主要分享一些对内核的简单基础的知识,帮助你们更好的学习和了解操作系统相关原理。从具象角度来看,内核就是计算机资源的管理者,当然管理资源是为了让应用使用资源。既然内核是资源的管理者,我们先来瞧瞧计算机中有什么资源,然后通过资源的归纳新设计团队linux内核设计的艺术:图解linux操作系统架,就能推论出内核这个大黑盒中应当有哪些。在目前的来看,内核设计的演化似乎和软件系统构架演化惊人的相像。宏内核和单体构架一致,微内核和SOA构架一致,而课程上面讲的第三种构架更像是微服务构架。从整体的构架演进来看,核心就是分拆,从all in one到垂直分拆,再到水平分拆,更面向用户操作和技术专注。
一、计算机资源分类
计算机中资源大致可以分为两类资源,一种是硬件资源,一种是软件资源。先来瞧瞧硬件资源有什么,如下:
而计算机中的软件资源,则可表示为计算机中的各类方式的数据。如各类文件、软件程序等。内核作为硬件资源和软件资源的管理者,其内部组成在逻辑上大致如下:
内核不仅这种必要组件之外,根据功能不同还有安全组件等,最值得一提的是,各种计算机硬件的性能不同,硬件机型不同,硬件种类不同,硬件厂商不同,内核要想管理和控制这种硬件就要编撰对应的代码,通常这样的代码我们称之为驱动程序。硬件厂商就可以按照自己不同的硬件编撰不同的驱动,加入到内核之中。以上我们早已大致晓得了内核之中有什么组件,但是另一个问题又出现了,即怎样组织这种组件,让系统愈发稳定和高效?
二、宏内核结构模型
其实看这名子,就早已能猜到了,宏即大也,这种最简单适用,也是最早的一种内核结构。宏内核就是把以上例如管理进程的代码、管理显存的代码、管理各类 I/O 设备的代码、文件系统的代码、图形系统代码以及其它功能模块的代码,把这种所有的代码经过编译,最后链接在一起,形成一个大的可执行程序。这个大程序里有实现支持这种功能的所有代码,向用户应用软件提供一些插口,这些插口就是常说的系统 API 函数。而这个大程序会在处理器的特权模式下运行,这个模式一般被称为宏内核模式。结构如下图所示:
尽管图中一层一层的,这并不是它们有层次关系,仅仅表示它们链接在一起。为了理解宏内核的工作原理,我们来看一个事例,宏内核提供显存分配功能的服务过程,具体如下:
上面这个过程和一个实际的操作系统中的运行过程,可能有差别,但大同小异。当然,系统 API 和应用程序之间可能还有库函数,也可能只是分配了一个虚拟地址空间,但是我们关注的只是这个过程。上图的宏内核结构有显著的缺点,因为它没有模块化,没有扩展性、没有移植性,高度耦合在一起,一旦其中一个组件有漏洞,内核中所有的组件可能就会出问题。开发一个新的功能也得重新编译、链接、安装内核。其实现今这些原始的宏内核结构早已没有人用了。这种宏内核惟一的优点是性能挺好,因为在内核中,这些组件可以相互调用,性能极高。为了便捷我们了解不同内核构架间的优缺点,下面我们看一个和宏内核结构对应的例子。
三、微内核结构模型
微内核构架恰好与宏内核构架相反,它倡导内核功能尽可能少:仅仅只有进程调度、处理中断、内存空间映射、进程间通信等功能。这样的内核是不能完成哪些实际功能的,开发者们把实际的进程管理、内存管理、设备管理、文件管理等服务功能,做成一个个服务进程。和用户应用进程一样,只是它们很特殊,宏内核提供的功能,在微内核构架里由这种服务进程专门负责完成。微内核定义了一种良好的进程间通信的机制——消息。应用程序要恳求相关服务,就向微内核发送一条与此服务对应的消息,微内核再把这条消息转发给相关的服务进程,接着服务进程会完成相关的服务。服务进程的编程模型就是循环处理来自其它进程的消息,完成相关的服务功能。其结构如下所示:
为了理解微内核的工程原理,我们来瞧瞧微内核提供显存分配功能的服务过程,具体如下:
微内核的构架实现似乎不同,但是大致过程和前面一样。同样是分配显存,在微内核下拐了几个弯,一来一去的消息带来了特别大的开支,当然各个服务进程的切换开支也不小。这样系统性能就大打折扣。
但是微内核有很多优点,首先,系统结构相当清晰利于协作开发。其次,系统有良好的移植性,微内核代码量特别少,就算重画整个内核也不是难事。最后,微内核有相当好的伸缩性、扩展性,因为这些系统功能只是一个进程,可以随时拆掉一个服务进程以降低系统功能,或者降低几个服务进程以提高系统功能。
微内核的代表作有 MACH、MINIX、L4 系统,这些系统都是微内核,但是它们不是商业级的系统,商业级的系统不采用微内核主要还是由于性能差。
四、分离硬件的相关性
我们会时常据说,Windows 内核有哪些 HAL 层、Linux 内核有哪些 arch 层。这些 层就是 Windows 和 Linux 内核设计者,给她们的系统内核分的第一个层。今天这么繁杂的计算机,其实也是一层一层地建立上去的,从硬件层到操作系统层再到应用软件层这样完善。分层的主要目的和益处在于屏蔽底层细节,使下层开发愈发简单。计算机领域的一个基本方式是降低一个具象层,从而促使具象层的上下两层独立地发展,所以在内核内部再分若干层也不足为怪。分离硬件的相关性,就是要把操作硬件和处理硬件功能差别的代码抽离下来,形成一个独立的软件具象层,对外提供相应的插口,方便下层开发。
为了让你更好理解,我们举进程管理中的一个模块实现细节的事例:进程调度模块。通过这个事例,来瞧瞧分层对系统内核的设计与开发有哪些影响。
其实说到底,进程是操作系统开发者为了实现多任务而提出的,并让每位进程在 CPU 上运行一小段时间,这样才能实现多任务同时运行的表象。
当然,这种表象非常奏效。要实现这些表象,就要实现下边这两种机制:
1.进程调度,它的目的是要从诸多进程中选择一个即将运行的进程,当然有各类选择的算法,例如,轮转算法、优先级算法等。
2.进程切换,它的目是停止当前进程,运行新的进程,主要动作是保存当前进程的机器上下文,装载新进程的机器上下文。
我们不难发觉,不管是在 ARM 硬件平台上还是在 x86 硬件平台上,选择一个进程的算法和代码是不容易发生改变的,需要改变的代码是进程切换的相关代码,因为不同的硬件平台的机器上下文是不同的
所以,这时最好是将进程切换的代码放到一个独立的层中实现,比如硬件平台相关层,当操作系统要运行在不同的硬件平台上时,就只是须要更改硬件平台相关层中的相关代码,这样操作系统的移植性就大大提高了。
五、微大型操作系统构架模型
首先大致将我们的操作系统内核分为三个大层,分别是:
5.1 内核插口层
内核插口层,定义了一系列插口,主要有两点内容,如下:
5.2 内核功能层
内核功能层的模块如下:
5.3 内核硬件层
我们的操作系统内核没有任何设备驱动程序,甚至没有文件系统和网路组件,内核所实现的功能甚少。这汲取了微内核的优势,内核小出问题的可能性就少,扩展性就越强。同时,我们把文件系统、网络组件、其它功能组件作为虚拟设备交由设备管理,比如须要文件系统时就写一个文件系统虚拟设备的驱动,完成文件系统的功能,需要网路时就开发一个网路虚拟设备的驱动,完成网路功能。这些驱动一旦被装载,就是内核的一部分了,并不是像微内核一样作为服务进程运行。这又汲取了宏内核的优势,代码高度耦合,性能强劲。这样的内核构架既不是宏内核构架也不是微内核构架,而是这两种构架综合的结果,可以说是混合内核构架,也可以说这是我们自己的内核构架。
六、Darwin-XNU 内核设计
我们先来瞧瞧 Darwin,Darwin 是由苹果公司在 2000 年开发的一个开放源代码的操作系统。苹果公司有台式计算机、笔记本、平板、手机,台式计算机、笔记本使用了 macOS 操作系统,平板和手机则使用了 iOS 操作系统。Darwin 作为 macOS 与 iOS 操作系统的核心,从技术实现角度说,它必然要支持 PowerPC、x86、ARM 架构的处理器。Darwin 使用了一种微内核(Mach)和相应的固件来支持不同的处理器平台,并提供操作系统原始的基础服务,上层的功能性系统服务和工具则是整合了 BSD 系统所提供的。苹果公司还为其开发了大量的库、框架和服务,不过它们都工作在用户态且闭源。
什么?两套内核?惊不惊喜?由于我们是研究 Darwin 内核,所以上图中我们只须要关注内核 - 用户转换层以下的部份即可。显然它有两个内核层——Mach 层与 BSD 层。
Mach 内核是卡耐基梅隆大学开发的精典微内核,意在提供最基本的操作系统服务,从而达到高性能、安全、可扩充的目的,而 BSD 则是伯克利大学开发的类 UNIX 操作系统,提供一整套操作系统服务。
那为何两套内核会同时存在呢?
MAC OS X(2011 年之前的尊称)的发展经过了不同时期,随着时代的进步,产品功能需求降低,单纯的 Mach 之上实现出现了性能困局,但是为了兼容之前为 Mach 开发的应用和设备驱动,就保留了 Mach 内核,同时加入了 BSD 内核。
Mach 内核一直提供非常简单的进程、线程、IPC 通信、虚拟内存设备驱动相关的功能服务,BSD 则提供强悍的安全特点,完善的网路服务,各种文件系统的支持,同时对 Mach 的进程、线程、IPC、虚拟内核组件进行细化、扩展延展。
那么应用怎样使用 Darwin 系统的服务呢?
应用会通过用户层的框架和库来恳求 Darwin 系统的服务,即调用 Darwin 系统 API。
在调用 Darwin 系统 API 时,会传入一个 API 号码,用这个号码去索引 Mach 陷入中断服务表中的函数。此时,API 号码假如大于 0,则表明恳求的是 Mach 内核的服务,API 号码假如小于 0,则表明恳求的是 BSD 内核的服务,它提供一整套标准的 POSIX 接口。
Mach 中还有一个重要的组件 Libkern,它是一个库,提供了好多底层的操作函数,同时支持 C++ 运行环境。依赖这个库的还有 IOKit,IOKit 管理所有的设备驱动和内核功能扩充模块。驱动程序开发人员则可以使用 C++ 面向对象的形式开发驱动,这个方法很甜美,你完全可以找一个成熟的驱动程序作为父类承继它,要非常实现某个功能就重载其中的函数,也可以同时承继其它驱动程序,这大大节约了显存,也大大增加了出现 BUG 的可能。如果你要详尽了解 Darwin 内核的话,可以自行阅读:GitHub - apple/darwin-xnu: The Darwin Kernel (mirror). This repository is a pure mirror and contributions are currently not accepted via pull-requests, please submit your contributions via
七、Windows NT 内核设计
NT 内核在设计上层次十分清晰明了,各组件之间界限耦合程度很低。下面我们就来瞧瞧 NT 内核构架图,了解一下 NT 内核是怎样“庄严宏伟”。如下图:
当然谷歌自己在 HAL 层上是定义了一个小内核,小内核之下是硬件抽象层 HAL,这个 HAL 存在的用处是:不同的硬件平台只要提供对应的 HAL 就可以移植系统了。小内核之上是各类内核组件,微软称之为内核执行体,它们完成进程、内存、配置、I/O 文件缓存、电源与即插即用、安全等相关的服务。
每个执行体相互独立,只对外提供相应的插口,其它执行体要通过内核模式可调用插口和其它执行体通讯或则恳求其完成相应的功能服务。所有的设备驱动和文件系统都由 I/O 管理器统一管理,驱动程序可以堆叠产生 I/O 驱动栈,功能恳求被封装成 I/O 包,在栈中一层层流动处理。Windows 引以为傲的图形子系统也在内核中。
显而易见,NT 内核中各层次分明,各个执行体相互独立,这种“高内聚、低偶合”的特点,正是检验一个软件工程是否优秀的重要标准。而那些你都可以通过谷歌公开的 WRK 代码得到旁证,
NT是混合内核,内核相较于linux来说小,但是仍有一些模块在内核新设计团队linux内核设计的艺术:图解linux操作系统架,也有相当多的模块在用户态。架构额外清晰,也为啥几十年迭代都从未大改大变。
博文参考
《极客时间的操作系统实战》