操作系统-进程实现
进程介绍
进程可以利用系统的资源,有自己的代码和数据,同事拥有自己的堆栈
进程的形成
需要一个数据解雇记录一个进程的状态,在进程被挂起的时候,进程信息就被写入这个数据,等到进程重新启动的时候,这个信息重新被读出来。
进程和进程调度是运行在不同的层级上的。我们让任务运行在ring1,而让进程切换运行在ring0.
当时钟中断发生时,中断处理程序会将控制权交给调度模块。进程切换就发生了,当前进程的状态被保存起来,队列中的下一个进程将被恢复执行。
最简单的进程
一个进程正在兢兢业业地运行着,这时候时钟中断发生了,特权级从ring1跳转到ring0,开始执行时钟中断处理程序,中断程序这时调用进程调度模块,指定下一个应该运行的进程,当中断处理程序结束时,下一个进程准备就绪并开始运行,特权级又从ring0跳回ring1.
我们把这个过程按照时间顺序整理
进程A运行中。
时钟发生中断,ring1-ring0,时钟中断处理程序启动。
进程调度,下一个应运行的进程(假设为进程B)被指定。
进程B被恢复,ring0->ring1。
进程B运行中。
要实现这些功能,我们必须完成的应该有以下几项:
时钟中断处理程序
进程调度模块
两个进程
关键技术
进程的哪些状态需要被保存
不同进程的内存互不干涉,我们要把寄存器的值统统保存起来,准备进程被恢复执行时使用。
进程的状态需要何时以及怎样被保存
Inter的pushad指令,一条指令可以保存许多寄存器值。而这些代码,我们应该把它写在时钟中断例程的最顶端,以便中断发生时迷上被执行。
如何恢复进程B的状态
不用说,保存时为了恢复,既然保存用的是push,恢复一定用pop了。等所有寄存器的值都被恢复,执行指令iretd,就回到了进程B。
进程表引入
数据结构”进程表”(进程控制块,也即PCB)。通过进程表,我们可以非常方便地进程进程管理。
进程表是用来描述进程的,所以它必须独立于进程之外。所以,当我们把寄存器值压到进程表内的时候,已经处在进程管理模块中。
进程栈和内核栈
当寄存器的值已经被保存到进程表内,进程调度模块就开始执行了。但是这时有一个很重要的问题容易被忽视,就是esp现在指向何处。
毫无疑问,我们在进程调度模块中会用到堆栈,而寄存器被压在进程表之后,esp是指向进程表某个位置的。这就有了问题,如果接下来进行任何的堆栈操作,都会破坏掉进程表的值,从而在下一次进程恢复时产生严重的错误。
为解决这个问题,避免错误的出现,一定要记得将esp指向专门的内核栈区域。这样,在短短的进程切换过程中,esp的位置出现了3个不同的区域。
进程栈-进程运行时自身的堆栈。
进程表-存储进程状态信息的数据结构。
内核栈-进程调度模块运行时使用的堆栈。
特权级变换:ring1->ring0
如果由外层向内层转移时,需要从TSS中取得从当前TSS中取出内层ss和esp作为目标代码的ss和esp。所以,我们必须事先准备好TSS。由于每个进程相对独立,我们把涉及到的描述符放在局部描述符表LDT中,所以,我们还需要为每个进程准备LDT。
特权级变换:ring0->ring1
我们假设的初始状态是“进程A运行中”。到目前为止我们的代码完全运行在ring0。当我们准备
雏形操作系统 来自淘豆网www.taodocs.com转载请标明出处.