操作系统从入门到入土①:概述
深入理解计算机系统使用指南:https://book.douban.com/review/5627139/
1. 什么是操作系统
操作系统所处的位置
硬件包括芯片、电路板、磁盘、键盘、显示器以及类似的设备。
用户态和内核态
多数计算机有两种运行模式:内核态和用户态。
- 内核态:操作系统运行在内核态,具有对所有硬件的完全访问权,可以执行机器能够运行的任何指令。内核态的程序由硬件保护,防止用户试图对其进行修改。
- 用户态:软件的其余部分运行在用户态,只使用了机器指令中的一个子集。
1.1. 操作系统分类
- 单用户操作系统:单用户操作系统一次只能支持一个用户程序的运行。单用户操作系统向用户提供联机交互式的工作环境,比如 MS-DOS 就是一个经典的单用户操作系统。
- 批处理操作系统:早期的一种大型机用操作系统。可对用户作业成批处理,期间无需用户干预,分为单道批处理系统和多道批处理系统。
- 分时操作系统:利用分时技术的一种联机的多用户交互式操作系统,每个用户可以通过自己的终端向系统发出各种操作控制命令,完成作业的运行。分时是指把处理机的运行时间分成很短的时间片,按时间片轮流把处理机分配给各联机作业使用。
- 实时操作系统:一个能够在指定或者确定的时间内完成系统功能以及对外部或内部事件在同步或异步时间内做出响应的系统,实时意思就是对响应时间有严格要求,要以足够快的速度进行处理。分为硬实时和软实时两种。
- 通用操作系统:同时兼有多道批处理、分时、实时处理的功能,或者其中两种以上功能的操作系统。
- 网络操作系统:一种在通常操作系统功能的基础上提供网络通信和网络服务功能的操作系统。
- 分布式操作系统:一种以计算机网络为基础的,将物理上分布的具有自治功能的数据处理系统或计算机系统互联起来的操作系统。分布式系统中各台计算机无主次之分,系统中若干台计算机可以并行运行同一个程序,分布式操作系统用于管理分布式系统资源。
- 嵌入式操作系统:一种运行在嵌入式智能芯片环境中,对整个智能芯片以及它所操作、控制的各种部件装置等资源进行统一协调、处理、指挥和控制的系统软件。
1.2. 操作系统接口
分为系统调用接口、POSIX 接口和领域应用接口
1.2.1. 系统调用接口
应用程序通过操作系统内核提供的接口(例如系统调用)向内核申请服务。
printf -> lib 中的 write -> svc 下陷到内核 -> 下陷处理函数 sys_syscall 找到内核对应中对应的函数 -> sys_write
1.2.2. POSIX 接口
为了同一个应用程序在不同操作系统上的可移植性,逐渐形成了一些可移植操作系统接口标准。
POSIX(Portable Operating System Interface for uniX,可移植操作系统接口)。POSIX 标准通常通过 C library(libc)来实现,常见的 libc 包括 glibc、musl、eglibc。 Android 也实现了一个名为 bionic 的 libc。
应用程序只需要调用 libc 提供的接口就可以实现对操作系统功能的调用。
1.2.3. 领域应用接口
在 POSIX 或操作系统调用的基础上还可以封装面向不同领域的领域应用接口。
2. 硬件
2.1. CPU
指令集架构(Instruction Set Architecture, ISA)是 CPU 和软件之间的桥梁。ISA 包含指令集、特权级、寄存器、执行模式、安全扩展、性能加速扩展等诸多方面。
2.1.1. 指令集
每个 CPU 都有一套可执行的专门 ** 指令集 **。所以,x86 处理器不能执行 ARM 程序,而 ARM 处理器也不能执行 x86 程序。
2.1.2. 特权级
AArch64(首款 64 位架构的 ARM 处理器)中的特权级被称为异常级别(Exception Level,EL)
- EL0:最低的特权级,应用程序通常运行在该特权级,也称为 用户态。
- EL1:操作系统通常运行在该特权级,也称为 ** 内核态 **。
- EL2:在虚拟化场景下需要,虚拟机监控器(Virtual Machine Monitor,VMM)通常运行在该特权级。
- EL3:TrustZone 是从 ARMv6 体系结构开始引入的安全特性,其从逻辑上将整个系统分为安全世界(能访问所有资源)和普通世界(不能访问安全世界的资源)。
EL3 和安全特性 TrustZone 相关,负责普通世界和安全世界之间的切换。
用户态切换至内核态的场景:
- 应用程序执行 svc(特权调用,supervisor call)指令切换。
- 指令触发异常切换,如缺页异常。
- CPU 收到来自外设的中断。
用户态切换至内核态过程:
操作系统可以在异常向量表中为不同的异常类型配置相应的异常处理函数。
- 发生特权级切换时,CPU 会读取 VBAR_EL1(向量基地址寄存器,Vector Base Address Register)来获得 异常向量表(exception vector table)的基地址。
- 然后根据异常原因(ESR_EL1 中保存的内容)调用操作系统设置的相应异常处理函数。
- 该函数通常会先保存应用程序的上下文(如通用寄存器),然后会根据异常原因进行相应的处理。
例如,若特权级切换是应用程序执行 svc 指令导致的,则执行相应的系统调用;
若特权级切换是访存过程中缺页异常导致的,则执行相应的缺页异常处理函数。
- 异常处理完成之后,操作系统会恢复应用程序的上下文,然后执行 eret(异常返回,Exception Return)指令恢复 CPU 自动保存的 EL0 状态,并切回到 EL0,使应用程序从被中断处继续执行。
pipeline
为了改善性能,CPU 设计师早就放弃了同时读取、解码和执行一条指令的简单模型。许多现代 CPU 具有同时 ** 取出多条指令 ** 的机制。这样的机制称为 流水线(pipeline)。
例如,一个 CPU 可以有单独的取指单元、解码单元和执行单元,于是当它执行指令 n 时,还可以对指令 n +1 解码,并且读取指令 n +2。
超标量 CPU
超标量 CPU,有多个执行单元。两个或更多的指令被同时取出、解码并装入暂存缓冲区中,直至它们执行完毕。只要有一个执行单元空闲,就检查保持缓冲区中是否还有可处理的指令,如果有,就把指令从缓冲区中移出并执行之。
有指令不按顺序执行的隐患。
例如,一个 CPU 用于整数算术运算,一个 CPU 用于浮点算术运算,一个 CPU 用于布尔运算。
2.1.3. 寄存器
用与 CPU 相同的材料制成,所以和 CPU 一样快。
2.2. 存储器
存储器分层结构
2.2.2. 高速缓存
L1 缓存:总是在 CPU 中,用来将已解码的指令调入 CPU 的执行引擎,不存在任何延时。
L2 缓存:用来存放近来使用过的若干兆字节的内存字,延时 1 或 2 个时钟周期。
- 带有共享 L2 缓存的 4 核芯片(Intel):
- 带有分离 L2 缓存的 4 核芯片(AMD):
缓存行:
CPU 缓存是由若干个缓存行(cache line)组成的。物理内存与 CPU 缓存之间的数据传输以缓存行为单位,一般为 64 字节。这比单个字节读取要快得多。
每个缓存行有一个用于表示其是否有效的有效位(valid bit)和一个用于标识其对应的物理地址的标记地址(tag address)。
缓存命中:
当某个程序需要读一个存储字时,高速缓存硬件检查所需要的高速缓存行是否在高速缓存中。
- 命中,就不需要访问主存,命中通常需要两个时钟周期。
- 未命中就必须访问内存,这将花费大量时间。
存储器读取某一个位置,接下来访问这个位置的概率非常高,尤其是紧随其后的内存位置。
缓存结构:
物理地址在逻辑上分为 Tag、Set(也称为 Index)以及 Offset 三段。
类似三维坐标中的 xyz 坐标
组(Set)与路(Way)是 CPU 缓存的经典概念。
- 物理地址中的 Set 段能表示的最大数目称为组。
- 同一组(即 Set 段相等)下,支持的最大 Tag 数则称为路,即同一组下的缓存行数目,该 CPU 缓存被称为 4 路组相联(4-Way Set Associative)。
2.2.3. 主存
- 随机访问存储器(RAM)
- 只读存储器(ROM):用于启动计算机的引导加载模块
- 电可擦除可编程 ROM(EEPROM) 和闪存:与 ROM 相比可以擦除和重写
2.2.4. 磁盘
概念:
- 在任意一个给定臂的位置,每个磁头可以读取一段环形区域,称为 磁道(track)。
- 把一个给定臂的位置上的所有磁道合并起来,组成了一个 柱面(cylinder)。外部的柱面比内部的柱面有更多的扇区。
过程:
- 机械臂从一个柱面移到相邻的柱面大约需要 1ms。而随机移到一个柱面的典型时间为 5ms 至 10ms,其具体时间取决于驱动器。
- 一旦磁臂到达正确的磁道上,驱动器必须等待所需的扇区旋转到磁头之下,这就增加了 5ms 至 10ms 的时延,其具体延时取决于驱动器的转速。
- 一旦所需要的扇区移到磁头之下,就开始读写,低端硬盘的速率是 50MB/s,而高速磁盘的速率是 160 MB/s。
2.2.5. I/O 设备
- 实际设备:如 SATA(串行高级技术附件),标准化后任何一个 SATA 磁盘控制器就可以适配任一种 SATA 磁盘。
- 设备控制器:
设备控制器是插在电路板上的一块芯片或一组芯片。它从操作系统接收命令,物理地控制设备。
例如,从设备读数据,并且完成数据的处理。
控制器的任务是为操作系统提供一个简单的接口(不过还是很复杂)。
例如,磁盘控制器可以接受一个命令从磁盘 2 读出 11206 号扇区,然后,控制器把这个线性扇区号转化为柱面、扇区和磁头。
- 设备驱动程序:与设备控制器交互的软件。每个控制器厂家必须为所支持的操作系统提供相应的设备驱动程序。
例如,一台扫描仪会配有用于 OS X、Windows 7、Windows 8 以及 Linux 的设备驱动程序。
设备驱动器装入操作系统的三个途径:
- 将内核与设备驱动程序重新链接,然后重启动系统。许多 UNIX 系统以这种方式工作。
- 在一个操作系统文件中设置一个入口,并通知该文件需要一个设备驱动程序,然后重启动系统。在系统启动时,操作系统去找寻所需的设备驱动程序并装载之。Windows 就是以这种方式工作。
- 操作系统能够在运行时接受新的设备驱动程序并且立即将其安装好,无须重启动系统。热插拔设备,像 USB 之类需要动态可装载设备驱动程序。
- I/O 端口空间:
每个设备控制器都有少量用于通信的寄存器。
要激活控制器,设备驱动程序从操作系统获得一条命令,然后翻译成对应的值,并写进设备寄存器中。所有设备寄存器的集合构成了 I/O 端口空间。
例如,一个最小的磁盘控制器也会有用于指定磁盘地址、内存地址、扇区计数和方向(读或写)的寄存器。
内存映射 I/O(Memory-Mapped I/O MMIO)
把输人输出设备和物理内存放到同一个地址空间,为设备内部的内存和寄存器也分配相应的地址。
CPU 可以使用和访问物理内存一样的指令去读写这些属于设备的地址。
实现输入输出的三种方式:
- 忙等待(轮询):
用户程序发出一个系统调用,内核对设备驱动程序进行过程调用,然后设备驱动程序启动 I/O 并循环检查该设备是否完成了工作。
当 I/O 结束后,设备驱动程序把数据送到指定的地方并返回,然后操作系统将控制返回给调用者。
其缺点是要占据 CPU,CPU 一直轮询设备直到对应的 I/O 操作完成。
- 中断:
设备驱动程序启动设备,让该设备在操作完成时发出一个中断,设备驱动程序在这个时刻返回。
当设备驱动程序检测到该设备的操作完毕时,它发出一个中断通知操作完成,操作系统接着在需要时阻塞调用者并安排其他工作进行。
- 直接存储器访问(DMA)芯片:
可以控制在内存和某些控制器之间的位流,而无须持续的 CPU 干预。CPU 对 DMA 芯片进行设置,说明需要传送的字节数、有关的设备和内存地址以及操作方向,接着启动 DMA。当 DMA 芯片完成时,它引发一个中断。
MMIO 使得 CPU 可以主动地访问设备,中断使得设备能够主动地通知 CPU,这两种机制是 CPU 与设备之间交互的重要方式。
2.2.6. 总线
概述:
系统有很多总线(例如高速缓存、内存、PCle、PCI、USB、SATA 和 DMI),每条总线的传输速度和功能都不同。操作系统必须了解所有总线的配置和管理。其中主要的总线是 PCIe 总线。
USB(Universal Serial Bus):
将所有慢速 I/O 设备(如键盘和鼠标)与计算机连接。USB 是一种集中式总线,其根设备每 1ms 轮询一次 IO 设备,看是否有信息收发。USB 1.0 可以处理总计 12Mb/s 的负载,USB 2.0 总线提速到 480 Mb/s,而 USB 3.0 能达到不小于 5Gb/s 的速率。
SCSI(Small Computer System Interface):
是一种高速总线,用在高速硬盘、扫描仪和其他需要较大带宽的设备上。主要用在服务器和工作站中,速度可以达到 640MB/s。
2.2.7. 启动计算机
BIOS:
基本输入输出系统(Basic Input Output System,BIOS)。
在 BIOS 内有底层 I/O 软件,包括读键盘、写屏幕、进行磁盘 IO 以及其他过程。
现在这个程序存放在一块闪速 RAM 中,它是非易失性的,但是在发现 BIOS 中有错时可以通过操作系统对它进行更新。
BIOS 的运行过程:
在计算机启动时,BIOS 开始运行。
- 首先检查所安装的 RAM 数量,键盘和其他基本设备是否已安装并正常响应。
- 接着,开始扫描 PCIe 和 PCI 总线并找出连在上面的所有设备。
也会记录即插即用设备。如果现有的设备和系统上一次启动时的设备不同,则新的设备将被配置。
- 根据存储在 CMOS 存储器中的设备清单决定启动设备。用户可以在系统刚启动之后进入一个 BIOS 配置程序,对设备清单进行修改。
如果存在 CD-ROM(有时是 USB),则系统试图从中启动,如果失败,系统将从硬盘启动。
- 启动设备上的第一个扇区,被读入内存并执行。这个扇区中包含一个检查分区表的程序,以确定哪个分区是活动的。
- 然后,从该分区读入第二个启动装载模块。来自活动分区的这个装载模块被读入操作系统,并启动。
- 然后,操作系统询问 BIOS,以获得配置信息。系统检查每个设备对应的设备驱动程序是否存在。如果没有,系统要求用户插入含有该设备驱动程序的 CD-ROM。
- 一旦有了全部的设备驱动程序,操作系统就将它们调入内核。然后初始化有关表格,创建需要的任何背景进程,并在每个终端上启动登录程序或 GUI。
即插即用(plug and play):
每块 I/O 卡有一个固定的中断请求级别和用于其 I/O 寄存器的固定地址。
例如,键盘的中断级别是 1,并使用 0x60 至 0x64 的 I/O 地址,
软盘控制器是中断 6 级并使用 Ox3F0 至 0x3F7 的 I/O 地址,
而打印机是中断 7 级并使用 0x378 至 0x37A 的 I/O 地址等。
如果有一块声卡和调制解调卡,都是使用中断 4,它们就会冲突。必须得在每块 I/O 卡上提供 DIP 开关或跳接器,并指导用户对其进行设置去选择中断级别和 I/O 地址才能解决冲突。
即插即用让系统能自动地收集有关 I/O 设备的信息,集中赋予中断级别和 I/O 地址,然后通知每块卡所使用的数值。计算机启动时 BIOS 会记录所有的设备,如果现有的设备和系统上一次启动时的设备不同,则新的设备将被配置。
3. 系统相关
3.1. 文件系统
进程树和文件树的区别:
- 一般进程的树状结构层次不深(很少超过三层),而文件树状结构的层次常常多达四层、五层或更多层。
- 进程树层次结构是暂时的,通常最多存在几分钟,而目录层次则可能存在数年之久。
- 所有权及保护:只有父进程能控制和访问子进程,而在文件和目录能使其他用户也可以访问。
文件描述符:
在读写文件之前,首先要打开文件,检查其访问权限。若权限许可,系统将返回一个小整数,称作 文件描述符(file descriptor),供后续操作使用。若禁止访问,系统则返回一个错误码。
安装文件系统:
UNIX 允许把光盘上的文件系统接到主文件树上。mount 系统调用允许把在 CD-ROM 上的文件系统连接到程序所希望的根文件系统上。
装配文件系统将使得装配目录中已有的任何文件都不可访问,因此装配点通常都是空的。
但是,系统管理人员可能需要将某些位于被装配目录中的非常重要的文件复制到装配点,使得他们在进行设备检查或修理时,可以在紧急事件中的普通路径上找到这些文件。
特殊文件:
提供特殊文件是为了使 I/O 设备看起来像文件一般。I/O 设备也可通过同样的系统调用进行读写。
按照惯例,特殊文件保存在 /dev
目录中。例如, /dev/lp
是打印机。
- 块特殊文件:指那些由可随机存取的块组成的设备,如磁盘等。比如打开一个块特殊文件,然后读第 4 块,程序可以直接访问设备的第 4 块而不必考虑存放该文件的文件系统结构。
- 字符特殊文件:用于打印机、调制解调器和其他接收或输出字符流的设备。
管道:
管道(pipe)是一种虚文件,它可连接两个进程。如果进程 A 和 B 希望通过管道对话,它们必须提前设置该管道。
当进程 A 想对进程 B 发送数据时,它把数据写到管道上,进程 B 可以通过读该管道而得到数据。这样,在 UNIX 中两个进程之间的通信就非常类似于普通文件的读写了。
若进程想发现它所写入的输出文件不是真正的文件而是管道,则需要使用特殊的系统调用。
4. 系统调用
read 系统调用:
它的调用由 C 程序完成,方法是调用一个与该系统调用名称相同的库过程 read。
1 | count = read(fd, buffer,nbytes); |
调用过程如下
4.1. 进程管理
进程管理 | |
---|---|
调用 | 说明 |
pid = fork() | 创建与父进程相同的子进程 |
pid = waitpid(pid, &statloc, options) | 等待一个子进程终止 |
s = execve(name, argv, environp) | execve () 系统调用的作用是运行另外一个指定的程序。它会把新程序加载到当前进程的内存空间内,当前的进程会被丢弃,它的堆、栈和所有的段数据都会被新进程相应的部分代替,然后会从新程序的初始化代码和 main 函数开始运行。同时,进程的 ID 将保持不变。 execve () 系统调用通常与 fork () 系统调用配合使用。从一个进程中启动另一个程序时,通常是先 fork () 一个子进程,然后在子进程中使用 execve () 变身为运行指定程序的进程。 |
exit(status) | 终止进程执行并返回状态 |
pid:进程的 id
fork:
1 | define TRUE 1 |
父进程从终端读取命令,创建一个子进程,等待该子进程执行命令。
- 父进程执行 waitpid 系统调用来等待子进程结束,直至子进程终止。
waitpid 参数:
- waitpid 可以等待一个特定的子进程,或者通过将第一个参数设为 -1 的方式,等待任何一个老的子进程。
- 在 waitpid 完成之后,将把第二个参数 statloc 所指向的地址设置为子进程的退出状态(正常或异常终止以及退出值)。
- 有各种可使用的选项,它们由第三个参数确定。例如,如果没有已经退出的子进程则立即返回。
- 子进程通过使用 execve 系统调用执行用户的命令。这个系统调用会引起其整个核心映像被一个文件所替代,该文件由第一个参数给定。
execve 参数:
- name:要执行的文件名称。如
cp
- argv:指向变量数组的指针。传入命令的参数
- environp:指向环境数组的指针
进程存储空间:
在 UNIX 中的进程将其存储空间划分为三段:正文段(如程序代码)、数据段(如变量)以及 堆栈段。数据向上增长而堆栈向下增长。
4.2. 文件管理
文件管理 | |
---|---|
调用 | 说明 |
fd = open(file, how, …) | 打开一个文件供读、写或两者 |
s = close(fd) | 关闭一个打开的文件 |
n = read(fd, buffer, bnytes) | 把数据从一个文件读到缓冲区中 |
n= write(fd, buffer, nbytes) | 把数据从缓冲区写到一个文件中 |
position = lseek(fd, offset, whence) | 移动文件指针 |
s = stat(name, &buf) | 取得文件的状态信息 |
fd:文件描述符
n:字节数
position:在文件中的偏移量
open:
使用 open 打开文件返回文件描述符,然后可使用返回的文件描述符进行读写操作。接着可以用 close 关闭文件。
lseek:
每个文件有一个指向文件当前位置的指针。在顺序读(写)时,该指针通常指向要读出(写入)的下一个字节。
lseek 调用可以改变该位置指针的值,这样后续的 read 或 write 调用就可以在文件的任何地方开始。
4.3. 目录管理
目录和文件系统管理 | |
---|---|
调用 | 说明 |
s = mkdir(name, mode) | 创建一个新目录 |
s = rmdir(name) | 删去一个空目录 |
s = link(name1, name2) | 创建 — 个新目录项 name2,并指向 name1 |
s = unlink(name) | 删去一个目录项 |
s = mount(special, name, flag) | 安装一个文件系统 |
s = umount(special) | 卸载一个文件系统 |
link:
允许同一个文件以两个或多个名称出现
在 UNIX 中,每个文件都有唯一的编号,即 i - 编号,用以标识文件。该 i - 编号是对 i - 节点表格的一个引用,它们一一对应,说明该文件的拥有者、磁盘块的位置等。
目录就是一个包含了(i - 编号,ASCII 名称)集合的文件。link 所做的只是利用某个已有文件的 i - 编号,创建一个新目录项(也许用一个新名称)。
上图两个目录项有相同的 i - 编号(70),从而指向同一个文件。如果使用 unlink 系统调用将其中一个文件移走了,可以保留另一个。
如果两个都被移走了,UNIX 00 看到尚且存在的文件没有目录项,就会把该文件从磁盘中移去。
4.4. 其他
杂项 | |
---|---|
调用 | 说明 |
s = chdir(dirname) | 改变工作目录 |
s = chmod(name, mode) | 修改一个文件的保护位 |
s = kill(pid, signal) | 发送信号给一个进程 |
seconds =time(&seconds) | 自 1970 年 1 月 1 日起的流逝时间 |
seconds:流逝时间
5. 操作系统结构
5.1. 策略和机制
策略表示要做什么,机制表示该怎么做。
有时会出现一个进程有多个子进程,每个子进程可能实现不同的功能(计算分析,访问磁盘等),并具有不同的优先级。这就要求调度程序需要从用户进程中获取调度决策信息。
将调度算法以某种形式参数化,而参数可以由用户进程填写。这样便使得策略和机制分离,算法由底层实现,而用户进程可以设置参数来对其进行调整。
假设内核使用优先级调度算法,并提供一条可供进程设置优先级的系统调用,尽管父进程本身并不参与调度,但它可以控制如何调度子进程的细节。
5.2. 内核结构
5.2.1. 简要结构(单体)
整个操作系统在内核态以单一程序的方式运行。整个操作系统以过程集合的方式编写,链接成一个大型可执行二进制程序。
使用这种技术,系统中每个过程可以自由调用其他过程,只要后者提供了前者所需要的一些有用的计算工作。调用任何一个你所需要的过程或许会非常高效。
但上千个可以不受限制地彼此调用的过程常常导致系统笨拙且难于理解。并且,任何一个过程的崩溃都会连累整个系统。
结构:
对于这类操作系统的基本结构,需要如下结构:
- 需要一个主程序,用来处理服务过程请求。
- 需要一套服务过程,用来执行系统调用。
- 需要一套实用过程,用来辅助服务过程。
每一个系统调用都通过一个服务过程为其工作并运行之。要有一组实用程序来完成一些服务过程所需要用到的功能,如从用户程序取数据等。
5.2.2. 宏内核
THE 操作系统结构,底层保证基础功能,上层依赖底层
注:让我想起了七层网络模型
5.2.3. 微内核
在宏内核架构下,所有内核模块均运行在特权空间,一个单点的错误就可能会导致整个系统崩溃或者被攻破。
为了实现高可靠性,将操作系统划分成小的、良好定义的模块,只有微内核运行在内核态,其余的模块由于功能相对弱些,则作为普通用户进程运行。
优点:
由于把每个设备驱动和文件系统分别作为普通用户进程,这些模块中的错误虽然会使这些模块崩溃,但是不会使得整个系统死机。所以,音频驱动中的错误会使声音断续或停止,但是不会使整个计算机垮掉。
使用场景:
通常桌面操作系统并不使用微内核。微内核在实时、工业、航空以及军事应用中特别流行,这些领域都是关键任务,需要有高度的可靠性。
5.2.4. 客户端 - 服务器模式
客户端 - 服务器模式将进程划分为两类
- 服务器:每个服务器提供某种服务
- 客户端:使用这些服务。
通常,在系统最底层是微内核,但并不是必须这样。客户端 - 服务器模式的本质是存在客户端进程和服务器进程。
消息通信:
客户端和服务器之间的通信是消息传递。为了获得一个服务,客户端进程构造段消息,并将其发给合适的服务器。该服务器完成工作,发送回应。
一个普遍方式是运行在不同计算机上的客户端和服务器,通过局域网或广域网连接。
其内部细节对客户端来说是屏蔽的。所以,客户端 - 服务器模式是一种可以应用在单机或者网络机器上的抽象。
5.2.5. 虚拟机
虚拟机监控程序:
VM/370 系统
这个系统的核心被称为 虚拟机监控程序(virtual machine monitor),它在裸机上运行并且具备了多道程序功能
该系统向上层提供了若干台虚拟机。每台虚拟机都与裸机相同,所以不同的虛拟机可以运行不同的操作系统。
CMS:
在早期的 VM/370 系统上,有一些系统运行 OS/360 或者其他大型批处理或事务处理操作系统,而另一些虚拟机运行单用户、交互式系统供分时用户使用,这个系统称为 会话监控系统(Conversational Monitor System,CMS)。
系统调用:
当一个 CMS 程序执行系统调用时,该调用被陷入到其虚拟机的操作系统上。
CMS 然后发出硬件 I/O 指令读出虛拟磁盘或其他需要执行的调用。这些 I/O 指令由 VM/370 陷入并完成指令。通过对多道程序功能和提供扩展机器二者的完全分离,每个部分都变得非常简单、非常灵活且容易维护。
第一类与第二类虚拟机管理程序:
区别:
第二类虚拟机管理程序利用 宿主操作系统(host operatingsystem)并通过其文件系统创建进程、存储文件等。它从 CD-ROM 安装盘中读入供选择的 客户操作系统(guestoperating system),并安装在一个虚拟盘上,该盘实际上只是宿主操作系统的文件系统中的一个大文件。
第一类虚拟机管理程序没有底层(宿主操作系统)支持,所以必须在原始的硬盘分区上自行管理储存。
5.2.6. 外壳
与虚拟机克隆真实机器不同,另一种策略是对机器进行分区,即给每个用户整个资源的一个子集。
外核的任务是为虚拟机分配资源,确保没有机器会使用他人的资源。每个用户层的虚拟机可以运行自己的操作系统。