实验执行流程概述

lab2 和 lab3 完成了对内存的虚拟化,但整个控制流还是一条线串行执行。lab4 将在此基础上进行 CPU 的虚拟化,即让 ucore 实现分时共享 CPU,实现多条控制流能够并发执行。从某种程度上,我们可以把控制流看作是一个内核线程。本次实验将首先接触的是内核线程的管理。内核线程是一种特殊的进程,内核线程与用户进程的区别有两个:内核线程只运行在内核态而用户进程会在在用户态和内核态交替运行;所有内核线程直接使用共同的 ucore 内核内存空间,不需为每个内核线程维护单独的内存空间而用户进程需要维护各自的用户内存空间。从内存空间占用情况这个角度上看,我们可以把线程看作是一种共享内存空间的轻量级进程。

为了实现内核线程,需要设计管理线程的数据结构,即进程控制块(在这里也可叫做线程控制块)。如果要让内核线程运行,我们首先要创建内核线程对应的进程控制块,还需把这些进程控制块通过链表连在一起,便于随时进行插入,删除和查找操作等进程管理事务。这个链表就是进程控制块链表。然后在通过调度器(scheduler)来让不同的内核线程在不同的时间段占用 CPU 执行,实现对 CPU 的分时共享。那 lab4 中是如何一步一步实现这个过程的呢?

我们还是从 lab4/kern/init/init.c 中的 kern_init 函数入手分析。在 kern_init 函数中,当完成虚拟内存的初始化工作后,就调用了 proc_init 函数,这个函数完成了 idleproc 内核线程和 initproc 内核线程的创建或复制工作,这也是本次实验要完成的练习。idleproc 内核线程的工作就是不停地查询,看是否有其他内核线程可以执行了,如果有,马上让调度器选择那个内核线程执行(请参考 cpu_idle 函数的实现)。所以 idleproc 内核线程是在 ucore 操作系统没有其他内核线程可执行的情况下才会被调用。接着就是调用 kernel_thread 函数来创建 initproc 内核线程。initproc 内核线程的工作就是显示“Hello World”,表明自己存在且能正常工作了。

调度器会在特定的调度点上执行调度,完成进程切换。在 lab4 中,这个调度点就一处,即在 cpu_idle 函数中,此函数如果发现当前进程(也就是 idleproc)的 need_resched 置为 1(在初始化 idleproc 的进程控制块时就置为 1 了),则调用 schedule 函数,完成进程调度和进程切换。进程调度的过程其实比较简单,就是在进程控制块链表中查找到一个“合适”的内核线程,所谓“合适”就是指内核线程处于“PROC_RUNNABLE”状态。在接下来的 switch_to 函数(在后续有详细分析,有一定难度,需深入了解一下)完成具体的进程切换过程。一旦切换成功,那么 initproc 内核线程就可以通过显示字符串来表明本次实验成功。

接下来将主要介绍了进程创建所需的重要数据结构--进程控制块 proc_struct,以及 ucore 创建并执行内核线程 idleproc 和 initproc 的两种不同方式,特别是创建 initproc 的方式将被延续到实验五中,扩展为创建用户进程的主要方式。另外,还初步涉及了进程调度(实验六涉及并会扩展)和进程切换内容。

results matching ""

    No results matching ""