操作系统基础原理
计算机自身是由众多电子元器件构成,硬件本身提供给用户的接口十分底层复杂,使用很不方便。在硬件之上的操作系统将硬件接口抽象封装为比较直观,用户容易调用的接口;用户开发应用程序,通过指令代码调用这些接口完成任务。
狭义的操作系统主要指系统内核,内核有以下作用:进程管理、文件系统、网络管理、内存管理、驱动程序、安全功能。内核可以将用户无法操作的底层硬件接口进行抽象并封装为用户可以操作的接口,称为系统调用(system call),当用户需要操作硬件时需要向内核发起系统调用完成相应操作。
shell解释器是运行在操作系统上的一个特殊的应用程序,它提供了人机交互接口,用户通过shell向操作系统发出各种命令,而shell解释器又可以将用户输入的命令翻译成操作系统能够理解的指令交给CPU执行。
最高层是运行在系统上的各种应用程序,由程序员使用各种编程语言开发,例如C、Java、JavaScript、PHP、C++等。应用程序体现了用户的真实目的,才能完成用户想做的事情。
总之从整个计算机系统看,越高级就越抽象,越接近用户的最终目的;越底层就越具体,越接近硬件的真实面目。
用户态与内核态
用户开发的应用程序都是工作在操作系统之上的,不属于操作系统内部。系统内核之上的空间称为用户空间(用户态),内核自身称为内核空间(内核态)。不论用户程序还是内核指令,执行时加载到CPU然后运行。CPU在生产过程中,研制人员开发了CPU能够执行的众多指令,这些CPU支持的所有指令的集合称为CPU的指令集。CPU的指令主要分为4个层次,即环0、环1、环2、环3。以Intel的X86指令架构CPU为例,主要使用环0和环3两个层次,环3上是用户可以执行的指令;环0上为特权指令,用户不能直接操作。例如操作硬件,这是个特权操作,用户不可以执行,必须向内核申请,即发起系统调用,由内核执行,完成后将结果返回给用户程序。对于计算机的所有特权操作都必须由内核承担,内核最重要的一个功能就是管理硬件资源。
程序员编写的代码其实就是一条条指令构成,程序代码在执行过程中,如果这条指令用户自身有权限去执行,则可以直接执行。如果需要执行特权指令,只能由内核执行,用户没有权限执行;此时要向内核发起系统调用,内核执行系统调用的代码,完成后将执行结果返回给执行的程序,然后再继续执行后面的指令。 程序执行遇到特权指令,必须发起系统调用,内核在运行系统调用代码时,程序是处在等待状态。执行系统调用时,程序工作在内核空间(内核态);运行用户可以执行的指令时,程序工作在用户空间(用户态)。
应用程序在工作过程中,就是不断在用户态和内核态之间做模式切换,需要执行特权命令就发起系统调用,陷入内核态,当内核执行系统调用完毕后再返回用户态。所以内核或者系统调用并不直接发挥生产力,它更多是在底层提供支撑,帮助用户完成其特定功能,只有用户自己的程序才具有生产力,才能真正实现用户自己的目标。 一个有效率的程序,它不应该浪费太多时间在系统调用。一般CPU应该至少有70%的时间在执行用户代码(即工作在用户态),不多于30%的时间用来执行系统调用(工作在内核态)。
保护现场与恢复现场
CPU是通过给不同的程序分配时间片(time slice)来完成多任务运行,给每一个程序分配独立的时间片。在执行过程中,很产生很多中间状态数据,例如执行到第几条指令,接下来CPU该去取第几条指令,这些数据存放在CPU的指令指针寄存器中。如果此时发生了进程切换,寄存器的数据就会被新的进程所覆盖,等到下次再执行相同程序时又得从头再来,这是所不能接受的。所以一旦程序在一个时间片内没有办法执行完毕,CPU需要把程序执行的中间状态的数据保存起来,例如当前运行到哪个指令,在内存中取数据取到哪个地址,这称为保存现场。保存完成后,在下一个时间片执行另一个进程。当重新恢复执行当前进程时,需要把保存的中间数据装载到CPU中,称为恢复现场。保存和恢复现场需要执行内核代码完成(即工作在内核空间,所以也会消耗CPU时间)。