【梳理】简明操作系统原理 第二章 过程、系统调用、陷阱指令和中断(内含文档高清截图)

参考教材:
Operating Systems: Three Easy Pieces
Remzi H. Arpaci-Dusseau and Andrea C. Arpaci-Dusseau
在线阅读:
http://pages.cs.wisc.edu/~remzi/OSTEP/
University of Wisconsin Madison 教授 Remzi Arpaci-Dusseau 认为课本应该是免费的
————————————————————————————————————————
这是专业必修课《操作系统原理》的复习指引。
在本文的最后附有复习指导的高清截图。需要掌握的概念在文档截图中以蓝色标识,并用可读性更好的字体显示 Linux 命令和代码。代码部分语法高亮。

二 过程、系统调用、陷阱指令和中断

1、在操作系统中,控制是很有必要的:系统不受控制会导致进程无限期运行,或访问本不允许访问的信息。我们需要高效的控制,不能让控制本身耗费过多的资源。操作系统在进行任务调度的时候,往往利用硬件支持来降低开销。

2、过程(procedure)是一个代码段,用于执行特定的任务。过程与函数(function)非常接近,有的编程语言统称为函数,并将过程视为函数的一种特殊情形。一般而言,两者的区别是:函数具有返回值(return value),而过程没有。
使用函数和过程的原因主要有二:一是在编程中总是会遇到需要大量重复执行相同代码的情况。把这部分代码写成一个过程,就不用在每一个需要用到这些代码的地方都把这些代码粘贴一遍。函数与过程的引入大大增加了代码的可读性和可维护性,而且可以避免在不使用函数和过程且需要修改实现这个功能的代码时,只修改了一部分而漏掉其它需要一并修改的位置的情况。二是这将程序变得模块化,使得程序更有条理、目的更清晰。如果你的能力不错,你可以自己编写函数和过程,并集成到一个库(library)中,使其它程序可以调用这些函数和过程。

3、中断(interrupt)是指CPU接收到来自硬件或软件的信号,提示发生了某个事件,应该被注意,这种情况就称为中断。通常,在接收到来自外围(CPU、内存以外)硬件的异步信号或软件的同步信号之后,CPU将会进行相应的硬件/软件处理。发出这样的信号称为进行中断请求(interrupt request,IRQ)。硬件中断导致处理器通过上下文切换(context switch)来保存执行状态(以程序计数器和程序状态字等寄存器信息为主);软件中断则通常作为CPU指令集中的一个指令,以可编程的方式直接指示这种执行资讯切换,并将处理导向一段中断处理代码。中断在计算机多任务处理,尤其是即时系统中尤为有用。这样的系统,包括运行于其上的操作系统,也被称为“中断驱动的”(interrupt-driven)。
中断是用以提高计算机工作效率、增强计算机功能的一项重要技术。最初引入硬件中断,只是出于性能上的考量。如果计算机系统没有中断,则处理器与外部设备通信时,它必须在向该设备发出指令后进行忙等待(Busy waiting),反复轮询该设备是否完成了动作并返回结果。这就造成了大量处理器周期被浪费。引入中断以后,当处理器发出设备请求后就可以立即返回以处理其他任务,而当设备完成动作后,发送中断信号给处理器,后者就可以再回过头获取处理结果。这样,在设备进行处理的周期内,处理器可以执行其他一些有意义的工作,而只付出一些很小的切换所引发的时间代价。后来被用于CPU外部与内部紧急事件的处理、机器故障的处理、时间控制等多个方面,并产生通过软件方式进入中断处理(软中断)的概念。在硬件实现上,中断可以是一个包含控制线路的独立系统,也可以被整合进存储器子系统中。

4、陷阱指令(trap instruction)是由 用户程序或错误 生成的软件中断,当操作系统需要执行系统调用或某些操作时产生。陷阱指令将CPU从用户态切换(进入)至内核态。用户模式(user mode)和内核模式(kernel mode)是CPU的两种运行模式(CPU可以细分更多的运行模式,但操作系统至少需要这两种)。内核模式下,一些访问和操作不受限制,例如访问特定的内存空间、访问硬件设备、执行特定的指令。操作系统和CPU配合,通过设置用户态和内核态,防止程序越权操作,保护应用程序、操作系统和IO设备。如果进程发出了非法指令,CPU会抛出异常(exception),操作系统可能会结束进程。
用户态下,应用程序不能直接访问硬件设备,需要向操作系统提出请求才可能被允许访问。实际上,应用程序访问硬件的能力完全取决于操作系统是否允许。用户态下,所有内存访问都要通过CPU中的MMU(内存管理单元)或MPU(内存保护单元),内核态下对内存的访问则绕过MMU(MPU),获得对物理内存的完整访问权限。CPU不能直接区分代码是来自应用程序还是来自操作系统,所以设计操作系统时,需要用各种各样的手段保证应用程序只能通过跳转到操作系统代码的方式来切换到内核态上,这样也就间接保障了内核态下执行的都是操作系统(包括驱动)的代码。

5、系统调用(system call,syscall)是一种接口,用于实现一些限制级功能。一些系统调用看起来和C语言的典型的过程调用很像。事实上,系统调用本身就是一种特殊的过程调用,不过隐藏在这些过程调用之下的是陷阱指令。当操作系统接收到系统调用请求后,会让处理器进入内核模式,从而执行诸如I / O操作,修改基址寄存器内容等指令;而当处理完系统调用内容后,操作系统会让处理器返回用户模式,来执行用户代码。这些代码多用C / C++编写,一些非常底层的指令则直接用汇编语言编写。

