目录
1 计算机硬件
1.1 计算机体系结构
计算机的多种设备都是通过系统总线 (system bus) 连接在一起,这样就构成了一个基本的计算机系统,如下图,可以发现图中有很多的控制器 (controller),事实上每个设备都对应着一个控制器 (controller)。
在这样的体系结构下,有如下特征:
- I/O 设备与 CPU 可并行运行;
- 每一设备控制器负责一个设备类型;
- 每一设备控制器有一局部缓存 (local buffer);
- CPU 通过局部缓存与主存交换数据;
- I/O 从设备到设备控制器有局部缓存;
- 设备控制器通过引起中断 (interrupt) 通知 CPU 操作已完成。
1.2 中断机制
中断指的是 CPU 在执行程序的时候出现了某些异常突发情况,需要紧急处理,CPU 必须暂停当前的任务去处理紧急突发事件,处理完之后又返回原程序被打断的地方去继续执行,中断通常分为以下两种:
- 硬件中断 (hardware interrupt):设备控制器通知 CPU 它所做的操作已经完成,会触发一个中断;
- 软件中断 (software interrupt):一种是异常,指的是系统在执行过程中出现的错误,如除 0 0 0 操作或无效的内存访问,另一种是系统调用 (system call)。
为什么需要中断呢?为什么有了中断后就能实现多道呢?如下图,用户程序一开始是在 CPU 上执行的,当执行到某个时间点的时候(图中横轴 transfer done
)会触发一个中断,CPU 在延迟一点时间后会收到这个中断,收到中断后会去处理这个中断,也就是会从高电平的 user process executing
跳到低电平 I/O interrupt processing
,中断处理完成后又会回到原来的用户程序继续执行,有了这样的中断机制带来的好处是在 CPU 执行的过程中,I/O 设备也在执行,能够使系统更高效,响应性更好
为什么说有了通道技术和中断机制后才真正地实现了多道?
- 通道是一种控制外部设备的硬件结构,它独立于 CPU 运行,因此 I/O 操作能和 CPU 并行运行,但以前CPU 依然要发送指令询问通道是否完成工作,若未完成,CPU 则要一直询问直到通道工作完成,虽然引入通道技术提高了效率,但是并未实现真正的多道并行;
- 中断和通道结合起来就实现了多道,CPU 启动通道传输数据后便去执行其他程序的计算工作,而通道则进行输入输出操作;当通道工作结束时,通过中断机构向 CPU 发出中断请求,CPU 则暂停正在执行的操作,对出现的中断进行处理,处理完后则继续原来的工作,这样,就真正做到了 CPU 与 I/O 设备并行工作。
现代操作系统是中断驱动的,中断将控制权转移到中断服务程序,所谓中断服务程序就是中断出现后要去执行处理的那一段程序代码,实现控制权转移的方法如下:
- 在中断服务程序中有单独的一段代码,来确定当前中断属于哪种类型的中断;
- 会有一个通用的历程去检查中断信息,当中断发生时,就会调用中断服务程序;
- 当检查到中断时,要求能快速处理,这里的实现方法是利用中断向量 (interrupt vector),中断向量就存储了服务历程的地址。
下面的表列出了常见的中断向量,中断号及其功能:
中断向量 | 中断号 | 中断功能 |
---|---|---|
00~03 | 0 | 除法溢出中断 |
04~07 | 1 | 单步 (用于DEBUG) |
08~0B | 2 | 非屏蔽中断 (NMI) |
0C~0F | 3 | 断点中断 (用于DEBUG) |
10~13 | 4 | 溢出中断 |
14~17 | 5 | 打印屏幕 |
18~1F | 6,7 | 保留 |
1.3 I/O操作
使用 I/O 操作需要具备以下条件:
- 设备与设备控制器相连;
- 本地缓冲器,一组寄存器;
- 设备驱动程序。
有两种常见的 I/O 操作:
- 同步 (Synchronous):当启动 I/O 操作时,直到 I/O 操作结束后,控制权才会返回到用户程序,也就是说你运行了一个程序,但突然触发了 I/O,那么你的程序要等待这次 I/O 操作结束后,才会运行;
- 异步 (Asynchronous):当启动 I/O 操作时,控制权会立马转到用户程序,那么此时 I/O 操作是否运行结束是通过中断机制来实现的。
下图是同步和异步的比较:
2 硬件保护
当计算机执行过程中,计算机硬件需要提供一些支持能够保证计算机能够正确的运行,在早期的操作系统中为单用户系统,程序员可完全控制系统,在后来的批处理操作系统中,通过读取卡片来录入程序和数据,此时有可能会把其他程序当作当前程序的数据输入进去了,在这个时候就需要提供一些保护,而后的多道批处理系统就更为复杂,它运行多个程序并发执行,多个程序竞争某些资源,当一个程序在执行过程中,它有可能会修改到其他程序的代码或数据,甚至可能会修改操作系统,这时为了能够让计算机正确执行,必须提供一些保护。
那么解决的方法就是当程序在执行非法指令或访问不属于自己的地址空间内存时把控制权交给操作系统,甚至情况严重时可以直接终止程序。
2.1 实现保护两状态操作
共享系统资源要求操作系统确保当前程序不会引起其他程序的运行错误,我们的方法是两状态操作,即至少在两个运行状态之间提供硬件支持:
- 用户态 (User mode):代表用户执行;
- 管态,特权模式或系统模式 (Monitor mode):代表操作系统执行。
那么计算机是如何区分这两种状态呢?在计算机中实现的方法很简单,只需要一个位的 0
和 1
就可以区分,这个位叫做模式位 (mode bit) ,表示当前模式 monitor (0) or user (1)
,这个模式位可以放在 PSW
中(PSW 是 Program Status Word 的缩写,即程序状态字),当系统引导启动时,硬件处于管态,在用户模式下执行用户进程,如下图:
若在用户程序中出现了问题,就会触发中断,出现中断或陷阱,硬件切换到管态,一旦切换到管态,控制权就转交给了操作系统,由操作系统来处理这些中断错误信息,那么操作系统如何知道用户程序执行了非法操作呢?在操作系统中把只能由管态执行的指令称为特权指令 (Privileged instructions),若用户程序执行到了特权指令,那么就可判断当前操作为非法操作,可能会引发错误,但是有时候用户程序要执行特权指令怎么办?操作系统中提供了系统调用 (system call) 方式,可以让用户程序合法的使用特权指令,系统调用实际上会触发软中断,那么就会从用户态切换到了管态,控制权也转交给了操作系统。在处于管态下,特权指令是可以直接执行的。
使用这种方法,也可以对所有的 I/O 操作进行保护,我们把所有的 I/O 操作定义为特权指令,用户不能直接用 I/O 指令,必须通过系统调用,确保用户程序不能在管态下控制计算机,下图是系统调用执行 I/O 操作的过程:
既然系统调用是通过软中断来实现的,那么也要保护中断机制不能被破坏,所以必须保护中断向量和中断服务程序,而程序都是在内存中,所以问题也转换为了对某些内存的保护,因此要划分进程能够运行的合法空间,划分合法空间用到了两个寄存器,通俗来讲这两个寄存器就是来划分合法空间地址的起点和空间的大小,有了这两个值,那么就唯一确定了这一块内存空间:
- 基址寄存器 (base register):指出起始地址;
- 界限寄存器 (limit register):指出空间大小。
如下图的 job2
就被两个寄存器唯一确定了:
在具体实现时,CPU每得到一个地址,都需要去检测该地址的合法性,流程图如下:
2.2 CPU保护
需防止用户程序陷入死循环或者不调用系统服务且不将控制权返回到操作系统,解决的方法就是使用定时器 (timer),也就是说当从管态切换到用户态时,设置了一个定时器,当定时器时间到的时候就会触发一个中断,那么控制权就会转交给操作系统,操作系统又重新获得了控制权。
3 操作系统服务
操作系统是覆盖在计算机硬件系统上的第一层软件,对于这个复杂的软件系统,必须清楚其设计的目标是什么,应该提供哪些服务,通常会考虑以下三个方面:
- 提供的服务 (services it provides);
- 为用户和程序提供的接口 (interface to users and programmers);
- 各组成部分及其相互连接 (components and their interconnections)。
3.1 提供的服务
针对用户要提供的服务:
- 用户接口 (User interface):通过这些接口,用户能够访问到操作系统提供的功能,几乎所有的操作系统都有用户接口,常见的表现形式分为命令行 Command-Line (CLI) 和 图形用户界面 Graphics User Interface (GUI);
- 执行程序 (Program execution):能够把程序调入内存,并转交给 CPU 处理的能力;
- I/O操作 (I/O operations):由于用户程序不能直接执行 I/O 操作,操作系统必须提供手段完成 I/O 操作;
- 文件系统操作 (File-system manipulation):读、写、创建和删除文件的能力;
- 通信 (Communications):运行的进程在同一计算机或由网络连接的不同系统中交换信息。通过共享存储器或消息传递实现;
- 错误检测 (Error detection):探测在 CPU 与内存硬件中,在 I/O 设备中,或在用户程序中的错误,确保正确运算。
针对提高系统效率要提供的服务:
- 资源分配 (Resource allocation):把资源分配给多个用户或多个同时运行的作业;
- 帐务 (Accounting):跟踪和记录用户对资源的使用,用于帐单和统计哪些资源已经分配出去了,哪些资源是可用的等等;
- 保护 (Protection):确保对资源的所有访问均在控制中。
下图是整个操作系统提供的服务结构图:
4 系统调用
根据上面的服务结构图可以找到 system calls
,他处在的位置是操作系统众多服务之上,用户接口之下,它的功能就是给用户提供方法来使用系统服务,系统调用提供在运行程序和操作系统之间的接口,系统调用由于接近底层,不方便使用 ,并且不同的操作系统的系统调用使用都有差别,所以实际上大多数程序员在开发时都是直接使用 API ( level Application Program Interface),API 实际上就是系统调用的封装,里面可能封装了一个或多个系统调用,常见的系统 API 有 Win32 API for Windows,Java API for the Java virtual machine (JVM) 等等。
4.1 系统调用的处理过程
系统调用的处理过程如下:
- 当用户使用系统调用时,产生一条相应的指令;
- CPU 在执行到该指令时发生中断,发出有关的信号给陷入处理机构;
- 处理机构在收到了 CPU 发来的信号后,启动相关的处理程序去完成该系统调用所要求的功能;
- 在处理系统调用之前,陷入处理机构还需保存处理机现场(PSW、PC、系统调用号、用户栈指针、通用寄存器、用户定义的参数等)。
不同的系统调用对应着不同的子程序代码段,我们通过入口地址表,使每个入口地址与相应的系统程序对应,陷入处理程序用系统调用功能号查找入口地址表,得到该系统程序的入口地址,并执行之,系统调用处理结束后,要恢复处理机现场,从而用户程序可以继续执行,过程如下图所示:
4.2 系统调用传递参数的方式
在系统调用时,难免需要传递一些参数来实现特定的功能,有三种常用方式用于在运行程序和操作系统之间的参数传递:
- 寄存器中的参数传递,寄存器容量较小,故只适用于少量且小的参数传递;
- 参数存在内存的一张表中,表地址作为寄存器的参数传递,如下图所示,若传递的参数比较大的时候,先把参数放到内存里,这些参数在内存中的地址就放在寄存器 (register) 中,当使用系统调用时就会查找寄存器然后取出地址再转到内存中去寻找参数:
- 程序把参数压入栈,由操作系统弹出。
4.3 系统调用的分类
系统调用的分类如下:
- 进程控制 (process control);
- 文件管理 (file management);
- 设备管理 (device management);
- 信息维护 (information maintenance );
- 通信 (communications)。
5 操作系统结构
这一节主要讨论的问题是操作系统中各个组件之间的关系,操作系统的早期非常简单,如 MS-DOS 以最小的空间提供最多的功能,它并不划分模块。
在 MS-DOS 中,应用程序可直接访问 BIOS 例程,来直接操纵设备,当然这受限于当时的硬件,Intel8088 没提供双模式和硬件保护,这使得 DOS 别无选择只能任由应用程序访问 BIOS,如下图所示:
而在 UNIX 中,受硬件功能限制,早期 UNIX 只是有限的结构化。UNIX包括2个分离的部分:
- 系统程序 (Systems programs );
- 内核 (The kernel):包括了在物理硬件之上,系统调用之下的一切。提供文件系统, CPU调度,存储管理,和其他操作系统功能 ;每一层有大量的功能,如下图所示:
5.1 层次化系统结构
操作系统划分为若干层,在低层上构建高层。底层(
0
0
0 层)为硬件,最高层(
N
N
N 层)为用户层,在设计时考虑模块化,层的选择是每层只使用低层次的功能和服务,由此分层的基本原则是每一层都使用其底层所提供的功能和服务,以便于系统调试和验证,如下图所示:
最早使用层次化操作系统的是 THE 操作系统,它有如下六层:
分层有如下优点:
- 低层和高层可分别实现(便于扩充);
- 高层错误不会影响到低层,便于调试、利于功能的增删改;
- 调用关系清晰(高层对低层单向依赖),避免递归调用,有利于保证设计和实现的正确性。
分层有如下缺点:
- 系统中所有进程的控制转移、通讯等任务全部交给系统的核心去管理,要花费一定的代价。
5.2 微内核
微内核 (Microkernels) 对层次进行进一步的划分,通过划分系统程序和用户程序,把所有不必要的部件移出内核,形成一个小内核,微内核提供最少量的进程管理、存储管理,以及通信功能。
微内核操作系统由两大部分组成:
- 运行在核心态的内核,即保留下来的核心功能;
- 运行在用户态并以 C/S 方式运行的进程层,即移出去的不必要功能。
移出去的功能通过一种 Server 运行,如下图所示:
微内核与传统操作系统相比,有如下特点:
- 内核精巧:通常内核只由任务管理、虚存管理和进程间通信 3 3 3 个部分组成。传统操作系统内核中的许多部分都被移出内核,采取服务器方式实现;
- 面向多处理机和分布式系统:基于微内核的操作系统,在内核中引入了多处理机调度和管理机制,并引入了细粒度并发机制,即线程,使得多个处理机可以在同一个任务中并行地执行;
- 基于客户/服务器体系结构:在微内核结构的操作系统中,任务间通信机制,消息机制是系统的基础,操作系统的各种功能都以服务器方式实现,向用户提供服务。用户对服务器的请求是以消息传递的方式传给服务器的。