本系列文章为MIT6.S081的学习笔记,包含了参考手册、课程、实验三部分的内容,前面的系列文章链接如下
操作系统MIT6.S081:[xv6参考手册第1章]->操作系统接口
本文由MITS6.081课程内容翻译而来,由于水平有限,加之第一次学习操作系统,许多内容难免有误。敬请各位网友指出以便持续修正,谢谢!
参考内容: MIT6.S081(2020)翻译简介
一、操作系统概述
这门课程的目标
①理解操作系统的设计和实现。设计是指整体的结构,实现是指具体的代码长什么样。
②通过一个名为XV6的小型操作系统深入了解具体的工作原理、获得扩展操作系统、修改并提升操作系统的相关经验
③通过研究现有的操作系统并结合课程配套的实验,能够通过操作系统接口编写系统软件。
期待操作系统支持的目标
市面上有大量不同的操作系统,通常来说它们都有一些共同的目标:
①Abstraction。通常来说,你买了一台计算机,里面包含了CPU、内存等硬件,但是这是一种非常低层级的资源。幸好我们有一些应用程序实现了高层级的接口和抽象,例如进程、文件系统。这些高层级的接口和抽象(Abstraction)方便了应用的开发,也提供了更好的移植性。
②multiplex。操作系统的另一个重要的任务是:在多个应用程序之间共用硬件资源。你可以在一个操作系统同时运行文本编辑器、程序编译器、多个数据库等应用程序。操作系统能非常神奇地在不相互干扰的前提下同时运行这些程序,这里通常被称为multiplex。
③Isolation。在操作系统中可能同时运行很多程序,当一个或多个程序出现了故障,这些程序之间互不干扰就变得非常重要。所以这里需要隔离性(Isolation),不同的活动之间不能相互干扰。
④Sharing。另一方面,不同的活动之间有时又想要相互影响,比如说数据交互、协同完成任务等。例如,我通过文本编辑器创建了一个文件,我希望我的编译器能读取文件,即我们想共享一些数据。所以,我们希望能在需要的时候实现共享(Sharing)。
⑤Security。是在很多场景下,用户并不想要共享。比如你登录到了一个公共的计算机,你不会想要其他人来读取你的文件。所以在共享的同时,我们也希望在没有必要的时候不共享。这里我们称为Security或Permission System或Access Control System。
⑥Performance。人们认为操作系统应该具有的价值是:如果你在硬件上花费了大量的金钱,你的应用程序应该拥有硬件提供的完整性能。所以操作系统必须保证自身提供的服务不会阻止应用程序获得高性能,甚至需要帮助应用程序获得高性能(Performance)。
⑦Range of uses。对于大部分操作系统,必须要支持大量不同类型的应用程序,如一个笔记本正在运行文本编辑器、正在运行游戏,或者你的操作系统需要支持数据库服务器和云计算。通常来说,设计并构造一个操作系统代价是非常大的,所以人们总是希望在相同的操作系统上运行大量的任务。所以,同一个操作系统需要能够支持大量不同的用户场景(Range of uses)。
操作系统的组织架构
过去几十年,人们将一些分层的设计思想加入到操作系统中,并运行得很好。操作系统经典的组织结构如下所示:
①底层硬件
当我们想到操作系统得组织结构时,我们首先会想到用一个矩形表示一个计算机。这个计算机有一些硬件资源,包括CPU、内存、磁盘、网卡等。我们将这些硬件资源其放在矩形的下面,所以硬件资源在最底层。
②用户空间
在这个架构的最上层,我们会运行各种各样的应用程序,如文本编辑器(VI)、C编译器(CC)、作为命令行界面(Command-line Interface, CLI)存在的Shell。这里程序都运行在同一个空间中,我们通常将其称为用户空间(Userspace)
③内核
区别于用户空间程序,有一个特殊的程序总是会在运行,它被称为Kernel。Kernel是计算机资源的守护者,当你打开计算机时,Kernel总是第一个被启动。Kernel程序只有一个,它维护数据来管理用户空间中的每一个进程。Kernel同时还维护了大量的数据结构来帮助它管理各种各样的硬件资源,以供给用户空间的程序使用。Kernel同时还有大量内置的服务,如文件系统FS,它实现了类似文件名、文件内容、目录的东西,并知道如何将文件存储在磁盘中。所以用户空间的程序会与Kernel中的文件系统交互,文件系统再与磁盘交互。
二、操作系统内核
Kernel提供的服务
在这门课程中,我们主要的关注点在Kernel内部发生的事情、连接Kernel和用户空间程序的接口、Kernel内软件的架构。我们来看看Kernel提供的一些服务
①进程
每一个用户空间中的程序都被称为一个进程,它们有自己的内存和共享的CPU时间。
②内存分配
Kernel会管理各个进程内存的分配。不同的进程需要不同数量的内存,Kernel会复用内存、划分内存,并为所有的进程分配内存。
③文件内容
文件系统通常有一些逻辑分区。目前而言,我们可以认为文件系统的作用是管理文件内容并找出文件具体在磁盘中的哪个位置。
④文件名、文件目录
文件系统还维护了一个独立的命名空间,其中每个文件都有文件名,并且命名空间中有一个层级的目录,每个目录包含了一些文件。所有这些都被文件系统所管理。
⑤访问控制
当一个进程想要使用某些资源时,比如读取磁盘中的数据、使用某些内存,Kernel中的Access Control机制会决定是否允许这样的操作。对于一个分时共享的计算机(例如Athena系统),这里可能会变得很复杂。因为在Athena系统中,每一个进程可能属于不同的用户,因此会有不同Access规则来约定哪些资源可以被访问。
⑥其它
在一个真实的完备的操作系统中,还会有很多其他的服务。比如在不同进程之间通信的进程间通信服务、许多与网络关联的软件(TCP/IP协议栈)、支持声卡的软件、支持数百种不同磁盘、不同网卡的驱动。所以在一个完备的系统中,Kernel会包含大量的内容,数百万行代码。
Kernel的一些API
我们也对应用程序是如何与Kernel交互、它们之间的接口长什么样感兴趣。这里通常称为Kernel的API,它决定了应用程序如何访问Kernel。通常来说,这里是通过所谓的系统调用(System Call)来完成。系统调用与程序中的函数调用看起来是一样的,但区别是系统调用会实际运行到系统内核中,并执行内核中对于系统调用的实现。在这门课程的后面,我们再详细介绍系统调用,现在我们只学习以下系统调用在应用程序中是长什么样的。
open
fd = open("out", 1)。如果应用程序需要打开一个文件,它会调用名为open的系统调用,并且把文件名作为参数传给open。假设现在要打开一个名为“out”的文件,那么会将文件名“out”作为参数传入。同时我们还希望写入数据,那么还会有一个额外的参数,在这里这个参数的值是1,表明我想要写文件。这里看起来像是个函数调用,但是open是一个系统调用,它会跳到Kernel。Kernel可以获取到open的参数,执行一些实现了open的Kernel代码,或许会与磁盘有一些交互,最后返回一个文件描述符对象fd(file descriptor)。之后,应用程序可以使用这个文件描述符来表示相应打开的文件。
write
write(fd, "hello\n", 6)。如果你想要向文件写入数据,相应的系统调用是write。你需要向write传递一个由open返回的文件描述符作为第一个参数。还需要向write传递一个指向要写入数据的指针(数据通常是char型序列)作为第二个参数。所以我们这里实际上告诉内核,将内存中这个地址起始的6个字节数据写入到fd对应的文件中。第三个参数是你想要写入字符的数量。
fork
int pid = fork()。fork是一个这样的系统调用,它创建了一个与调用进程一模一样的新的进程,并返回新进程的process ID(PID)。这里实际上会复杂的多,我们后面会有更多的介绍
注:所以对这些系统调用看起来就跟普通的函数调用一样。系统调用不同的地方是,它最终会跳到系统内核中。

本文详细解读了操作系统设计的概述、内核服务、系统调用、XV6实例、I/O重定向,以及设计中的矛盾点,如抽象与效率、接口复杂性与易用性等。通过学习XV6,理解操作系统接口和内核实现的关键概念。




最低0.47元/天 解锁文章
609

被折叠的 条评论
为什么被折叠?