6、执行陷阱指令时,以x86为例,处理器将程序计数器、标志、一些寄存器压入进程的内核栈(kernel stack);从陷阱返回时,栈中的内容被弹出至原位置,然后在用户模式继续执行原来的程序。其它平台执行陷阱指令的基本思想是相似的。

7、执行陷阱指令时,操作系统的内核必须小心控制陷阱期间代码的执行,否则可能使恶意程序在获得批准之后执行任意代码。内核在系统启动时会令CPU进入特权模式,与此同时内核建立一个陷阱指令表(trap table)。这个表决定了在不同的事件(磁盘中断、键盘中断、系统调用等)发生时,需要执行的操作有哪些。操作系统会把陷阱处理程序的位置告知硬件,硬件保留这些位置直到系统下次启动。于是在系统调用和异常发生时,硬件就会执行相应的操作(如:跳至指定的代码)。陷阱指令表中的代码是不允许被用户模式下的程序访问的。

8、当心用户输入。虽然我们在系统调用期间如何保护操作系统这方面已经付出了很大的代价,但是为了打造一个更安全的系统,有很多方面还要考虑。例如:在系统调用时,要检查参数的合法性。比如对write()要检查请求写入的地址是否为合法的地址,不能让应用程序访问内核的地址或者其它程序的地址。

9、一般地,每个系统调用都有一个系统调用码(system-call number)。于是用户进程可以把需要调用的系统调用以一个编号的形式保存在寄存器或者栈中。操作系统通过检查这个代码可以确认其合法性。这提供了一种保护机制:用户不能直接访问指定的地址,而是通过系统调用来间接访问。

10、有限直接执行(Limited Direct Execution)协议分为两部分。第一部分在启动时、内核模式下执行,建立陷阱指令表,并令相应的硬件记忆指定的陷阱指令所在的位置。第二部分则是在创建进程时执行。在返回到用户模式之前先在进程列表中增加相应的项,然后把程序读入内存,建立带调用参数的用户栈,并用程序计数器和寄存器内容填充内核栈,然后切换至用户模式,从内核栈恢复内容并跳至入口开始执行进程。当进程进行系统调用时,又切换至内核模式,处理完系统调用后返回,继续执行进程。在进程执行完毕,从main()返回后,又切换至内核模式,清除程序占用的内存,并从进程列表中删除相关的项。

11、过去的操作系统,如早期的Macintosh和Xerox Alto,认为应用程序总是合理执行。它们仅在程序进行系统调用或进行非法操作时才取回控制权并调度其它任务运行。例如当除以零或者非法访问内存时,程序向系统生成一个陷阱,于是系统取回对CPU的控制权,并结束进程。
但是这个方法并不能应对诸如陷入死循环或者程序拒绝系统调用并拒绝移交控制权的情况。老式的操作系统在遇到这些问题时只能重启机器。后来的操作系统引入了定时器中断(timer interrupt)。这属于硬件特性:由一个定时器每隔一定的毫秒就发出中断,然后操作系统的中断处理程序开始运行。操作系统取回对CPU的控制权并暂停当前进程,调度下一个进程。操作系统必须告知硬件在定时器中断发生时需要执行哪些指令,并在系统启动时启动这个定时器。某些情况下,这个定时器也可以关闭。当然,这两种操作都是特权级的。
发生中断时,操作系统也需要进行相应的处理。比如保存进程的内容,并在处理完中断后恢复;或者在恢复进程运行时正确还原之前保存的数据。这跟处理显式系统调用的情况一样。

12、研究人员发现,重启对于一个健壮的(robust)系统是必要的。因为这会把各个软件都从不太稳定的、未知或故障状态还原回已知的、经过反复测试的状态,而且重启这个操作很容易完成。大型网络服务中,系统管理软件常常周期性重启系统。

13、当操作系统取回控制权时,要执行上下文切换的代码。所有的操作系统要做的就是:进入内核模式,从当前进程保存寄存器的值到该进程的内核栈,将准备执行的进程原来的寄存器的值从这个进程自己的内核栈还原,然后从陷阱返回。这部分操作是由汇编代码完成的。一般需要保存和恢复的内容主要有:通用寄存器、程序计数器、当前进程和准备执行的进程的内核栈的指针。当定时器中断发生时,当前进程的用户寄存器被硬件隐式保存;当操作系统决定从一个进程切换到另一个进程时,内核寄存器被操作系统显式保存。

14、现在,单次上下文切换和单次系统调用的时间已经远远小于1 ms。这与前些年CPU进步极快有关。但是很多系统操作是内存敏感的,而内存带宽的增长程度远不如CPU速率的增长程度。因此,操作系统在最新的CPU上不一定明显快于前几代CPU。
【梳理】简明操作系统原理 第二章 过程、系统调用、陷阱指令和中断(内含文档高清截图)
【梳理】简明操作系统原理 第二章 过程、系统调用、陷阱指令和中断(内含文档高清截图)
【梳理】简明操作系统原理 第二章 过程、系统调用、陷阱指令和中断(内含文档高清截图)
【梳理】简明操作系统原理 第二章 过程、系统调用、陷阱指令和中断(内含文档高清截图)
【梳理】简明操作系统原理 第二章 过程、系统调用、陷阱指令和中断(内含文档高清截图)
【梳理】简明操作系统原理 第二章 过程、系统调用、陷阱指令和中断(内含文档高清截图)