操作系统学习笔记(二)操作系统的运行环境和体系结构

继续上次的总结,这次来讲一下,操作系统的运行环境和体系结构。

操作系统的运行环境

操作系统运行机制

计算机系统中,通常CPU执行两种不同性质的程序,一种是操作系统内核程序,另一种是用户自编程序(即系统外层的应用程序,又称应用程序)。

对操作系统而言,这两种程序作用不同,前者是后者的管理者,因此管理程序要执行一些特权指令,而后者处于安全考虑则不能执行这些指令。

所谓特权指令,是指计算机中不允许用户直接使用的指令,如I/O指令,置中断指令,存取用于内存保护的寄存器,送程序状态字到程序状态字寄存器等的指令。

具体实现上,将CPU的状态划分为用户态(目态)和核心态(管态,内核态)

注意,用户态和核心态是CPU的状态,是CPU处于核心态时可以运行操作系统内核程序的特权指令,可以理解为CPU内部有个开关,开关为1时,CPU处于核心态,可以执行特权指令,为0时则不可以。

操作系统的内核分为两个部分:

  • 一些与硬件紧密相关的模块,如时钟管理,中断处理,设备驱动处于底层。
  • 其次是运行频率较高的程序,如进程管理,存储器管理和设备管理。

不同系统对内核的定义稍有区别,大致可以分为四种

1. 时钟管理

在计算机各种部件中,时钟是最关键的设备。

时钟的第一功能是计时,向用户提供准确的系统时间。

另外,通过时钟中断的处理,可以实现进程切换。例如,在分时操作系统中采取时间片轮转调度,在实时系统中按截止时间控制运行,在批处理中通过时钟管理来衡量一个作业的运行程度。

2. 中断机制

引入中断的初衷是提高多道程序运行环境中的CPU利用率,而且主要针对外部设备。

后来逐渐发展,形成了多种类型,成为操作系统各项操作的基础。例如鼠标或者键盘的信息输入,进程的管理和调度,系统功能的调用,设备驱动,文件访问等,无不依赖中断机制,可以说,现代操作系统是靠中断驱动的软件

中断机制,只有一小部分属于内核,它们负责保护和恢复中断现场,转移控制权到相关的处理程序等,这样可以减少中断的处理时间,提高系统并行处理的能力。

中断,顾名思义,是暂停某些东西的运行,它不仅仅是异常导致的,如A的I/O完成后的中断,暂停当前CPU中B程序的执行。

3. 原语

操作系统底层可被调用的公用的小程序,它们有以下特点:

  • 操作系统最底层,最接近硬件的部分。
  • 具有原子性,操作只能一气呵成。
  • 运行时间短,且调用频繁。

定义原语的直接方法是,关闭中断(也就是禁止其他中断),然所有动作不可分割地完成后再打开终端。

系统中的设备驱动,CPU切换,进程通信等功能中的部分操作都可以定义为原语。

也就是说,原语是属于操作系统的,它的实现和保证是软件层次的。

4. 系统控制的数据结构和处理

系统中用来登记状态信息的数据结构很多,如作业控制块,进程控制块(PCB),设备控制块,链表,消息队列,缓冲区,空闲区内存登记表等。为了实现有效的管理,系统需要一些基本的操作,如:

  • 进程管理:进程状态管理,进程调度和分派,创建与撤销进程控制块等。
  • 存储器管理:存储器空间的分配和回收,内存信息保护程序,代码对换程序。
  • 设备管理:缓冲区管理,设备分配和回收。

中断和异常

系统不允许用户程序实现核心态的功能,但它们又必须使用这些功能。因此需要在核心态上提供一些“门”,以便实现从用户态到核心态。

在实际操作系统中,CPU运行上层程序时,唯一能够进入这些门的途径就是中断或者异常,一旦发生中断或异常,运行用户态的CPU会立即进入核心态,这是通过硬件实现的

操作系统发展的历程大体上就是一个想方设法提高资源利用率的过程,而提高资源利用率,就需要在程序并未使用某种资源时,把它对那种资源的占有权释放,这就需要中断。

中断和异常的定义

中断,又称外中断,指的是来自CPU当前执行指令以外的事件发生,如设备发出的I/O结束中断,表示设备的输入输出已经完成,希望处理机能够向设备发出下一个输入输出指令,并然完成输入输出后的程序继续执行。时钟中断,表示一个固定的时间片已到,让处理机处理计时,启动定时任务等任务。

异常,又称内中断,例外或者陷入(trap),指的是来自CPU正在执行的指令内部的事件,如地址越界,算术溢出,内存缺页等。对异常的处理一般依赖当前程序的运行现场,且异常不能被屏蔽,一旦出现应立即处理。

中断处理过程

不同计算机的中断(这里指外中断)的处理过程各具特色,但是大概相同:

  1. 关中断。CPU响应中断后,首先要保护程序的现场,在保护现场过程中,CPU不能响应其他的中断,否则现场就无法保存完整。
  2. 保存断点。为保证中断服务程序执行完毕后能够正确返回原来的程序,必须将原来程序的端点(程序计数器PC)保存。(注意这一步由硬件自动完成)
  3. 中断服务程序寻址。实质是找到中断服务程序的入口,送入程序计数器,这个入口地址又叫做中断向量。
  4. 保存现场和屏蔽字。进入中断服务程序后,首先要保存现场,现场信息一般指的是程序状态字寄存器PSWR和某些通用寄存器(由操作系统)。
  5. 开中断。允许更高级别的中断请求得到相应。
  6. 执行中断服务程序。这是中断的目的。但是注意,此时已经开中短了,也就是说,这里是可以被打断的。
  7. 关中断。保证恢复现场和屏蔽字时不被中断。
  8. 恢复现场和屏蔽字。将现场和屏蔽字恢复到原来状态。
  9. 开中断,中断返回。返回源程序的断点处。

这个过程中有几点需要注意。

在执行中断服务程序之前和之后分别有一个原语,但是中断服务程序本身不是整个在原语中,所以理论上是可以被打断的。如果中断本身又被中断,那就需要一个栈来层层保存现场。

但是注意这个栈与程序内部函数的调用栈不同,程序内部函数调用栈由程序自己模拟并管理。

中断因为涉及程序计数器的保存等操作,所以一定会陷入内核态。

中断的目的是通过一系列操作去打断CPU当前正在执行的程序并转去执行中断服务程序,而原语的目的则是有的指令不可以被打断。而中断处理过程中至少是包含两个原语的,也就是说,中断处理的流程中,本身就至少有两个不可被中断的原语。

系统调用

所谓系统调用,是指用户在程序中调用系统提供的一些子功能,系统调用可以视为特殊的公共子程序。

系统中的各种共享资源都由操作系统统一掌管,因此在用户程序中,凡是与资源相关的操作,都必须通过系统调用的方式提出服务请求,由操作系统代为完成。

注意上篇博客的内容:程序接口由一系列系统调用组成。

系统调用按功能分为几类:

  • 设备管理
  • 文件管理
  • 进程控制
  • 进程通信
  • 内存管理

系统调用相关功能涉及系统资源管理,进程管理之类,对整个操作系统影响较大,需要运行在核心态。用户可以执行陷入指令,法器系统调用

用户执行陷入指令,相当于把CPU的使用权主动交给操作系统内核,之后内核程序对系统调用做出相关处理,完成后再将CPU使用权还给用户程序。