Skip to content
On this page

受限直接执行

概述

操作系统运行一个进程一段时间,然后运行另一个进程,通过这种以时分共享 CPU,就实现了虚拟化,然而这样构建的虚拟化机制存在一些挑战:

  1. 性能:如何在不增加系统开销的情况下实现虚拟化
  2. 控制权:如何有效的运行进程,同时保留 CPU 的控制权

如何权衡性能和控制权是构建操作系统的主要挑战之一。

基本技巧:受限直接执行

为了使程序尽快运行,操作系统开发人员,想出了一种技术——受限的直接执行。

受限直接执行的后半截,直接运行非常简单,就只是放在 CPU 里运行而已,重点在于受限的实现。

硬件通过不同的执行模式来协助操作系统。在用户模式下,应用程序不能完全访问硬件资源。在内核模式,操作系统可以访问机器的全部资源。

因此,我们采用的方式是引入一种新的处理器模式,称为用户模式,在用户模式下的代码会受到限制,例如在用户模式下,进程不能发出 I/O 请求,这样会导致处理器异常,从而被操作系统停止。

然而用户希望执行某种特权操作:如磁盘读取,为了实现这一点,所有现代硬件都提供了用户执行系统调用的能力,它允许内核小心地向用户程序暴露某些关键功能,如访问文件系统、创建或销毁进程,大多数操作系统提供几百个系统调用。

要执行系统调用,程序必须执行特殊的陷阱指令(trap),该命令同时跳入内核,并将特权级别提升到内核模式,进入内核之后,系统执行任何需要的特权操作,从而为调用进程执行所需的工作。完成后,操作系统执行一个特殊的从陷阱返回(return-from-trap)指令,如你期望的那样,该指令返回到发起调用的用户程序中,同时将特权等级降低,回到用户模式。

执行陷阱时,硬件需要小心,因为它必须确保存储足够的调用者寄存器,以便在操作系统发出从陷阱返回指令时能够正确返回。

直接执行:在进程间切换

直接执行的下一个问题是实现进程之间的切换,在进程之间切换应该很简单,操作系统应该决定停止一个进程并开始另一个进程。然而这实际上有点棘手:如果一个进程在 CPU 上运行,这就意味着操作系统没有运行,如果操作系统没有运行,它该如何做事情?

于是这里引出了关键问题:如何重获 CPU 的控制权,以便实现在进程间切换。

协作方式

过去某些系统采用这种方式,比如旧版的 macOS。在这种风格下,操作系统相信系统的进程会合理运行,运行时间过长的进程会定期放弃 CPU,以便操作系统可以决定运行其他任务。应用可以通过一个显式的系统调用将 CPU 的控制权转移给操作系统,当应用执行了非法操作,操作系统会一击出局,夺回 CPU 的控制权。

非协作方式:操作系统进行控制

事实证明,没有硬件的额外帮助,如果进程拒绝执行系统调用(也不出错),从而将控制权交还给操作系统,那么操作系统无法做任何事情。所以在写作方式下,当进程陷入无限循环的时候,唯一的办法就是使用万能 Windows 系统问题解决方案:重新启动计算机,于是在这里,我们又遇到了请求 CPU 控制权的另一个问题:如何在没有协作的情况下获得控制权?操作系统如何保证流氓进程不会占用机器?

答案是:时钟中断。时钟设备可以编程为每隔几毫秒产生一次中断。产生中断时,当前运行的进程暂停,操作系统中预先配置的中断处理程序运行。此时操作系统重新获得 CPU 控制权,因此开始做它想做的事情:停止当前进程,并启动另一个进程。

像很多系统调用一样,操作系统必须告知硬件,哪些代码发生在时钟中断时,一旦时钟开始运行,操作系统就感觉安全了,因此操作系统就可以自由运行用户软件了,时钟也可以通过特权操作关闭。

保存和恢复上下文

操作系统重新获得了控制权,无论是通过系统调用写作,还是通过时钟中断强制执行,都必须决定:是继续运行当前进程,还是切换到另一个进程。这个决定是由调度程序作出的,它是操作系统的一部分。

如果决定进行切换,操作系统就会执行一些底层代码,即所谓的上下文切换。上下文切换在概念上很简单:操作系统要做的就是为当前正在执行的进程保存一些寄存器的值,并为即将运行的进程恢复一些寄存器的值。

受限直接运行:小结

基本思路很简单,就让你想运行的程序在 CPU 上运行,但是先保证设置好了硬件,以便在没有操作系统帮助的情况下限制进程可以执行的操作。

这种方法在现实生活中也被采用,比如你将婴儿锁在房间,你锁好了包含危险物品的柜子,掩盖电源插座,然后就让婴儿自由活动,确保房间里危险的方面被限制。

Released under the MIT License.