mirror of
https://github.com/cheetahlou/CategoryResourceRepost.git
synced 2025-11-19 07:33:47 +08:00
mod
This commit is contained in:
201
极客时间专栏/操作系统实战45讲/心有蓝图:设计/03 | 黑盒之中有什么:内核结构与设计.md
Normal file
201
极客时间专栏/操作系统实战45讲/心有蓝图:设计/03 | 黑盒之中有什么:内核结构与设计.md
Normal file
@@ -0,0 +1,201 @@
|
||||
<audio id="audio" title="03 | 黑盒之中有什么:内核结构与设计" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/1c/19/1ccd265954fa3bf67ea907dab6087c19.mp3"></audio>
|
||||
|
||||
你好,我是LMOS。
|
||||
|
||||
在上节课中,我们写了一个极简的操作系统——Hello OS,并成功运行,直观地感受了一下自己控制计算机的乐趣,或许你正沉浸在这种乐趣之中,但我不得不提醒你赶快从这种快乐中走出来。
|
||||
|
||||
因为我们的Hello OS虽然能使计算机运行起来,但其实没有任何实际的功能。
|
||||
|
||||
什么?没有实际功能,我们往里增加功能不就好了吗?
|
||||
|
||||
你可能会这样想,但是这样想就草率了,开发操作系统内核(以下简称内核)就像建房子一样,房子要建得好,就先要设计。比如用什么结构,什么材料,房间怎么布局,电路、水路等,最后画出设计图纸,依据图纸按部就班地进行建造。
|
||||
|
||||
而一个内核的复杂程度要比房子的复杂程度高出几个数量级,所以在开发内核之前先要对其进行设计。
|
||||
|
||||
下面我们就先搞清楚内核之中有些什么东西,然后探讨一下怎么组织它们、用什么架构来组织、并对比成熟的架构,最后设计出我们想要的内核架构。
|
||||
|
||||
## 黑盒之中有什么
|
||||
|
||||
从用户和应用程序的角度来看,内核之中有什么并不重要,能提供什么服务才是重要的,所以内核在用户和上层应用眼里,就像一个大黑盒,至于黑盒里面有什么,怎么实现的,就不用管了。
|
||||
|
||||
不过,作为内核这个黑盒的开发者,我们要实现它,就必先设计它,而要设计它,就必先搞清楚内核中有什么。
|
||||
|
||||
从抽象角度来看,内核就是计算机资源的管理者,当然管理资源是为了让应用使用资源。既然内核是资源的管理者,我们先来看看计算机中有哪些资源,然后通过资源的归纳,就能推导出内核这个大黑盒中应该有什么。
|
||||
|
||||
计算机中资源大致可以分为两类资源,一种是硬件资源,一种是软件资源。先来看看硬件资源有哪些,如下:
|
||||
|
||||
1.总线,负责连接各种其它设备,是其它设备工作的基础。<br>
|
||||
2.CPU,即中央处理器,负责执行程序和处理数据运算。<br>
|
||||
3.内存,负责储存运行时的代码和数据。<br>
|
||||
4.硬盘,负责长久储存用户文件数据。<br>
|
||||
5.网卡,负责计算机与计算机之间的通信。<br>
|
||||
6.显卡,负责显示工作。<br>
|
||||
7.各种I/O设备,如显示器,打印机,键盘,鼠标等。
|
||||
|
||||
下面给出一幅经典的计算机内部结构图,如下:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/28/14/28cc064d767d792071a789a5b4e7d714.jpg" alt="" title="经典计算机结构图">
|
||||
|
||||
而计算机中的软件资源,则可表示为计算机中的各种形式的数据。如各种文件、软件程序等。
|
||||
|
||||
内核作为硬件资源和软件资源的管理者,其内部组成在逻辑上大致如下:
|
||||
|
||||
1.**管理CPU,**由于CPU是执行程序的,而内核把运行时的程序抽象成进程,所以又称为进程管理。<br>
|
||||
2.**管理内存**,由于程序和数据都要占用内存,内存是非常宝贵的资源,所以内核要非常小心地分配、释放内存。<br>
|
||||
3.**管理硬盘**,而硬盘主要存放用户数据,而内核把用户数据抽象成文件,即管理文件,文件需要合理地组织,方便用户查找和读写,所以形成了文件系统。<br>
|
||||
4.**管理显卡**,负责显示信息,而现在操作系统都是支持GUI(图形用户接口)的,管理显卡自然而然地就成了内核中的图形系统。<br>
|
||||
5.**管理网卡**,网卡主要完成网络通信,网络通信需要各种通信协议,最后在内核中就形成了网络协议栈,又称网络组件。<br>
|
||||
6.**管理各种I/O设备**,我们经常把键盘、鼠标、打印机、显示器等统称为I/O(输入输出)设备,在内核中抽象成I/O管理器。
|
||||
|
||||
内核除了这些必要组件之外,根据功能不同还有安全组件等,最值得一提的是,各种计算机硬件的性能不同,硬件型号不同,硬件种类不同,硬件厂商不同,内核要想管理和控制这些硬件就要编写对应的代码,通常这样的代码我们称之为**驱动程序**。
|
||||
|
||||
硬件厂商就可以根据自己不同的硬件编写不同的驱动,加入到内核之中。
|
||||
|
||||
以上我们已经大致知道了内核之中有哪些组件,但是另一个问题又出现了,即如何组织这些组件,让系统更加稳定和高效,这就需要我们从现有的一些**经典内核结构**里找灵感了。
|
||||
|
||||
## 宏内核结构
|
||||
|
||||
其实看这名字,就已经能猜到了,宏即大也,这种最简单适用,也是最早的一种内核结构。
|
||||
|
||||
宏内核就是把以上诸如管理进程的代码、管理内存的代码、管理各种I/O设备的代码、文件系统的代码、图形系统代码以及其它功能模块的代码,把这些所有的代码经过编译,最后链接在一起,形成一个大的可执行程序。
|
||||
|
||||
这个大程序里有实现支持这些功能的所有代码,向用户应用软件提供一些接口,这些接口就是常说的系统API函数。而这个大程序会在处理器的特权模式下运行,这个模式通常被称为宏内核模式。结构如下图所示。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/eb/6b/eb8e9487475f960dccda0fd939999b6b.jpg" alt="" title="宏内核结构图">
|
||||
|
||||
尽管图中一层一层的,这并不是它们有层次关系,仅仅表示它们链接在一起。
|
||||
|
||||
为了理解宏内核的工作原理,我们来看一个例子,宏内核提供内存分配功能的服务过程,具体如下:
|
||||
|
||||
1.应用程序调用内存分配的API(应用程序接口)函数。<br>
|
||||
2.处理器切换到特权模式,开始运行内核代码。<br>
|
||||
3.内核里的内存管理代码按照特定的算法,分配一块内存。<br>
|
||||
4.把分配的内存块的首地址,返回给内存分配的API函数。<br>
|
||||
5.内存分配的API函数返回,处理器开始运行用户模式下的应用程序,应用程序就得到了一块内存的首地址,并且可以使用这块内存了。
|
||||
|
||||
上面这个过程和一个实际的操作系统中的运行过程,可能有差异,但大同小异。当然,系统API和应用程序之间可能还有库函数,也可能只是分配了一个虚拟地址空间,但是我们关注的只是这个过程。
|
||||
|
||||
上图的宏内核结构有明显的缺点,因为它没有模块化,没有扩展性、没有移植性,高度耦合在一起,一旦其中一个组件有漏洞,内核中所有的组件可能都会出问题。
|
||||
|
||||
开发一个新的功能也得重新编译、链接、安装内核。其实现在这种原始的宏内核结构已经没有人用了。这种宏内核唯一的优点是性能很好,因为在内核中,这些组件可以互相调用,性能极高。
|
||||
|
||||
为了方便我们了解不同内核架构间的优缺点,下面我们看一个和宏内核结构对应的反例。
|
||||
|
||||
## 微内核结构
|
||||
|
||||
微内核架构正好与宏内核架构相反,它提倡内核功能尽可能少:仅仅只有进程调度、处理中断、内存空间映射、进程间通信等功能(目前不懂没事,这是属于管理进程和管理内存的功能模块,后面课程里还会专门探讨的)。
|
||||
|
||||
这样的内核是不能完成什么实际功能的,开发者们把实际的进程管理、内存管理、设备管理、文件管理等服务功能,做成一个个服务进程。和用户应用进程一样,只是它们很特殊,宏内核提供的功能,在微内核架构里由这些服务进程专门负责完成。
|
||||
|
||||
微内核定义了一种良好的进程间通信的机制——**消息**。应用程序要请求相关服务,就向微内核发送一条与此服务对应的消息,微内核再把这条消息转发给相关的服务进程,接着服务进程会完成相关的服务。服务进程的编程模型就是循环处理来自其它进程的消息,完成相关的服务功能。其结构如下所示:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/4b/64/4b190d617206379ee6cd77fcea231c64.jpg" alt="" title="微内核结构图">
|
||||
|
||||
为了理解微内核的工程原理,我们来看看微内核提供内存分配功能的服务过程,具体如下:
|
||||
|
||||
1.应用程序发送内存分配的消息,这个发送消息的函数是微内核提供的,相当于系统API,微内核的API(应用程序接口)相当少,极端情况下仅需要两个,一个接收消息的API和一个发送消息的API。<br>
|
||||
2.处理器切换到特权模式,开始运行内核代码。<br>
|
||||
3.微内核代码让当前进程停止运行,并根据消息包中的数据,确定消息发送给谁,分配内存的消息当然是发送给内存管理服务进程。<br>
|
||||
4.内存管理服务进程收到消息,分配一块内存。<br>
|
||||
5.内存管理服务进程,也会通过消息的形式返回分配内存块的地址给内核,然后继续等待下一条消息。<br>
|
||||
6.微内核把包含内存块地址的消息返回给发送内存分配消息的应用程序。<br>
|
||||
7.处理器开始运行用户模式下的应用程序,应用程序就得到了一块内存的首地址,并且可以使用这块内存了。
|
||||
|
||||
微内核的架构实现虽然不同,但是大致过程和上面一样。同样是分配内存,在微内核下拐了几个弯,一来一去的消息带来了非常大的开销,当然各个服务进程的切换开销也不小。这样系统性能就大打折扣。
|
||||
|
||||
但是微内核有很多优点,首先,系统结构相当清晰利于协作开发。其次,系统有良好的移植性,微内核代码量非常少,就算重写整个内核也不是难事。最后,微内核有相当好的伸缩性、扩展性,因为那些系统功能只是一个进程,可以随时拿掉一个服务进程以减少系统功能,或者增加几个服务进程以增强系统功能。
|
||||
|
||||
微内核的代表作有MACH、MINIX、L4系统,这些系统都是微内核,但是它们不是商业级的系统,商业级的系统不采用微内核主要还是因为性能差。
|
||||
|
||||
好了,粗略了解了宏内核和微内核两大系统内核架构的优、缺点,以后设计我们自己的系统内核时,心里也就有了底了,到时就可以扬长避短了,下面我们先学习一点其它的东西,即分离硬件相关性,为设计出我们自己的内核架构打下基础。
|
||||
|
||||
## 分离硬件的相关性
|
||||
|
||||
我们会经常听说,Windows内核有什么HAL层、Linux内核有什么arch层。这些xx层就是Windows和Linux内核设计者,给他们的系统内核分的第一个层。
|
||||
|
||||
今天如此庞杂的计算机,其实也是一层一层地构建起来的,从硬件层到操作系统层再到应用软件层这样构建。分层的主要目的和好处在于**屏蔽底层细节,使上层开发更加简单。**
|
||||
|
||||
计算机领域的一个基本方法是增加一个抽象层,从而使得抽象层的上下两层独立地发展,所以在内核内部再分若干层也不足为怪。
|
||||
|
||||
分离硬件的相关性,就是要把操作硬件和处理硬件功能差异的代码抽离出来,形成一个独立的**软件抽象层**,对外提供相应的接口,方便上层开发。
|
||||
|
||||
为了让你更好理解,我们举进程管理中的一个模块实现细节的例子:进程调度模块。通过这个例子,来看看分层对系统内核的设计与开发有什么影响。
|
||||
|
||||
一般操作系统理论课程都会花大量篇幅去讲进程相关的概念,其实说到底,进程是操作系统开发者为了实现多任务而提出的,并让每个进程在CPU上运行一小段时间,这样就能实现多任务同时运行的假象。
|
||||
|
||||
当然,这种假象十分奏效。要实现这种假象,就要实现下面这两种机制:
|
||||
|
||||
1.**进程调度**,它的目的是要从众多进程中选择一个将要运行的进程,当然有各种选择的算法,例如,轮转算法、优先级算法等。<br>
|
||||
2.**进程切换**,它的目的是停止当前进程,运行新的进程,主要动作是保存当前进程的机器上下文,装载新进程的机器上下文。
|
||||
|
||||
我们不难发现,不管是在ARM硬件平台上还是在x86硬件平台上,选择一个进程的算法和代码是不容易发生改变的,需要改变的代码是进程切换的相关代码,因为不同的硬件平台的机器上下文是不同的。
|
||||
|
||||
所以,这时最好是将进程切换的代码放在一个独立的层中实现,比如硬件平台相关层,当操作系统要运行在不同的硬件平台上时,就只是需要修改硬件平台相关层中的相关代码,这样操作系统的**移植性**就大大增强了。
|
||||
|
||||
如果把所有硬件平台相关的代码,都抽离出来,放在一个独立硬件相关层中实现并且定义好相关的调用接口,再在这个层之上开发内核的其它功能代码,就会方便得多,结构也会清晰很多。操作系统的移植性也会大大增强,移植到不同的硬件平台时,就构造开发一个与之对应的硬件相关层。这就是分离硬件相关性的好处。
|
||||
|
||||
## 我们的选择
|
||||
|
||||
从前面内容中,我们知道了内核必须要完成的功能,宏内核架构和微内核架构各自的优、缺点,最后还分析了分离硬件相关层的重要性,其实说了这么多,就是为了设计我们自己的操作系统内核。
|
||||
|
||||
虽然前面的内容,对操作系统设计这个领域还远远不够,但是对于我们自己从零开始的操作系统内核这已经够了。
|
||||
|
||||
首先大致将我们的操作系统内核分为三个大层,分别是:
|
||||
|
||||
1.内核接口层。<br>
|
||||
2.内核功能层。<br>
|
||||
3.内核硬件层。
|
||||
|
||||
内核接口层,定义了一系列接口,主要有两点内容,如下:
|
||||
|
||||
1.定义了一套UNIX接口的子集,我们出于学习和研究的目的,使用UNIX接口的子集,优点之一是接口少,只有几个,并且这几个接口又能大致定义出操作系统的功能。<br>
|
||||
2.这套接口的代码,就是检查其参数是否合法,如果参数有问题就返回相关的错误,接着调用下层完成功能的核心代码。
|
||||
|
||||
内核功能层,主要完成各种实际功能,这些功能按照其类别可以分成各种模块,当然这些功能模块最终会用具体的算法、数据结构、代码去实现它,内核功能层的模块如下:
|
||||
|
||||
1.进程管理,主要是实现进程的创建、销毁、调度进程,当然这要设计几套数据结构用于表示进程和组织进程,还要实现一个简单的进程调度算法。<br>
|
||||
2.内存管理,在内核功能层中只有内存池管理,分两种内存池:页面内存池和任意大小的内存池,你现在可能不明白什么是内存池,这里先有个印象就行,后面课程研究它的时候再详细介绍。<br>
|
||||
3.中断管理,这个在内核功能层中非常简单:就是把一个中断回调函数安插到相关的数据结构中,一旦发生相关的中断就会调用这个函数。<br>
|
||||
4.设备管理,这个是最难的,需要用一系列的数据结构表示驱动程序模块、驱动程序本身、驱动程序创建的设备,最后把它们组织在一起,还要实现创建设备、销毁设备、访问设备的代码,这些代码最终会调用设备驱动程序,达到操作设备的目的。
|
||||
|
||||
内核硬件层,主要包括一个具体硬件平台相关的代码,如下:
|
||||
|
||||
1.初始化,初始化代码是内核被加载到内存中最先需要运行的代码,例如初始化少量的设备、CPU、内存、中断的控制、内核用于管理的数据结构等。<br>
|
||||
2. CPU控制,提供CPU模式设定、开、关中断、读写CPU特定寄存器等功能的代码。<br>
|
||||
3.中断处理,保存中断时机器的上下文,调用中断回调函数,操作中断控制器等。<br>
|
||||
4.物理内存管理,提供分配、释放大块内存,内存空间映射,操作MMU、Cache等。<br>
|
||||
5.平台其它相关的功能,有些硬件平台上有些特殊的功能,需要额外处理一下。
|
||||
|
||||
如果上述文字让你看得头晕,我们来画幅图,可能就会好很多,如下所示,当然这里没有画出用户空间的应用进程,**API接口以下的为内核空间,这才是设计、开发内核的重点。**
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/6c/3c/6cf68bebe4f114f00f848d1d5679d33c.jpg" alt="" title="我们的内核结构">
|
||||
|
||||
从上述文字和图示,可以发现,我们的操作系统内核没有任何设备驱动程序,甚至没有文件系统和网络组件,内核所实现的功能很少。这吸取了微内核的优势,内核小出问题的可能性就少,扩展性就越强。
|
||||
|
||||
同时,我们把文件系统、网络组件、其它功能组件作为虚拟设备交由设备管理,比如需要文件系统时就写一个文件系统虚拟设备的驱动,完成文件系统的功能,需要网络时就开发一个网络虚拟设备的驱动,完成网络功能。
|
||||
|
||||
这些驱动一旦被装载,就是内核的一部分了,并不是像微内核一样作为服务进程运行。这又吸取了宏内核的优势,代码高度耦合,性能强劲。
|
||||
|
||||
这样的内核架构既不是宏内核架构也不是微内核架构,而是这两种架构综合的结果,可以说是混合内核架构,也可以说这是我们自己的内核架构……
|
||||
|
||||
好了,到这里为止,我们已经设计了内核,确定了内核的功能并且设计了一种内核架构用来组织这些功能,这离完成我们自己的操作系统内核又进了一步。
|
||||
|
||||
## 重点回顾
|
||||
|
||||
内核设计真是件让人兴奋的事情,今天的内容讲完了,我们先停下赶路的脚步,回过头来看一看这一节课我们学到了什么。
|
||||
|
||||
我们一开始感觉内核是个大黑盒,但通过分析通用计算机有哪些资源,就能推导出内核作为资源管理者应该有这些组件:I/O管理组件、内存管理组件、文件系统组件、进程管理组件、图形系统组件、网络组件、安全组件等。
|
||||
|
||||
接着,我们探讨了用两种结构来组织这些组件,这两种结构分别是宏内核结构和微内核结构,知道了他们各自的优缺点,**宏内核有极致的性能,微内核有极致的可移植性、可扩展性。**还弄清楚了它们各自完成应用程序服务的机制与流程。
|
||||
|
||||
然后,我们研究了分层的重要性,为什么分离硬件相关性。用实例说明了分离硬件相关性的好处,这是为了更容易扩展和移植。
|
||||
|
||||
最后,在前面的基础上,我们为自己的内核设计作出了选择。
|
||||
|
||||
我们的内核结构分为三层:内核硬件层,内核功能层,内核接口层,内核接口层主要是定义了一套UNIX接口的子集,内核功能层主要完成I/O管理组件、内存管理组件、文件系统组件、进程管理组件、图形系统组件、网络组件、安全组件的通用功能型代码;内核硬件层则完成其内核组件对应的具体硬件平台相关的代码。
|
||||
|
||||
## 思考题
|
||||
|
||||
其实我们的内核架构不是我们首创的,它是属于微内核、宏内核之外的第三种架构,请问这是什么架构?
|
||||
|
||||
欢迎你在留言区跟我交流互动。如果这节课对你有启发,也欢迎分享给你的朋友或同事。
|
||||
147
极客时间专栏/操作系统实战45讲/心有蓝图:设计/04 | 震撼的Linux全景图:业界成熟的内核架构长什么样?.md
Normal file
147
极客时间专栏/操作系统实战45讲/心有蓝图:设计/04 | 震撼的Linux全景图:业界成熟的内核架构长什么样?.md
Normal file
@@ -0,0 +1,147 @@
|
||||
<audio id="audio" title="04 | 震撼的Linux全景图:业界成熟的内核架构长什么样?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/93/ea/9304970b119d7bd464c2acc4b65460ea.mp3"></audio>
|
||||
|
||||
你好,我是LMOS。
|
||||
|
||||
什么?你想成为计算机黑客?
|
||||
|
||||
梦想坐在计算机前敲敲键盘,银行账号里的数字就会自己往上涨。拜托,估计明天你就该被警察逮捕了。真正的黑客是对计算机技术有近乎极致的追求,而不是干坏事。
|
||||
|
||||
下面我就带你认识这样一个计算机黑客,看看他是怎样创造出影响世界的Linux,然后进一步了解一下Linux的内部结构。
|
||||
|
||||
同时,我也会带你看看Windows NT和Darwin的内部结构,三者形成对比,你能更好地了解它们之间的差异和共同点,这对我们后面写操作系统会很有帮助。
|
||||
|
||||
## 关于Linus
|
||||
|
||||
Linus Benedict Torvalds,这个名字很长,下面简称Linus,他1969年12月28日出生在芬兰的赫尔辛基市,并不是美国人。Linus在赫尔辛基大学学的就是计算机,妻子还是空手道高手,一个“码林高手”和一个“武林高手”真的是绝配啊。
|
||||
|
||||
Linus在小时候就对各种事情充满好奇,这点非常具有黑客精神,后来有了自己的计算机更是痴迷其中,开始自己控制计算机做一些事情,并深挖其背后的原理。就是这种黑客精神促使他后来写出了颠覆世界的软件——Linux,也因此登上了美国《时代》周刊。
|
||||
|
||||
你是否对很多垃圾软件感到愤慨,但自己又无法改变。Linus就不一样,他为了方便访问大学服务器中的资源 ,而在自己的机器上写了一个文件系统和硬盘驱动,这样就可以把自己需要的资源下载到自己的机器中。
|
||||
|
||||
再后来,这成为了Linux的第一个版本。看看牛人之所以为牛人就是敢于对现有的规则说不,并勇于改变。
|
||||
|
||||
如果仅仅如此,那么也不会有后来的Linux内核。Linus随后做了一个重要决定,他把这款操作系统雏形开源,并加入到自由软件运动,以GPL协议授权,允许用户自由复制或者改动程序代码,但用户必须公开自己的修改并传播。
|
||||
|
||||
无疑,正是Linus的这一重要决定使得Linux和他自己名声大振。短短几年时间,就已经聚集了成千上万的狂热分子,大家不计得失的为Linux添砖加瓦,很多程序员更是对Linus像神明一样顶礼膜拜。
|
||||
|
||||
## Linux内核
|
||||
|
||||
好了回到正题,回到Linux。Linus也不是什么神明,现有的Linux,99.9%的代码都不是Linus所写,而且他的代码,也不一定比你我的代码写得更好。
|
||||
|
||||
Linux,全称GNU/Linux,是一套免费使用和自由传播的操作系统,支持类UNIX、POSIX标准接口,也支持多用户、多进程、多线程,可以在多CPU的机器上运行。由于互联网的发展,Linux吸引了来自全世界各地软件爱好者、科技公司的支持,它已经从大型机到服务器蔓延至个人电脑、嵌入式系统等领域。
|
||||
|
||||
Linux系统性能稳定且开源。在很多公司企业网络中被当作服务器来使用,这是Linux的一大亮点,也是它得以壮大的关键。
|
||||
|
||||
Linux的基本思想是一切都是文件:每个文件都有确定的用途,包括用户数据、命令、配置参数、硬件设备等对于操作系统内核而言,都被视为各种类型的文件。Linux支持多用户,各个用户对于自己的文件有自己特殊的权利,保证了各用户之间互不影响。多任务则是现代操作系统最重要的一个特点,Linux可以使多个程序同时并独立地运行。
|
||||
|
||||
Linux发展到今天,不是哪一个人能做到的,更不是一群计算机黑客能做到的,而是由很多世界级的顶尖科技公司联合开发,如IBM、甲骨文、红帽、英特尔、微软,它们开发Linux并向Linux社区提供补丁,使Linux工作在它们的服务器上,向客户出售业务服务。
|
||||
|
||||
Linux发展到今天其代码量近2000万行,可以用浩如烟海来形容,没人能在短时间内弄清楚。但是你也不用害怕,我们可以先看看Linux内部的全景图,从全局了解一下Linux的内部结构,如下图。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/92/cb/92ec3d008c77bb66a148772d3c5ea9cb.png" alt="" title="Linux内部的全景图">
|
||||
|
||||
啊哈!是不是感觉壮观之后一阵头晕目眩,头晕目眩就对了,因为Linux太大了,别怕,下面我们来分解一下。但这里我要先解释一下,上图仍然不足于描述Linux的全部,只是展示了重要且显而易见的部分。
|
||||
|
||||
上图中大致分为**五大重要组件**,每个组件又分成许多模块从上到下贯穿各个层次,每个模块中有重要的函数和数据结构。具体每个模块的主要功能,我都给你列在了文稿里,你可以详细看看后面这张图。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/8d/b2/8dc5780041e95c8ec269bc4b97eda0b2.jpg" alt="">
|
||||
|
||||
不要着急,不要心慌,因为现在我们不需要搞清楚这些Linux模块的全部实现细节,只要在心里默念Linux的模块真多啊,大概有五大组件,有好几十个模块,每个模块主要完成什么功能就行了。
|
||||
|
||||
是不是松了口气,先定定神,然后我们就能发现Linux这么多模块挤在一起,之间的通信主要是函数调用,而且函数间的调用没有一定的层次关系,更加没有左右边界的限定。函数的调用路径是纵横交错的,从图中的线条可以得到印证。
|
||||
|
||||
继续深入思考你就会发现,这些纵横交错的路径上有一个函数出现了问题,就麻烦大了,它会波及到全部组件,导致整个系统崩溃。当然调试解决这个问题,也是相当困难的。同样,模块之间没有隔离,安全隐患也是巨大的。
|
||||
|
||||
当然,这种结构不是一无是处,它的性能极高,而性能是衡量操作系统的一个重要指标。这种结构就是传统的内核结构,也称为**宏内核架构**。
|
||||
|
||||
想要评判一个产品好不好,最直接的方法就是用相似的产品对比。你说Linux很好,但是什么为好呢?我说Linux很差,它又差在什么地方呢?
|
||||
|
||||
下面我们就拿出Windows和macOS进行对比,注意我们只是对比它们的内核架构。
|
||||
|
||||
## Darwin-XNU内核
|
||||
|
||||
我们先来看看Darwin,Darwin是由苹果公司在2000年开发的一个开放源代码的操作系统。
|
||||
|
||||
一个经久不衰的公司,必然有自己的核心竞争力,也许是商业策略,也许是技术产品,又或是这两者的结合。而作为苹果公司各种产品和强大的应用生态系统的支撑者——Darwin,更是公司核心竞争力中的核心。
|
||||
|
||||
苹果公司有台式计算机、笔记本、平板、手机,台式计算机、笔记本使用了macOS操作系统,平板和手机则使用了iOS操作系统。Darwin作为macOS与iOS操作系统的核心,从技术实现角度说,它必然要支持PowerPC、x86、ARM架构的处理器。
|
||||
|
||||
Darwin 使用了一种微内核(Mach)和相应的固件来支持不同的处理器平台,并提供操作系统原始的基础服务,上层的功能性系统服务和工具则是整合了BSD系统所提供的。苹果公司还为其开发了大量的库、框架和服务,不过它们都工作在用户态且闭源。
|
||||
|
||||
下面我们先从整体看一下Darwin的架构。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/5e/8d/5e9bd6dd86fba5482fab14b6b292aa8d.jpg" alt="" title="Darwin架构图">
|
||||
|
||||
什么?两套内核?惊不惊喜?由于我们是研究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和BSD就同时存在了。
|
||||
|
||||
Mach中还有一个重要的组件Libkern,它是一个库,提供了很多底层的操作函数,同时支持C++运行环境。
|
||||
|
||||
依赖这个库的还有IOKit,IOKit管理所有的设备驱动和内核功能扩展模块。驱动程序开发人员则可以使用C++面向对象的方式开发驱动,这个方式很优雅,你完全可以找一个成熟的驱动程序作为父类继承它,要特别实现某个功能就重载其中的函数,也可以同时继承其它驱动程序,这大大节省了内存,也大大降低了出现BUG的可能。
|
||||
|
||||
如果你要详细了解Darwin内核的话,可以自行阅读[相应的代码](https://github.com/apple/darwin-xnu)。而在这里,你只要从全局认识一下它的结构就行了。
|
||||
|
||||
## Windows NT内核
|
||||
|
||||
接下来我们再看下 NT 内核。现代Windows的内核就是NT,我们不妨先看看NT的历史。
|
||||
|
||||
如果你是90后,大概没有接触过MS-DOS,它的交互方式是你在键盘上输入相应的功能命令,它完成相应的功能后给用户返回相应的操作信息,没有图形界面。
|
||||
|
||||
在MS-DOS内核的实现上,也没有应用现代硬件的保护机制,这导致后来微软基于它开发的图形界面的操作系统,如Windows 3.1、Windows95/98/ME,极其不稳定,且容易死机。
|
||||
|
||||
加上类UNIX操作系统在互联网领域大行其道,所以微软急需一款全新的操作系统来与之竞争。所以,Windows NT诞生了。
|
||||
|
||||
Windows NT是微软于1993年推出的面向工作站、网络服务器和大型计算机的网络操作系统,也可做PC操作系统。它是一款全新从零开始开发的新操作系统,并应用了现代硬件的所有特性,“NT”所指的便是“新技术”(New Technology)。
|
||||
|
||||
而普通用户第一次接触基于NT内核的Windows是Windows 2000,一开始用户其实是不愿意接受的,因为Windows 2000对用户的硬件和应用存在兼容性问题。
|
||||
|
||||
随着硬件厂商和应用厂商对程序的升级,这个兼容性问题被缓解了,加之Windows 2000的高性能、高稳定性、高安全性,用户很快便接受了这个操作系统。这可以从Windows 2000的迭代者Windows XP的巨大成功,得到验证。
|
||||
|
||||
现在,NT内核在设计上层次非常清晰明了,各组件之间界限耦合程度很低。下面我们就来看看NT内核架构图,了解一下NT内核是如何“庄严宏伟”。如下图:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/c5/c9/c547b6252736375fcdb1456e6dfaa3c9.jpg" alt="" title="NT内核架构图">
|
||||
|
||||
这样看NT内核架构,是不是就清晰了很多?但这并不是我画图画得清晰,事实上的NT确实如此。
|
||||
|
||||
这里我要提示一下,上图中我们只关注内核模式下的东西,也就是传统意义上的内核。
|
||||
|
||||
当然微软自己在HAL层上是定义了一个小内核,小内核之下是硬件抽象层HAL,这个HAL存在的好处是:不同的硬件平台只要提供对应的HAL就可以移植系统了。小内核之上是各种内核组件,微软称之为内核执行体,它们完成进程、内存、配置、I/O文件缓存、电源与即插即用、安全等相关的服务。
|
||||
|
||||
每个执行体互相独立,只对外提供相应的接口,其它执行体要通过内核模式可调用接口和其它执行体通信或者请求其完成相应的功能服务。所有的设备驱动和文件系统都由I/O管理器统一管理,驱动程序可以堆叠形成I/O驱动栈,功能请求被封装成I/O包,在栈中一层层流动处理。Windows引以为傲的图形子系统也在内核中。
|
||||
|
||||
显而易见,NT内核中各层次分明,各个执行体互相独立,这种“高内聚、低偶合”的特性,正是检验一个软件工程是否优秀的重要标准。而这些你都可以通过微软公开的WRK代码得到佐证,如果你觉得WRK代码量太少,也可以看一看[REACT OS](https://reactos.org/)这个号称“开源版”的NT。
|
||||
|
||||
## 重点回顾
|
||||
|
||||
到这里,我们了解了Linux、Darwin-XNU和Windows的发展历史,也清楚了它们内部的组件和结构,并对它们的架构进行了对比,对比后我们发现:**Linux性能良好,结构异常复杂,不利于问题的排查和功能的扩展,而Darwin-XNU和Windows结构良好,层面分明,利于功能扩展,不容易产生问题且性能稳定。**
|
||||
|
||||
下面我们来回顾下这节课的重点。
|
||||
|
||||
首先,我们从一名计算机黑客切入,简单介绍了一下Linus,他由于沉迷于技术,对不好的规则敢于挑战而写出了Linux雏形,并且利用了GNU开源软件的精神推动了Linux后来的发展,这样的精神很值得我们学习。
|
||||
|
||||
然后我们探讨了Linux内核架构,大致搞清楚了Linux内核中的各种组件,它们是系统、进程、内存、储存、网络。其中,每个组件都是从接口到硬件经过了几个层次,组件与组件之间的层次互联调用。这些组件组合在一起,其调用关系形成了一个巨大的网状结构。因此,Linux也成了宏内核的代表。
|
||||
|
||||
为了有所对比,我们研究了苹果的Darwin-XNU内核结构,发现其分层更细,固件层、Mach层屏蔽了硬件平台的细节,向上层提供了最基础的服务。在Mach层之上的BSD层提供了更完善的服务,它们是进程与线程、IPC通信、虚拟内存、安全、网络协议栈以及文件系统。通过Mach中断嵌入表,可以让应用自己决定使用Mach层服务还是使用BSD层的服务,因此Darwin-XNU拥有了两套内核,Darwin-XNU内核层也成为了多内核架构的代表。
|
||||
|
||||
最后,我们研究了迄今为止,最成功的商业操作系统——Windows,它的内核是NT,其结构清晰明了,各组件完全遵循了软件工程**高内聚、低偶合**的设计标准。最下层是HAL(硬件抽象),HAL层是为了适配各种不同的硬件平台;在HAL层之上就是微软定义的小内核,你可以理解成是NT内核的内核;在这个小内核之上就是各种执行体了,这些执行体提供了操作系统的进程、虚拟内存、文件数据缓存、安全、对象管理、配置等服务,还有Windows的技术核心图形系统。
|
||||
|
||||
## 思考题
|
||||
|
||||
Windows NT内核属于哪种架构类型?
|
||||
|
||||
很期待在留言区看到你的分享,也欢迎你把这节课分享给身边的同事、朋友。
|
||||
|
||||
我是LMOS,让我们下节课见。
|
||||
Reference in New Issue
Block a user