当我们采用时分共享或者空分共享虚化CPU时,也要考虑它带来的问题,第一个是性能问题,频繁的进行上下文切换必然会导致性能下降。第二个是控制权,如何有效的运行进程,同时保留对CPU的控制。

关键问题:如何高效、可控的进行虚化。

受限直接执行

1、直接执行

直接执行比较好理解,即直接在CPU资源上运行程序即可。

当程序需要运行时,直接将代码加载到内存中,然后找到入口点运行用户代码。

但是如果没有限制,那么会产生问题:如何保证程序不做我们不想让它做的事情,另一方面是如何停止一个进程让另一个进程运行。

2、受限制的操作

关键问题:如何执行受限制的操作

一个进程要能够执行I/O和其他一些受限制的操作,但又不能让进程控制系统。

针对这个问题,引入了一个新的处理器模式:用户模式。在用户模式下运行的代码会收到限制,比如不能发出I/O请求。

与之对应的是内核模式。该模式代码可以做任何操作。

目前硬件提供了用户程序执行系统调用的功能,即用户代码可以通过系统调用执行如创建和销毁进程,与其他进程通信等。

要执行系统调用,程序必须执行特殊的陷阱(trap)指令。该指令跳入内核并将特权级别提升到内核模式。但是执行该指令时需要有足够多的寄存器来存储程序目前的状态,确保程序能够正确返回。

很明显的一点是,发起系统调用的过程不能让程序决定跳转到内核的哪里,因为这样会导致恶意程序在内核运行。

解决办法是由一个陷阱表,可以理解为一个map,记录了发生某种指令时需要运行那些代码,这样当用户程序执行系统调用,就会执行对应的位置的代码,而不再由程序决定跳入内核的那个位置。

3、在进程之间切换

一个很关键的问题,如果进程在CPU上运行,那就意味着操作系统此时没有运行,那操作系统如何拿回控制权呢?

协作方式:等待系统调用

在这种方式下,运行时间过长的进程会被假定主动放弃CPU,以便操作系统决定运行其他任务。注意,这里需要程序手动的将控制权交还给操作系统。

但是也有恶意或者不小的代码执行一些非法操作,就会陷入操作系统,此时操作系统将再次获得CPU。

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

这里要解决的问题:如何在没有协作的情况下获得控制权。

上面的那种方式,在出现非法操作时会导致进程陷入操作系统,但是如果一个进程进入无限循环,它不进行系统调用也不出错,那么操作系统就无法获得控制权。

这个问题的解决办法是时钟中断

时钟设备可以便成为每几毫秒产生一次中断,中断发生时,正在运行的进程停止,操作系统预先配置的中断程序会运行,然后操作系统会获得CPU的控制权。然后它就可以停止当前进程,运行另外一个进程。

保存和恢复上下文

当操作系统获得CPU时,它就要确定是继续执行当前进程还是进行切换。如果进行切换,就需要为当前正在运行的进行保存一些信息到寄存器(通用寄存器,程序计数器,当前正在运行进程的内核指针),并且恢复将要运行的进程恢复一些寄存器的值。这个过程就叫做上下文切换。

当发生时钟中断时,运行进程由用户寄存器隐式保存,使用该进程的内核栈。

当操作系统决定从A切换到B,内核寄存器被操作系统(OS)明确的保存在该进程的进程结构的内存中。

参考

《操作系统导论》